05Docker容器镜像

0 阅读29分钟

Docker容器镜像

Docker容器镜像操作

查看本地容器镜像

# 下面两个命令都可以用来查看本地容器镜像列表
docker images
docker image list
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    eea7b3dcba7e   2 weeks ago     187MB
centos       latest    5d0da3dc9764   24 months ago   231MB

docker容器镜像会占用本地存储空间,建议搭建其它存储系统挂载到本地以便解决占用大量本地存储的问题

docker容器镜像默认存储在 /var/lib/docker,可以自定义,上面安装的docker,镜像文件位置在 /data/docker

ls /data/docker
buildkit  containers  engine-id  image  network  overlay2  plugins  runtimes  swarm  tmp  volumes

搜索Docker Hub容器镜像

命令行搜索

docker search centos
NAME                                         DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
centos                                       DEPRECATED; The official build of CentOS.       7640      [OK]       
kasmweb/centos-7-desktop                     CentOS 7 desktop for Kasm Workspaces            39                   
bitnami/centos-base-buildpack                Centos base compilation image                   0         [OK]       
couchbase/centos7-systemd                    centos7-systemd images with additional debug…   8         [OK]       
continuumio/centos5_gcc5_base                                                                3                   
datadog/centos-i386                                                                          0                   
dokken/centos-7                              CentOS 7 image for kitchen-dokken               5                   
dokken/centos-8                              CentOS 8 image for kitchen-dokken               3                   
spack/centos7                                CentOS 7 with Spack preinstalled                1   
...

Docker Hub Web界面搜索

在网页hub.docker.com/上搜索

Docker 容器镜像下载

docker pull mysql

Docker容器镜像删除方法

docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    eea7b3dcba7e   2 weeks ago     187MB
mysql        latest    99afc808f15b   3 weeks ago     577MB
centos       latest    5d0da3dc9764   24 months ago   231MB
# 下面两个命令都可以用来删除镜像
docker rmi centos
docker rmi eea7b3dcba7e
Untagged: centos:latest
Untagged: centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Deleted: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6
Deleted: sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59

docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    eea7b3dcba7e   2 weeks ago   187MB
mysql        latest    99afc808f15b   3 weeks ago   577MB

Docker容器镜像介绍

Docker Image

  • Docker 镜像是只读的容器模板,是Docker容器基础
  • 为Docker容器提供了静态文件系统运行环境(rootfs)
  • 是容器的静止状态
  • 容器是镜像的运行状态

联合文件系统

定义

  • 联合文件系统(union filesystem)
  • 联合文件系统是实现联合挂载技术的文件系统
  • 联合挂载技术可以实现在一个挂载点同时挂载多个文件系统,将挂载点的原目录与被挂载内容进行整合,使得最终可见的文件系统包含整合之后的各层文件和目录

图解

image.png

Docker Overlay2

容器文件系统有多种存储驱动实现方式:aufs,devicemapper,overlay,overlay2 等,本次以overlay2为例进行说明。

概念
  • registry/repository: registry 是 repository 的集合,repository 是镜像的集合。
  • image:image 是存储镜像相关的元数据,包括镜像的架构,镜像默认配置信息,镜像的容器配置信息等等。它是“逻辑”上的概念,并无物理上的镜像文件与之对应。
  • layer:layer(镜像层) 组成了镜像,单个 layer 可以被多个镜像共享。

image.png

查看Docker Host存储驱动方式
docker info | grep overlay
Storage Driver: overlay2
  Network: bridge host ipvlan macvlan null overlay
了解images分层
docker rmi nginx
docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
52d2b7f179e3: Pull complete 
fd9f026c6310: Pull complete 
055fa98b4363: Pull complete 
96576293dd29: Pull complete 
a7c4092be904: Pull complete 
e3b6889c8954: Pull complete 
da761d9a302b: Pull complete 
Digest: sha256:104c7c5c54f2685f0f46f3be607ce60da7085da3eaa5ad22d3d9f01594295e9c
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

可以看到上述下载的镜像分为7层,如何找到这7层存储在Docker Host哪个位置呢?

docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    eea7b3dcba7e   3 weeks ago   187MB

ls /data/docker/image/overlay2/
distribution  imagedb  layerdb  repositories.json

/data/docker/image/overlay2/录是查找的入口,非常重要。它存储了镜像管理的元数据。

  • repositories.json 记录了 repo 与镜像 ID 的映射关系
  • imagedb 记录了镜像架构,操作系统,构建镜像的容器 ID 和配置以及 rootfs 等信息
  • layerdb 记录了每层镜像层的元数据。

通过短 ID 查找 repositories.json 文件,找到镜像 nginx 的长 ID,通过长 ID 在 imagedb 中找到该镜像的元数据:

cat /data/docker/image/overlay2/repositories.json | grep eea7b3dcba7e
{"Repositories":{"nginx":{"nginx:latest":"sha256:eea7b3dcba7ee47c0d16a60cc85d2b977d166be3960541991f3e6294d795ed24","nginx@sha256:104c7c5c54f2685f0f46f3be607ce60da7085da3eaa5ad22d3d9f01594295e9c":"sha256:eea7b3dcba7ee47c0d16a60cc85d2b977d166be3960541991f3e6294d795ed24"}}}

cat /data/docker/image/overlay2/imagedb/content/sha256/eea7b3dcba7ee47c0d16a60cc85d2b977d166be3960541991f3e6294d795ed24
...
"os":"linux","r
ootfs":{"type":"layers","diff_ids":["sha256:511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299",
"sha256:4713cb24eeff341d0c36343149beba247572a5ff65c2be5b5d9baafb345c7393","sha256:d0a62f56ef413f60049bc87e43e6
0032b2a2ab8d931e15b86ee0286c85ae91a2","sha256:8a7e12012e6f60450e6d2d777b2a2c2256d34a0ccd84d605f72cc5329a87c8b8
","sha256:e161c3f476b5199ab13856c7e190ed12a6562b7be059c7026ae9f594e1abbcaf","sha256:6fb960878295b567d25900b590
157b976d080340caeaa8bf8c46d38c01b4537d","sha256:563c64030925e9016a2329d3a2b7d47b0c90931baf5d2d0aa926c4c8d94ab8
94"]}}

这里仅保留我们想要的元数据 rootfs。在 rootfs 中看到 layers 有7层,这7层即对应镜像的7层镜像层。并且,自上而下分别映射到容器的底层到顶层。找到了镜像的7层,接下来的问题是每层的文件内容在哪里呢?

layerdb 元数据会给我们想要的信息,通过底层 diff-id: 511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299我们查到最底层镜像层的 cache_id,通过 cache_id 即可查找到镜像层的文件内容:

ls /data/docker/image/overlay2/layerdb/sha256/511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299
cache-id  diff  size  tar-split.json.gz
cat /data/docker/image/overlay2/layerdb/sha256/511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299/cache-id
70a84b873ced20488b785519f7422caddcad5d5028ceb1258c2bb764c33d8ccb

cat /data/docker/image/overlay2/layerdb/sha256/511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299/diff
sha256:511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299

使用 cacheId 查找文件内容

ls /data/docker/overlay2/70a84b873ced20488b785519f7422caddcad5d5028ceb1258c2bb764c33d8ccb
committed  diff  link

ls /data/docker/overlay2/70a84b873ced20488b785519f7422caddcad5d5028ceb1258c2bb764c33d8ccb/diff
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr

上面示例中,镜像元数据和镜像层内容是分开存储的。因此通过 cache-id 我们需要到 /data/docker/overlay2 目录下查看镜像层内容,它就存在 diff 目录下,其中 link 存储的是镜像层对应的短 ID,后面会看到它的用场。

找到了镜像层的最底层,接着查找镜像层的“中间层”,发现在 layerdb 目录下没有 diff-id 4713cb24eeff341d0c36343149beba247572a5ff65c2be5b5d9baafb345c7393的镜像层:

ls /data/docker/image/overlay2/layerdb/sha256/4713cb24eeff341d0c36343149beba247572a5ff65c2be5b5d9baafb345c7393
ls: cannot access ... No such file or directory

这是因为 docker 引入了内容寻址机制,该机制会根据文件内容来索引镜像和镜像层。docker 利用 rootfs 中的 diff_id 计算出内容寻址的 chainID,通过 chainID 获取 layer 相关信息,最终索引到镜像层文件内容。

对于最底层镜像层其 diff_id 即是 chainID。因此我们可以查找到它的文件内容。除最底层外,chainID 需通过公式 chainID(n) = SHA256(chain(n-1) diffID(n)) 计算得到,计算“中间层” chainID:

echo -n "sha256:511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299 sha256:4713cb24eeff341d0c36343149beba247572a5ff65c2be5b5d9baafb345c7393" | sha256sum -
49bfd4a4ea578aefcacdfd87efdc4999d6a4e4b7f00322484cac67ff7671389e  -

根据 “中间层” chainID 查找文件内容:

ls /data/docker/image/overlay2/layerdb/sha256/49bfd4a4ea578aefcacdfd87efdc4999d6a4e4b7f00322484cac67ff7671389e
cache-id  diff  parent  size  tar-split.json.gz

cat /data/docker/image/overlay2/layerdb/sha256/49bfd4a4ea578aefcacdfd87efdc4999d6a4e4b7f00322484cac67ff7671389e/cache-id
417f018435117a528ed4963f4e46facd1268c987efae80839b542e6d9607a59c

cat /data/docker/image/overlay2/layerdb/sha256/49bfd4a4ea578aefcacdfd87efdc4999d6a4e4b7f00322484cac67ff7671389e/diff
sha256:4713cb24eeff341d0c36343149beba247572a5ff65c2be5b5d9baafb345c7393

cat /data/docker/image/overlay2/layerdb/sha256/49bfd4a4ea578aefcacdfd87efdc4999d6a4e4b7f00322484cac67ff7671389e/parent
sha256:511780f88f80081112aea1bfdca6c800e1983e401b338e20b2c6e97f384e4299
# 镜像层文件内容,这里用到的是上面的cache-id
ls /data/docker/overlay2/417f018435117a528ed4963f4e46facd1268c987efae80839b542e6d9607a59c
committed  diff  link  lower  work

ls /data/docker/overlay2/417f018435117a528ed4963f4e46facd1268c987efae80839b542e6d9607a59c/diff/
docker-entrypoint.d  etc  tmp  usr  var

# 镜像层文件内容短 ID
cat /data/docker/overlay2/417f018435117a528ed4963f4e46facd1268c987efae80839b542e6d9607a59c/link
POGTJHLPQKI72V3SCWS2N7YTXV

# “父”镜像层文件内容短 ID
cat /data/docker/overlay2/417f018435117a528ed4963f4e46facd1268c987efae80839b542e6d9607a59c/lower
l/5DEMHARECNUU5RZ77ANSDDSRFW

找到最底层文件内容和“中间层”文件内容,再去找最顶层文件内容就变的不难了

Docker容器与镜像

通过 docker run 命令启动一个镜像为 nginx的容器:

docker run -d nginx:latest
61dde6968cc64be7b4f7ead16d0e0f4481fbdbee6992142a55b6ae76e3a75b75

docker ps | grep nginx
61dde6968cc6   nginx:latest   "/docker-entrypoint.…"   21 seconds ago   Up 20 seconds   80/tcp    modest_benz

mount | grep overlay
overlay on /data/docker/overlay2/6d2134a30675c66750138f069bce3b3a465b4b6e29d26dd42899125e49ab5c64/merged type overlay (rw,relatime,lowerdir=/data/docker/overlay2/l/6VHRCIJBQBRPME2ETJUFGVIBDK:/data/docker/overlay2/l/E63C6HLNVMQUKGJB623YHPKK3I:/data/docker/overlay2/l/WR6JLMCYXFUR6YTCLEISZSN37W:/data/docker/overlay2/l/4BUITPTAAHX2AHG4WRSJPVD35B:/data/docker/overlay2/l/CGJNFHYZTCIWSSWXLXEPJWLFBE:/data/docker/overlay2/l/W5EIOLLWFUVLJBZI7SLSCOY3J4:/data/docker/overlay2/l/POGTJHLPQKI72V3SCWS2N7YTXV:/data/docker/overlay2/l/5DEMHARECNUU5RZ77ANSDDSRFW,upperdir=/data/docker/overlay2/6d2134a30675c66750138f069bce3b3a465b4b6e29d26dd42899125e49ab5c64/diff,workdir=/data/docker/overlay2/6d2134a30675c66750138f069bce3b3a465b4b6e29d26dd42899125e49ab5c64/work)

可以看到,启动容器会 mount 一个 overlay 的联合文件系统到容器内。这个文件系统由三层组成:

  • lowerdir:只读层,即为镜像的镜像层。
  • upperdir:读写层,该层是容器的读写层,对容器的读写操作将反映在读写层。
  • workdir: overlayfs 的内部层,用于实现从只读层到读写层的 copy_up 操作。
  • merge:容器内作为同一视图联合挂载点的目录。

这里需要着重介绍的是容器的 lowerdir 镜像只读层,查看只读层的短 ID:

lowerdir=
/data/docker/overlay2/l/6VHRCIJBQBRPME2ETJUFGVIBDK:
/data/docker/overlay2/l/E63C6HLNVMQUKGJB623YHPKK3I:
/data/docker/overlay2/l/WR6JLMCYXFUR6YTCLEISZSN37W:
/data/docker/overlay2/l/4BUITPTAAHX2AHG4WRSJPVD35B:
/data/docker/overlay2/l/CGJNFHYZTCIWSSWXLXEPJWLFBE:
/data/docker/overlay2/l/W5EIOLLWFUVLJBZI7SLSCOY3J4:
/data/docker/overlay2/l/POGTJHLPQKI72V3SCWS2N7YTXV:
/data/docker/overlay2/l/5DEMHARECNUU5RZ77ANSDDSRFW

镜像层只有7层这里的短 ID 却有8个?在 /data/docker/overlay2/l 目录下我们找到了答案:

cd /data/docker/overlay2/l
ls
4BUITPTAAHX2AHG4WRSJPVD35B  CGJNFHYZTCIWSSWXLXEPJWLFBE  W5EIOLLWFUVLJBZI7SLSCOY3J4
5DEMHARECNUU5RZ77ANSDDSRFW  E63C6HLNVMQUKGJB623YHPKK3I  WR6JLMCYXFUR6YTCLEISZSN37W
6VHRCIJBQBRPME2ETJUFGVIBDK  POGTJHLPQKI72V3SCWS2N7YTXV  ZYRDU2NDGHXYNUPHQFBNX5UGUT

ls -l 6VHRCIJBQBRPME2ETJUFGVIBDK/
total 0
drwxr-xr-x 4 root root 43 Sep  6 19:43 dev
drwxr-xr-x 2 root root 66 Sep  6 19:43 etc

ls -l E63C6HLNVMQUKGJB623YHPKK3I/
total 0
drwxr-xr-x 2 root root 41 Aug 16 17:50 docker-entrypoint.d

ls -l WR6JLMCYXFUR6YTCLEISZSN37W/
total 0
drwxr-xr-x 2 root root 41 Aug 16 17:50 docker-entrypoint.d

ls -l 4BUITPTAAHX2AHG4WRSJPVD35B/
total 0
drwxr-xr-x 2 root root 38 Aug 16 17:50 docker-entrypoint.d

ls -l CGJNFHYZTCIWSSWXLXEPJWLFBE/
total 0
drwxr-xr-x 2 root root 45 Aug 16 17:50 docker-entrypoint.d

ls -l W5EIOLLWFUVLJBZI7SLSCOY3J4/
total 4
-rwxrwxr-x 1 root root 1620 Aug 16 17:50 docker-entrypoint.sh

ls -l POGTJHLPQKI72V3SCWS2N7YTXV/
total 4
drwxr-xr-x  2 root root    6 Aug 16 17:50 docker-entrypoint.d
drwxr-xr-x 19 root root 4096 Aug 16 17:50 etc
drwxrwxrwt  2 root root    6 Aug 16 17:50 tmp
drwxr-xr-x  7 root root   66 Aug 14 08:00 usr
drwxr-xr-x  5 root root   41 Aug 14 08:00 var

ls -l 5DEMHARECNUU5RZ77ANSDDSRFW/
total 4
lrwxrwxrwx  1 root root    7 Aug 14 08:00 bin -> usr/bin
drwxr-xr-x  2 root root    6 Jul 15 00:00 boot
drwxr-xr-x  2 root root    6 Aug 14 08:00 dev
drwxr-xr-x 29 root root 4096 Aug 14 08:00 etc
drwxr-xr-x  2 root root    6 Jul 15 00:00 home
lrwxrwxrwx  1 root root    7 Aug 14 08:00 lib -> usr/lib
lrwxrwxrwx  1 root root    9 Aug 14 08:00 lib32 -> usr/lib32
lrwxrwxrwx  1 root root    9 Aug 14 08:00 lib64 -> usr/lib64
lrwxrwxrwx  1 root root   10 Aug 14 08:00 libx32 -> usr/libx32
drwxr-xr-x  2 root root    6 Aug 14 08:00 media
drwxr-xr-x  2 root root    6 Aug 14 08:00 mnt
drwxr-xr-x  2 root root    6 Aug 14 08:00 opt
drwxr-xr-x  2 root root    6 Jul 15 00:00 proc
drwx------  2 root root   37 Aug 14 08:00 root
drwxr-xr-x  3 root root   18 Aug 14 08:00 run
lrwxrwxrwx  1 root root    8 Aug 14 08:00 sbin -> usr/sbin
drwxr-xr-x  2 root root    6 Aug 14 08:00 srv
drwxr-xr-x  2 root root    6 Jul 15 00:00 sys
drwxrwxrwt  2 root root    6 Aug 14 08:00 tmp
drwxr-xr-x 14 root root  160 Aug 14 08:00 usr
drwxr-xr-x 11 root root  139 Aug 14 08:00 var

后7个文件夹分别对应镜像的7层镜像层文件内容,它们分别映射到镜像层的 diff 目录。第一个6VHRCIJBQBRPME2ETJUFGVIBDK,映射的是容器的初始化层 init,该层内容是和容器配置相关的文件内容,它是只读的。

启动了容器,docker 将镜像的内容 mount 到容器中。那么,如果在容器内写文件会对镜像有什么影响呢?

容器内写文件

不难理解,镜像层是只读的,在容器中写文件其实是将文件写入到 overlay 的可读写层。

这里有几个 case 可以测试:

  • 读写层不存在该文件,只读层存在。
  • 读写层存在该文件,只读层不存在。
  • 读写层和只读层都不存在该文件。

我们简单构建一种读写层和只读层都不存在的场景:

# 会进入容器中
docker run -it centos:latest bash
touch test.txt
ls
bin  etc   lib    lost+found  mnt  proc  run   srv  test.txt  usr
dev  home  lib64  media       opt  root  sbin  sys  tmp       var
# Ctrl p q 退出容器环境

查看读写层是否有该文件:

# 查看镜像是否有变化
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    eea7b3dcba7e   3 weeks ago     187MB
centos       latest    5d0da3dc9764   24 months ago   231MB

cat /data/docker/image/overlay2/repositories.json | grep 5d0da3dc9764
{"Repositories":{"centos":{"centos:latest":"sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6","centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177":"sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6"},"nginx":{"nginx:latest":"sha256:eea7b3dcba7ee47c0d16a60cc85d2b977d166be3960541991f3e6294d795ed24","nginx@sha256:104c7c5c54f2685f0f46f3be607ce60da7085da3eaa5ad22d3d9f01594295e9c":"sha256:eea7b3dcba7ee47c0d16a60cc85d2b977d166be3960541991f3e6294d795ed24"}}}

cat /data/docker/image/overlay2/imagedb/content/sha256/5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6
...
"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59"]}}

ls /data/docker/image/overlay2/layerdb/sha256/74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59
cache-id  diff  size  tar-split.json.gz

cat /data/docker/image/overlay2/layerdb/sha256/74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59/cache-id
ef08c508b300cbf16d9cdc51191f54e2fa0797808110804c8237b8e1a0324556

cat /data/docker/image/overlay2/layerdb/sha256/74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59/diff
sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59

# 下面使用的是上面的cache-id
ls /data/docker/overlay2/ef08c508b300cbf16d9cdc51191f54e2fa0797808110804c8237b8e1a0324556
committed  diff  link

ls /data/docker/overlay2/ef08c508b300cbf16d9cdc51191f54e2fa0797808110804c8237b8e1a0324556/diff/
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

# 查看容器是否有变化
mount | grep overlay
overlay on /data/docker/overlay2/fa4b9ff3334fa16e1e069ca86abb3963a255f3a1a6ec6fa91422b84981ddefd9/merged type overlay (rw,relatime,lowerdir=/data/docker/overlay2/l/WQ26CLGP2ONNXFNLU3MLSTV2TH:/data/docker/overlay2/l/GEWNRFWQCWPPBGEAXMKFCVK3WL,upperdir=/data/docker/overlay2/fa4b9ff3334fa16e1e069ca86abb3963a255f3a1a6ec6fa91422b84981ddefd9/diff,workdir=/data/docker/overlay2/fa4b9ff3334fa16e1e069ca86abb3963a255f3a1a6ec6fa91422b84981ddefd9/work)

ls -l /data/docker/overlay2/l/
...
lrwxrwxrwx 1 root root 72 Sep  7 08:08 RKFVMCTQGNHQKBI3P4CDCOT2OM -> ../fa4b9ff3334fa16e1e069ca86abb3963a255f3a1a6ec6fa91422b84981ddefd9/diff
lrwxrwxrwx 1 root root 72 Sep  6 17:46 W5EIOLLWFUVLJBZI7SLSCOY3J4 -> ../3b66c106cd5738902740035e99ae1ed1c8831b1de82e110931356caecbf22d68/diff
...

ls /data/docker/overlay2/fa4b9ff3334fa16e1e069ca86abb3963a255f3a1a6ec6fa91422b84981ddefd9/diff
etc  lost+found  mnt  run  srv  test.txt  usr

ls /data/docker/overlay2/fa4b9ff3334fa16e1e069ca86abb3963a255f3a1a6ec6fa91422b84981ddefd9/merged
bin  etc   lib    lost+found  mnt  proc  run   srv  test.txt  usr
dev  home  lib64  media       opt  root  sbin  sys  tmp       var

Docker容器镜像操作命令

docker commit

上节提到容器内写文件会反映在 overlay 的可读写层,那么读写层的文件内容可以做成镜像吗?

可以。docker 通过 commit 和 build 操作实现镜像的构建。commit 将容器提交为一个镜像,build 在一个镜像的基础上构建镜像。

使用 commit 将上节的容器提交为一个镜像:

# Ctrl p q 退出容器环境

docker ps
CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS          PORTS     NAMES
16907ddf5b9f   centos:latest   "bash"    42 minutes ago   Up 42 minutes             thirsty_elbakyan

docker commit 16907ddf5b9f
sha256:e2bb9af57c619dcd348aa058c5886f356a8ef23ccda54ed0286c190c227bd67c

docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
<none>       <none>    e2bb9af57c61   18 seconds ago   231MB

image 短 ID e2bb9af57c61 即为容器提交的镜像,查看镜像的 imagedb 元数据:

cat /data/docker/image/overlay2/imagedb/content/sha256/e2bb9af57c619dcd348aa058c5886f356a8ef23ccda54ed0286c190c227bd67c
...
"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59","sha256:caa183522ca08242f94e1ac48140d80a56408b39c98bdfcca76911ef1c0b2665"]}}

可以看到镜像层自上而下的前1个镜像层 diff_id 和 centos 镜像层 diff_id 是一样的,说明每层镜像层可以被多个镜像共享。而多出来的一层镜像层内容即是上节我们写入文件的内容:

echo -n "sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59 sha256:caa183522ca08242f94e1ac48140d80a56408b39c98bdfcca76911ef1c0b2665" | sha256sum -
3e589464f2c041cd88b0f6a8dca47e3ac88f29902568e77dc46df648f35f2698  -

ls /data/docker/image/overlay2/layerdb/sha256/3e589464f2c041cd88b0f6a8dca47e3ac88f29902568e77dc46df648f35f2698
cache-id  diff  parent  size  tar-split.json.gz

cat /data/docker/image/overlay2/layerdb/sha256/3e589464f2c041cd88b0f6a8dca47e3ac88f29902568e77dc46df648f35f2698/cache-id
69b2a494c5d8f2aa9f1354b9fcfc6e573230d334b764a42df2ba5f4dd9c5dfd2

# 下面使用的是上面的cache-id
ls /data/docker/overlay2/69b2a494c5d8f2aa9f1354b9fcfc6e573230d334b764a42df2ba5f4dd9c5dfd2
diff  link  lower  work

ls /data/docker/overlay2/69b2a494c5d8f2aa9f1354b9fcfc6e573230d334b764a42df2ba5f4dd9c5dfd2/diff
etc  lost+found  mnt  run  srv  test.txt  usr

docker save

导出容器镜像,方便分享

docker save -o centos.tar centos:latest
ls
centos.tar

docker load

把他人分享的容器镜像导入到本地,这通常是容器镜像分发方式之一。

docker load -i centos.tar

docker export

把正在运行的容器导出

docker ps
CONTAINER ID   IMAGE           COMMAND   CREATED             STATUS             PORTS     NAMES
16907ddf5b9f   centos:latest   "bash"    About an hour ago   Up About an hour             thirsty_elbakyan

docker export -o centos7.tar 16907ddf5b9f
ls
centos7.tar

docker import

导入使用docker import导入的容器做为本地容器镜像。

ls
centos7.tar

docker import centos7.tar centos7:v1
sha256:92224c57d28a2a083973d2c78299bc6a6d5edccaf957314656256c44b0430345

docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
centos7      v1        92224c57d28a   18 seconds ago   231MB

通过docker save与docker load及docker export与docker import分享容器镜像都是非常麻烦的,有没有更方便的方式分享容器镜像呢?