Docker Engine


目前,以容器技术为代表的应用形态和以虚拟化为代表的系统形态完美融合于 OpenStack 生态圈之上,Kubernetes 是用于自动部署,扩展和管理容器化应用程序的开源系统(基于容器技术的分布式架构),Kubernetes 底层支持两种容器技术 Docker 的 containerd 和 CoreOS 的 rkt。 Docker 主要以 linux 内核的 namespace 和 cgroup 等特性为基础,保障进程或者进程组处于一个隔离、受限、安全的环境之中。Docker 用 Go 实现,并在容器技术之中有风靡之势。自 2007 年 cgroups 合并至 linux 内核 2.6.24 版本,2008 年 LXC 诞生,2009 年 Go 发布,2013 年 Docker 开源,2015 年 Kubernetes 发布。到 2018 年已经有不少企业应用于生产环境;当然不免有唱衰的 再见 docker

1   诞生与发展

Docker 和 Kubernetes 一样都是新生事物,处于快速迭代期,所以很多规范、架构、功能一直在更新中。书籍和网上的文章淘汰速度也很快,特别是 v1.13.0(2017年)前的版本其知识点并不一定适用于最新的版本。所以这里有必要对一些重要版本或时间点作一些说明:

2   引擎架构

2.1   Docker vs 虚拟机

容器比虚拟机轻量级的原因是共享宿主机的操作系统内核;而虚拟机各自运行一个完整的 Guest OS 并通过 hypervisor 连接到宿主机。所以 Docker 的 linux 内核版本一定是跟宿主机一样,不同的是操作系统发行版本。下面引用 docker 文档图片

2.2   引擎模块

一般我们用 Docker(大写D)表示整个 Docker,docker 和 dockerd 表示执行程序,docker ≈ docker client,dockerd ≈ docker daemon,docker engine ≈ client + daemon + containerd + runc,daemon ≈ 镜像管理、镜像构建、REST API、身份验证、安全、核心网络以及编排。总体逻辑如下图:

2.3   模块通信

综合 systemctl status dockersystemctl status containerd 等可以理解以下内容:

  1. /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock,dockerd 通过 -H 连接到 fd://,并用 –containerd 参数指定容器运行时;
  2. API listen on /var/run/docker.sock,dockerd 提供 API 接口并开启监听;
  3. docker -H unix:///var/run/docker.sock,docker 通过 -H 连接到 dockerd(docker daemon); docker 默认是 unix socket,所以只能同一宿主机调用,远程调用可以改为 TCP socket。 守护进程:dockerd -H tcp://0.0.0.0:2375 客户进程:docker -H tcp://<宿主机 IP>:2375 需要注意的时,守护进程改用 tcp 提供调用后,客户进程即使在本机也需要通过 tcp 去调用。

docker 和 dockerd 的通信可以用 socat 进行抓包。socat 是一个强大的代理命令,能让用户在两个几乎任意类型的通道之间中继数据。groups 包括 FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6,UDP,TCP 等,操作如下:

socat -v unix-listen:/tmp/dockerapi.sock unix-connect:/var/run/docker.sock
docker -H unix:///tmp/dockerapi.sock images

2.4   启动容器的过程

dockerd 监听 client 的处理请求,并连接到 containerd 管理容器在宿主机的生命周期:start、stop、pause、rm 等。启动容器的过程如下图:

3   安装

安装 docker 和 docker-compose 等都很简单,按官方文档安装就可以了。一般安装最新社区版(CE)即可,安装完成后 systemctl start docker、systemctl enable docker 自启动。macOS 和 Windows 抛弃了过时的 Docker Toolbox,采用桌面版安装。一般 linux 服务器只安装 Docker Engine(Docker 引擎),Mac 的桌面版包括了 Docker 引擎、Compose、Machine、Notary。

最好通过非 root 用户使用 Docker,如有提示:Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock; 处理方式文档中有说明 By default, a unix domain socket (or IPC socket) is created at /var/run/docker.sock, requiring either root permission, or docker group membership. sudo usermod -aG docker USER_NAME

Docker 文档提供了命令的使用 Command-Line Interfaces

4   镜像

4.1   images 和 layers

镜像是由 layer 有序列表和一些元数据组成的配置对象,layer 才是实际数据存储的地方(比如文件等,镜像之间是完全独立的,并没有从属于某个镜像集合的概念)。

linux 从启动到运行需要两个 fs: bootfs:用 bootloader 引导加载 kernel, 当 boot 成功后 kernel 被加载到内存中后 bootfs 就被 umount。 rootfs:kernel 利用 aufs 等添加系统的 rootfs 文件系统。

  1. 基础镜像: 从 scratch 空镜像构建起,在此基础上添加一层 rootfs,比如 centos-7-docker.tar.xz、alpine-minirootfs-3.9.3-x86_64.tar.gz。 这里要特别提一下 Alpine 基础镜像,稳定性和安全性都是挺可靠的,大小也在 5M 左右,未来 docker 官方也会用 Alpine 取代 Ubuntu。 基础镜像在启动后只会启动前台进程 bash。

  2. 其它镜像构建于基础镜像之上,即 baseImage/image/image…,即在基础镜像层上利用 UnionFS(联合文件系统) 构建一层一层的只读文件系统层。 一般这类镜像在启动后都会启动守护进程。

镜像 ID: 每个镜像都是用唯一 IMAGE ID 标识,并用可视化别名 NAME[:TAG] 分类显示,ID 和别名是一对多的关系;如同 IP 对域名一样。TAG 不指定的时候表示默认值 latest,但是不推荐用默认值。 镜像 digest: 镜像摘要 When pushing or pulling to a 2.0 registry, the push or pull command output includes the image digest. You can pull using a digest value. You can also reference by digest in create, run, and rmi commands, as well as the FROM image reference in a Dockerfile.

4.2   通过命令输出理解镜像

  1. 下面实例通过 Dockerfile 文件创建一个镜像。Dockerfile 文件内容如下:
FROM alpine:3.9
ENV ABC_VERSION   20190416
RUN apk add --no-cache --virtual .persistent-deps xz
COPY test_copy /usr/local/etc
ADD test_add /usr/local/etc
RUN adduser -u 1001 -D -s /sbin/nologin pub
EXPOSE 80
CMD ["/bin/sh"]
  1. 看创建时输出信息:
> docker build -t dtest:1.0 .
Sending build context to Docker daemon  324.1kB
Step 1/8 : FROM alpine:3.9
 ---> cdf98d1859c1
Step 2/8 : ENV ABC_VERSION   20190416
 ---> Running in 44ed3f9df47b
Removing intermediate container 44ed3f9df47b
 ---> a06b9552c5be
Step 3/8 : RUN apk add --no-cache --virtual .persistent-deps xz
 ---> Running in fd75b4d2063c
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/community/x86_64/APKINDEX.tar.gz
(1/3) Installing xz-libs (5.2.4-r0)
(2/3) Installing xz (5.2.4-r0)
(3/3) Installing .persistent-deps (0)
Executing busybox-1.29.3-r10.trigger
OK: 6 MiB in 17 packages
Removing intermediate container fd75b4d2063c
 ---> c421ae62239c
Step 4/8 : COPY test_copy /usr/local/etc
 ---> 123b7cf03238
Step 5/8 : ADD test_add /usr/local/etc
 ---> f63b6fdf1995
Step 6/8 : RUN adduser -u 1001 -D -s /sbin/nologin pub
 ---> Running in dc2be3fdbc00
Removing intermediate container dc2be3fdbc00
 ---> cd4063d6d004
Step 7/8 : EXPOSE 80
 ---> Running in df6d2ebc78ef
Removing intermediate container df6d2ebc78ef
 ---> a948ed8f4770
Step 8/8 : CMD ["/bin/sh"]
 ---> Running in cc2b4eaca4a6
Removing intermediate container cc2b4eaca4a6
 ---> b28b2394f41a
Successfully built b28b2394f41a
Successfully tagged dtest:1.0
  1. 查看所生成的镜像和中间镜像,注意这里上下并不是依赖关系,仅仅是时间排序。
> docker images -a
dtest               1.0                 b28b2394f41a        37 seconds ago      5.83MB
<none>              <none>              a948ed8f4770        37 seconds ago      5.83MB
<none>              <none>              cd4063d6d004        37 seconds ago      5.83MB
<none>              <none>              f63b6fdf1995        38 seconds ago      5.82MB
<none>              <none>              123b7cf03238        38 seconds ago      5.82MB
<none>              <none>              c421ae62239c        38 seconds ago      5.82MB
<none>              <none>              a06b9552c5be        41 seconds ago      5.53MB
  1. 查看构建历史
> docker history dtest:1.0
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
b28b2394f41a        2 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
a948ed8f4770        2 minutes ago       /bin/sh -c #(nop)  EXPOSE 80                    0B
cd4063d6d004        2 minutes ago       /bin/sh -c adduser -u 1001 -D -s /sbin/nolog…   4.82kB
f63b6fdf1995        2 minutes ago       /bin/sh -c #(nop) ADD file:b803a882fa128cb8c…   9B
123b7cf03238        2 minutes ago       /bin/sh -c #(nop) COPY file:24b874c6ab361858…   17B
c421ae62239c        2 minutes ago       /bin/sh -c apk add --no-cache --virtual .per…   291kB
a06b9552c5be        2 minutes ago       /bin/sh -c #(nop)  ENV ABC_VERSION=20190416     0B
cdf98d1859c1        7 days ago          /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           7 days ago          /bin/sh -c #(nop) ADD file:2e3a37883f56a4a27…   5.53MB
  1. 查看 所有镜像的 layers
> docker inspect -f '{{json .RootFS.Layers}}'  `docker history -q dtest:1.0`
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9","sha256:35b7153bfc8fd8e90ff45282bf7abb9c43046400287a912693fa409d4278818c","sha256:e7d271231802f2b45e74efcb14dfefc5dd952e0c3914fa823a5ce2c30c461043","sha256:3077c11a618ad8a5da0802c9228e4c17f1b0759950fbcca7256d2bdcdcf922a4","sha256:1e9e99d1a6a31105f60b0e466627405b653f1159d27d3c0f265e5f3c9f99e812"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9","sha256:35b7153bfc8fd8e90ff45282bf7abb9c43046400287a912693fa409d4278818c","sha256:e7d271231802f2b45e74efcb14dfefc5dd952e0c3914fa823a5ce2c30c461043","sha256:3077c11a618ad8a5da0802c9228e4c17f1b0759950fbcca7256d2bdcdcf922a4","sha256:1e9e99d1a6a31105f60b0e466627405b653f1159d27d3c0f265e5f3c9f99e812"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9","sha256:35b7153bfc8fd8e90ff45282bf7abb9c43046400287a912693fa409d4278818c","sha256:e7d271231802f2b45e74efcb14dfefc5dd952e0c3914fa823a5ce2c30c461043","sha256:3077c11a618ad8a5da0802c9228e4c17f1b0759950fbcca7256d2bdcdcf922a4","sha256:1e9e99d1a6a31105f60b0e466627405b653f1159d27d3c0f265e5f3c9f99e812"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9","sha256:35b7153bfc8fd8e90ff45282bf7abb9c43046400287a912693fa409d4278818c","sha256:e7d271231802f2b45e74efcb14dfefc5dd952e0c3914fa823a5ce2c30c461043","sha256:3077c11a618ad8a5da0802c9228e4c17f1b0759950fbcca7256d2bdcdcf922a4"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9","sha256:35b7153bfc8fd8e90ff45282bf7abb9c43046400287a912693fa409d4278818c","sha256:e7d271231802f2b45e74efcb14dfefc5dd952e0c3914fa823a5ce2c30c461043"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9","sha256:35b7153bfc8fd8e90ff45282bf7abb9c43046400287a912693fa409d4278818c"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9"]
["sha256:a464c54f93a9e88fc1d33df1e0e39cca427d60145a360962e8f19a1dbf900da9"]
Error: No such object: <missing>
  1. 删除镜像
> docker rmi dtest:1.0
Untagged: dtest:1.0                                                                Step
Deleted: sha256:b28b2394f41a2793a39ef52d5dd9d2baee25577ca186ae418f40788953461feb     8
Deleted: sha256:a948ed8f4770e63f048bd70cfeed285282b8f00cabd1e1f533a87f108bc732b0     7
Deleted: sha256:cd4063d6d0042155a55656769d862f245e52c3b4850c0058b9df57a2efb14f7e     6
Deleted: sha256:4e93fada93b2cd4957de03f29afcef7a1902f32bcfc2c1dc18981589908d17cc     删除6引用layer
Deleted: sha256:f63b6fdf19958d210f4025bd8e7712674100c258dc9cec1989b694f8ce584bb6     5
Deleted: sha256:137b3352b7489125cefce90a8090e65784b80f26cfd1d1d3cd476b8aaaa1ec25     删除5引用layer
Deleted: sha256:123b7cf032389fe77fbf9ceb824b78d193245994f4363a0afe54c22f022ef979     4
Deleted: sha256:24763812613715916999c97b6701f9efad57b5279037ada7379173cc4d3c2743     删除4引用layer
Deleted: sha256:c421ae62239c98dd587bc7f5a9acb03ea2566a72025b21006c25373ec0c186d9     3
Deleted: sha256:6a9da1e2e4d23c4323fb85d14fe8ca6d030a367d712189f193638296f5c82f68     删除3引用layer
Deleted: sha256:a06b9552c5be5fa3546e5eb25db5dccc196dfdb1fc3cd6f90def57bd0bac9488     2
Step 指令 中间容器 ID IMAGE ID Layers(只截前5字符) 说明
1 FROM - cdf98d1859c1 a464c 基础镜像 layer
2 ENV 44ed3f9df47b a06b9552c5be a464c 元数据
3 RUN fd75b4d2063c c421ae62239c a464c,35b71 新 layer
4 COPY - 123b7cf03238 a464c,35b71 e7d27 新 layer
5 ADD - f63b6fdf1995 a464c,35b71,e7d27 3077c, 新 layer
6 RUN dc2be3fdbc00 cd4063d6d004 a464c,35b71,e7d27,3077c,ef463 新 layer
7 EXPOSE df6d2ebc78ef a948ed8f4770 a464c,35b71,e7d27,3077c,ef463 元数据
8 CMD cc2b4eaca4a6 b28b2394f41a a464c,35b71,e7d27,3077c,ef463 元数据

根据以上分析可以看出,所有涉及的镜像仅由 5 layers 组成,第一个就是基础镜像的 layer,RUN、COPY、ADD、RUN 新增加 4 个 layers,从 history 的 SIZE 字段也可以看出。而 ENV、EXPOSE、CMD 只增加了元数据。关于如何区分命令是否会新建镜像层,一个基本的原则是,如果指令的作用是向镜像中增添新的文件或者程序,那么这条指令就会新建镜像层;如果只是告诉 Docker 如何完成构建或者如何运行应用程序,那么就只会增加镜像的元数据。所以并非所有的 RUN 都会有创建新层,比如 RUN echo "no data" 就不会创建新的层。 每一个指令都有相应的镜像,但是否生成中间容器要看指令看是否需要运行验证。 删除镜像的时候,会把新生成的7个镜像和4个 layers 都删除掉。对于拉取的镜像没有中间镜像,删除的时候就只主镜像和 layers。

4.3   inspect image

inspect 命令可以列出与镜像相关的信息,但是这些信息并不都是镜像的属性,而是对同一个镜像 ID 信息的归纳。以下列举一些说明:

5   容器

容器是以镜像为模板,在镜像上添加一层可写的容器层就成为容器:baseImage/image/image…/container,对容器的修改仅限于该容器的可写层。可以比喻镜像是类,容器是实例化的对象。

6   常用命令

  1. 正常镜像的中间镜像,无法删除,因为被上层依赖。docker images -a 命令才看得到;
  2. dangling 镜像,即重复 build 会把原来正常的镜像变成 dangling,可以用 docker rmi $(docker images -f “dangling=true” -q) 删除;
  3. 没用的镜像,可以用 docker image prune -f 删除。

也可以不加-d,并运行/bin/sh,依次输入ctrl+p、ctrl+q,就不会终止容器而只是退出。 –restart string Restart policy to apply when a container exits (default “no”)

上面的命令基本够用了,更多的命令可以查阅官方文档 Command-Line Interfaces

7   本地仓库

部署一个本地仓库可以查阅官方文档 Docker Registry,需要注意的几点是:

7.1   服务端

最简单可以用 docker run -d -p 5000:5000 --restart=always --name registry registry:2.7.1 这种情况只能在宿主机下操作,为了在其它主机连接上仓库,必须用 TLS。

接下来用自签名证书演示:

$ mkdir -p certs

$ openssl req \
  -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
  -x509 -days 365 -out certs/domain.crt -subj "/CN=192.168.56.113"
#Be sure to use the name myregistrydomain.com as a CN. 可以加 -subj '/C=CN/ST=ShenZhen/L=NanShan/CN=<Ipaddress>'

$ docker run -d \
  --restart=always \
  --name registry \
  -v `pwd`/registry:/var/lib/registry \
  -v `pwd`/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  -p 5000:5000 \
  registry:2.7.1

7.2   客户端配置

客户端配置其实就是公钥配置。

参考文献 [1] Nigel Poulton. 深入浅出 Dokcer. 版次:2019年4月第1版 [2] Lan Miell.等. Docker 实践. 版次:2018年2月第1版 [3] Explaining Docker Image IDs. https://windsock.io/explaining-docker-image-ids/