作者王涛,就职于悉尼一家数据分析公司。喜欢开源,对 Docker 有较深入的研究和实践。2017 年 1 月 18 日 Docker 1.13 新版本发布,他于第一时间发布了新版本的功能解读。本文为道客船长授权转载。
原文博客链接 ;欢迎关注王涛的 个人博客 ,阅读更多 Docker 干货及最新动态。
Docker 1.13
在 2017 年 1 月 18 日发布了。从 2016 年 7 月 29 日发布 1.12
发布以来,已经过去 5 个多月了,对于活跃的 Docker 社区来说,已经很久了,让我们看看都 1.13
都新增了什么内容吧。
1.13
有 一千四百多个 issue/pull request
,五千多个 commits,是 Docker 历史上最高的发布版本。这并不是一个简单的小版本变化,里面有大量的更新。
在发布之后,可以直接安装最新版本。在一个新的 Ubuntu / CentOS 系统中直接执行:
curl -fsSLhttps://get.docker.com/ | sh -s -- --mirror AzureChinaCloud
docker stack
docker plugin
secret
管理服务: docker secret
docker system
命令 docker-compose.yml
进行服务部署 docker service
滚动升级出故障后回滚的功能 docker service update --force
docker service create
映射宿主端口,而不是边界负载均衡网络端口 docker run
连入指定的 swarm mode 的 overlay
网络 GFW
墙掉 docker-engine
apt
/ yum
源的问题
让我们来详细解读一下
1.13.0
新增功能
吧。
https://github.com/docker/docker/pull/26839
我们都知道使用 Dockerfile
构建镜像的时候,会充分利用分层存储的特性进行缓存,之前构建过的层,如果没有变化,那么会直接使用缓存的内容,避免没有意义的重复构建。不过使用缓存的前提条件是曾经在本地构建过这个镜像。这在 CI 进行集群构建时是一个比较麻烦的问题,因为构建任务可能会被分配到不同的机器上,而该机器没有构建过该镜像,因此缓存总是用不上,因此大量的时间浪费在了重复构建已经构建过的层上了。
在 1.13
中,为 docker build
增加了一个新的参数 --cache-from
,利用镜像中的 History 来判断该层是否和之前的镜像一致,从而避免重复构建。
比如我们先下载获取作为缓存的镜像:
$ dockerpullmongo:3.2 3.2: Pullingfromlibrary/mongo 386a066cd84a: Pullcomplete 524267bc200a: Pullcomplete 476d61c7c43a: Pullcomplete 0750d0e28b90: Pullcomplete 4bedd83d0855: Pullcomplete b3b5d21a0eda: Pullcomplete 7354b6c26240: Pullcomplete db792d386b51: Pullcomplete a867bd77950c: Pullcomplete Digest: sha256:532a19da83ee0e4e2a2ec6bc4212fc4af26357c040675d5c2629a4e4c4563cef Status: Downloadednewerimagefor mongo:3.2
然后我们使用更新后的 Dockerfile
构建镜像时,如果加上 --cache-from mongo:3.2
后,会发现如果是已经在 mongo:3.2
中存在并没有修改的层,就会用 mongo:3.2
中的该层做缓存。
$ dockerbuild --cache-frommongo:3.2 -t mongo:3.2.1 . Sendingbuildcontextto Dockerdaemon 4.608 kB Step 1/18 : FROMdebian:jessie ---> 73e72bf822ca Step 2/18 : RUNgroupadd -r mongodb && useradd -r -g mongodbmongodb ---> Usingcache ---> 0f6297900a5e Step 3/18 : RUNapt-getupdate && apt-getinstall -y --no-install-recommends numactl && rm -rf /var/lib/apt/lists/* ---> Usingcache ---> a465f2e906fc Step 4/18 : ENVGOSU_VERSION 1.7 ---> Usingcache ---> d448ddca2126 ...
squash
)镜像(实验阶段) https://github.com/docker/docker/pull/22641
对于总是把 Dockerfile
当做 bash
文件来用的人,会发现很快由于太多的 RUN
导致镜像有特别多的层,镜像超级臃肿,而且甚至会碰到超出最大层数限制的问题。这些人往往不从自身找问题,反而去寻找旁门左道,比如导出镜像做一些特殊处理,合并为一层,然后再导入等等,这种做法是很错误的,除了导致构建缓存失败外,还导致 docker history
丢失,导致镜像变为黑箱镜像。其实正确的做法是遵循 Dockerfile
最佳实践,应该把多个命令合并为一个 RUN
,每一个 RUN
要精心设计,确保安装构建最后进行清理。这样才可以降低镜像体积,以及最大化的利用构建缓存。
在 Docker 1.13 中,为了应对这群用户,实验性的提供了一个 --squash
参数给 docker build
,其功能就是如上所说,将 Dockerfile
中所有的操作,压缩为一层。不过,与旁门左道不同,它保留了 docker history
。
比如如下的 Dockerfile
:
FROMbusybox RUNechohello > /hello RUNechoworld >> /hello RUNtouchremove_me /remove_me ENVHELLOworld RUNrm /remove_me
如果我们正常的构建的话,比如 docker build -t my-not-squash .
,其 history
是这样子的:
$ dockerhistorymy-not-squash IMAGE CREATED CREATEDBY SIZE COMMENT 305297a526e2 About a minuteago /bin/sh -c rm /remove_me 0 B 60b8e896d443 About a minuteago /bin/sh -c #(nop) ENV HELLO=world 0 B a21f3c75b6b0 About a minuteago /bin/sh -c touchremove_me /remove_me 0 B 038bca5b58cb About a minuteago /bin/sh -c echoworld >> /hello 12 B f81b1006f556 About a minuteago /bin/sh -c echohello > /hello 6 B e02e811dd08f 5 weeksago /bin/sh -c #(nop) CMD ["sh"] 0 B <missing> 5 weeksago /bin/sh -c #(nop) ADD file:ced3aa7577c8f97... 1.09 MB
而如果我们用 --squash
构建:
dockerbuild -t mysquash --squash .
其 history
则是这样子:
$ dockerhistorymysquash IMAGE CREATED CREATEDBY SIZE COMMENT a557e397ff56 15 secondsago 12 B mergesha256:305297a526e218e77f1b4b273442f8ac6283e2907e6513ff36e9048aa130dea6 to sha256:e02e811dd08fd49e7f6032625495118e63f597eb150403d02e3238af1df240ba <missing> 15 secondsago /bin/sh -c rm /remove_me 0 B <missing> 15 secondsago /bin/sh -c #(nop) ENV HELLO=world 0 B <missing> 15 secondsago /bin/sh -c touchremove_me /remove_me 0 B <missing> 16 secondsago /bin/sh -c echoworld >> /hello 0 B <missing> 16 secondsago /bin/sh -c echohello > /hello 0 B <missing> 5 weeksago /bin/sh -c #(nop) CMD ["sh"] 0 B <missing> 5 weeksago /bin/sh -c #(nop) ADD file:ced3aa7577c8f97... 1.09 MB
我们可以注意到,所有层的层ID都 <missing>
了,并且多了一层 merge
。
要注意,这并不是解决懒惰的办法,撰写 Dockerfile 的时候,依旧需要遵循最佳实践,不要试图用这种办法去压缩镜像。
--network
指定网络 https://github.com/docker/docker/pull/27702 https://github.com/docker/docker/issues/10324
在一些网络环境中,我们可能需要定制 /etc/hosts
文件来提供特定的主机和 IP 地址映射关系,无论是应对 GFW,还是公司内部 Git 服务器,都有可能有这种需求,这个时候构建时修改 /etc/hosts
是一个比较麻烦的事情。使用内部 DNS 虽然是一种解决办法,但是这将是全引擎范围的,而且并非所有环境都会有内部 DNS。更好地做法是使用宿主网络进行构建。另外,有的时候,或许这个构建所需 Git 服务器位于容器内网络,我们需要指定某个 overlay
网络来给镜像构建所需。
在 1.13
中,为 docker build
提供了 --network
参数,可以指定构建时的网络。
比如,我们有一个 Dockerfile
内容为:
FROMubuntu RUNcat /etc/hosts
内容很简单,就是看看构建时的 /etc/hosts
的内容是什么。假设我们宿主的 /etc/hosts
中包含了一条 1.2.3.4
到 example.com
的映射关系。
1.2.3.4 example.com
如果我们如同以往,使用默认网络进行构建。那么结果会是这样:
$ dockerbuild --no-cache -t build-network . Sendingbuildcontextto Dockerdaemon 2.048 kB Step 1/2 : FROMubuntu ---> 104bec311bcd Step 2/2 : RUNcat /etc/hosts ---> Runningin 42f0c014500f 127.0.0.1 localhost ::1 localhostip6-localhostip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 2866979c4d77 ---> 5f0b3dd56a32 Removingintermediatecontainer 42f0c014500f Successfullybuilt 5f0b3dd56a32
可以注意到,这次构建所看到的是容器默认网络的 /etc/hosts
,其内没有宿主上添加的条目 1.2.3.4 example.com
。
然后我们使用 docker build --network=host
来使用宿主网络构建:
$ dockerbuild --no-cache -t build-network --network=host . Sendingbuildcontextto Dockerdaemon 2.048 kB Step 1/2 : FROMubuntu ---> 104bec311bcd Step 2/2 : RUNcat /etc/hosts ---> Runningin b990c4e55424 # Your system has configured 'manage_etc_hosts' as True. # As a result, if you wish for changes to this file to persist # then you will need to either # a.) make changes to the master file in /etc/cloud/templates/hosts.tmpl # b.) change or remove the value of 'manage_etc_hosts' in # /etc/cloud/cloud.cfg or cloud-config from user-data # 127.0.1.1 d1.localdomaind1 127.0.0.1 localhost # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhostip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts 1.2.3.4 example.com ---> 63ef6cb93316 Removingintermediatecontainerb990c4e55424 Successfullybuilt 63ef6cb93316
这次由于使用了 --network=host
参数,于是使用的是宿主的网络命名空间,因此 /etc/hosts
也是宿主的内容。我们可以在其中看到 1.2.3.4 example.com
条目。
docker build
中定义 Dockerfile
未使用的参数(ARG) https://github.com/docker/docker/pull/27412
我们都知道镜像构建时可以用 --build-arg
来定义参数,这样 Dockerfile
就会使用这个参数的值来进行构建。这对于 CI/CD 系统很重要,我们可以使用一套 Dockerfile
来构建不同条件下的镜像。
但在 1.13
以前,这里有个问题,在 CI 系统中,我们有时希望用一套构建命令、脚本,通过给入不同的 Dockerfile
来构建不同的镜像,而 --build-arg
的目的是定义一些有可能会用到的全局变量,但是如果有的 Dockerfile
中没用这个变量,那么构建就会失败。 #26249
$ catDockerfile FROMubuntu RUNenv $ dockerbuild -t myapp --build-argVERSION=1.2.3 --no-cache . Sendingbuildcontextto Dockerdaemon 2.048 kB Step 1 : FROMubuntu ---> 104bec311bcd Step 2 : RUNenv ---> Runningin 81f4ba452a49 HOSTNAME=2866979c4d77 HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ ---> f78b4696a1ca Removingintermediatecontainer 81f4ba452a49 Oneor morebuild-args [VERSION] werenot consumed, failingbuild.
其背后的思想是,如果 --build-arg
指定了,但是没用,那么很可能是因为拼写错误、或者忘记了应该使用这个变量而出现的问题。最初 docker build
对于这类情况的处理,是直接报错退出,构建失败。
但是在上面的 CI 的案例中, --build-arg
只是定义一些 可能
用到的环境变量,并不强制使用,这种情况下,如果因为 Dockerfile
没有使用可能用到的变量就报错就有些过了。因此在 1.13
中,将其 降为警告
,并不终止构建,只是提醒用户有些变量未使用。
$ dockerbuild --no-cache -t myapp --build-argVERSION=1.2.3 . Sendingbuildcontextto Dockerdaemon 2.048 kB Step 1/2 : FROMubuntu ---> 104bec311bcd Step 2/2 : RUNenv ---> Runningin bb5e605cb4d0 HOSTNAME=2866979c4d77 HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ ---> 97207d784048 Removingintermediatecontainerbb5e605cb4d0 [Warning] Oneor morebuild-args [VERSION] werenot consumed Successfullybuilt 97207d784048
GFW
影响 Docker
安装问题 https://github.com/docker/docker/pull/27005
官方的 apt
/ yum
源使用的是 AWS
的服务,并且为了确保安全使用了 HTTPS
,因此伟大的墙很乐于干扰大家使用。没办法的情况下,各个云服务商纷纷建立自己官方源镜像,阿里云、DaoCloud、Azura 等等,并且自己做了个修订版的 https://get.docker.com
的脚本来进行安装。
现在这个发生改变了,官方的 https://get.docker.com
将支持 --mirror
参数,你可以用这个参数指定国内镜像源,目前支持微软的 Azure 云,( 或阿里云?(更新:由于阿里云镜像源不支持 HTTPS,所以不会支持阿里云)
)。使用方法如下,将原来官网安装命令:
curl -sSLhttps://get.docker.com/ | sh
替换为:
curl -sSLhttps://get.docker.com/ | sh -s -- --mirror AzureChinaCloud
在这次发布中,增加了
Ubuntu 16.10
的安装包
,而且对 Ubuntu
系统增加了
PPC64LE
和
s390x
构架的安装包。此外,还正式支持了
VMWare Photon OS
系统
的 RPM
安装包,以及在 https://get.docker.com
的支持。并且支持了
Fedora 25
,甚至开始支持
arm64
。同时也由于一些系统生命周期的结束,而被移除支持,比如 Ubuntu 15.10
、 Fedora 22
都不在支持了。
docker run
连入指定的 swarm mode
的网络 https://github.com/docker/docker/pull/25962
在 Docker 1.12 发布新的 Swarm Mode 之后,很多人都问过这样的问题,怎么才能让 docker run
的容器连入 Swarm Mode 服务的 overlay
网络中去?答案是不可以,因为 swarm
的 overlay
网络是为了 swarm mode service
准备的,相对更健壮,而直接使用 docker run
,会破坏了这里面的安全模型。
但是由于大家需求很多,于是提供了一种折衷的办法。1.13 允许建立网络的时候,设定该网络为 attachable
,允许之后的 docker run
的容器连接到该网络上。
我们创建一个默认的、不允许之后 attach
的网络:
$ dockernetworkcreate -d overlaymynet1 xmgoco2vfrtp0ggc5r0p5z4mg
然后再创建一个允许 attach
的网络,这里会使用 1.13 新加入的 --attachable
参数:
$ dockernetworkcreate -d overlay --attachablemynet2 yvcyhoc6ni0436jux9azc4cjt
然后我们启动一个 web
服务,连入这两个网络:
$ dockerservicecreate / --nameweb / --networkmynet1 / --networkmynet2 / nginx vv91wd7166y80lbl833rugl2z
现在我们用 docker run
启动一个容器连入第一个网络:
$ dockerrun -it --rm --networkmynet1busybox docker: Errorresponsefromdaemon: Couldnot attachto networkmynet1: rpcerror: code = 7 desc = networkmynet1not manuallyattachable.
由于 mynet1
不允许手动 attach
所以这里报错了。
在 1.12 的情况下,会报告该网络无法给 docker run
使用:
docker: Errorresponsefromdaemon: swarm-scopednetwork (mynet1) is not compatiblewith `dockercreate` or `dockerrun`. This networkcanonlybeusedby a dockerservice. See 'docker run --help'.
不过, --attachable
实际上是将网络的安全模型打开了一个缺口,因此这不是默认设置,而且并不推荐使用。用户在使用这个选项建立网络的时候,一定要知道自己在做什么。
docker service create
映射宿主端口,而不是边界负载均衡网络端口 https://github.com/docker/docker/pull/27917 https://github.com/docker/docker/pull/28943
docker service create
中的 --publish
格式有进一步的变化。(在 1.13 的 RC 期间,曾经去掉 --publish
,改为 --port
,经过讨论后,决定保持一致性,继续使用 --publish
,不使用新的 --port
选项。)
在 1.12 中, docker service create
允许使用参数 --publish 80:80
这类形式映射 边界(ingress)网络
的端口,这样的映射会享受边界负载均衡,以及 routing mesh。
从 1.13 开始,增加另一种映射模式,被称为 host
模式,也就是说,用这种模式映射的端口,只会映射于容器所运行的主机上。这就和一代 Swarm 中一样了。虽然失去了边界负载均衡,但是确定了映射点,在有的时候这种情况是需要的。
现在 --publish
的新的参数形式和 --mount
差不多。参数值为 ,
逗号分隔的键值对,键值间以 =
等号分隔。目前支持 4 项内容:
protocol
: 支持 tcp
或者 udp
mode
: 支持 ingress
或者 host
target
: 容器的端口号 published
: 映射到宿主的端口号
比如,与 -p 8080:80
等效的 --publish
新格式选项为:
--publishprotocol=tcp,mode=ingress,published=8080,target=80
当然我们可以继续使用 -p 8080:80
,但是新的选项格式增加了更多的可能。比如,使用 1.13 开始加入的 host
映射模式:
ubuntu@d1:~$ dockerservicecreate --nameweb / --publishmode=host,published=80,target=80 / nginx
运行成功后,查看一下服务容器运行的节点:
ubuntu@d1:~$ dockernodels ID HOSTNAME STATUS AVAILABILITY MANAGERSTATUS ntjybj51u6zp44akeawuf3i05 d2 Ready Active tp7icvjzvxla2n18j3nztgjz6 d3 Ready Active vyf3mgcj3uonrnh5xxquasp38 * d1 Ready Active Leader ubuntu@d1:~$ dockerservicepsweb ID NAME IMAGE NODE DESIREDSTATE CURRENTSTATE ERROR PORTS 5tij5sjvfpsf web.1 nginx:latest d3 Running Running 5 minutesago *:80->80/tcp
我们可以看到,集群有3个节点,而服务就一个副本,跑到了 d3
上。如果这是以前的使用边界负载均衡的网络 ingress
的话,那么我们访问任意节点的 80
端口都会看到页面。
但是, host
模式不同,它只映射容器所在宿主的端口。因此,如果我们 curl d1
的话,应该什么看不到网页,而 curl d3
的话就会看到页面:
root@d1:~$ curllocalhost curl: (7) Failedto connectto localhostport 80: Connectionrefused
root@d3:~$ curllocalhost <!DOCTYPEhtml> <html> <head> <title>Welcometo nginx!</title> ...
iptables
的转发规则将默认拒绝 https://github.com/docker/docker/pull/28257
从默认 FORWARD
改为 DROP
,从而避免 容器外露的安全问题
。
docker network inspect
里显示连入的节点
我们都是知道,在 swarm mode
中创建的 overlay
网络,并不是一下子就在集群中的每个节点上 docker network ls
就可以看到这个网络,这完全没有必要。只有当使用该网络的容器调度到某个节点上后,才会将该节点连入此 overlay
网络。在网络排障过程中,经常会有这种需求,需要得知现在连入该 overlay
网络中的节点到底有哪些,这在 1.13
之前不容易做到。
从 1.13
开始, docker network inspect
将显示连接到了这个网络的节点(宿主)有哪些。
$ docker network inspect mynet [ { "Name": "mynet", "Id": "jjpnbdh8vu4onjojskntd2jhh", "Created": "2017-01-18T00:00:31.742146058Z", "Scope": "swarm", "Driver": "overlay", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "10.0.0.0/24", "Gateway": "10.0.0.1" } ] }, "Internal": false, "Attachable": false, "Containers": { "3cafea27c53de34724e46d4fe83c9e60311b628b82e9be66d8d2e0812669d575": { "Name": "myapp.2.qz2hs1eqq3ikx59ydh0w7u1g4", "EndpointID": "0e26b08254e851b7b238215cec07acdd8b0b68dc4671f55235e203a0c260522f", "MacAddress": "02:42:0a:00:00:04", "IPv4Address": "10.0.0.4/24", "IPv6Address": "" } }, "Options": { "com.docker.network.driver.overlay.vxlanid_list": "4097" }, "Labels": {}, "Peers": [ { "Name": "d1-23348b84b134", "IP": "138.197.213.116" }, { "Name": "d2-8964dea9e75c", "IP": "138.197.221.47" } ] } ]
从上面的例子可以看出,一共有两个宿主连入了这个 mynet
的 overlay
网络,分别为 138.197.213.116
和 138.197.221.47
。
service
VIP
可以被 ping
https://github.com/docker/docker/pull/28019
在 1.12 的二代 Swarm 排障过程中,常见的一个问题就是
跨节点的服务 VIP 不可以 ping
,所以很多时候很多时候搞不懂是 overlay
网络不通呢?还是服务没起来?还是服务发现有问题?这个问题在 1.13 解决了,VIP 可以随便 ping
,跨宿主也没关系。
https://github.com/docker/docker/pull/28226
在 1.12 引入了插件概念后,作为试验特性得到了很多关注。包括 Docker Store 开始准备上线,以及第三方的插件的开发。现在 1.13 插件作为正式功能提供了。
$ dockerplugin Usage: dockerpluginCOMMAND Manageplugins Options: --help Printusage Commands: create Create a pluginfrom a rootfsand config disable Disable a plugin enable Enable a plugin inspect Displaydetailedinformationononeor moreplugins install Install a plugin ls Listplugins push Push a pluginto a registry rm Removeoneor moreplugins set Changesettingsfor a plugin Run 'docker plugin COMMAND --help' for moreinformationon a command.
相比于 1.12 的试验版本而言,最重要的是增加了 docker plugin create
命令,可以指定一个包含有 config.json
文件和 rootfs
目录的目录来创建插件。
$ ls -ls /home/pluginDir 4 -rw-r--r-- 1 rootroot 431 Nov 7 01:40 config.json 0 drwxr-xr-x 19 rootroot 420 Nov 7 01:40 rootfs $ dockerplugincreateplugin /home/pluginDir plugin $ dockerpluginls ID NAME TAG DESCRIPTION ENABLED 672d8144ec02 plugin latest A samplepluginfor Docker false
checkpoint
功能(试验功能) https://github.com/docker/docker/pull/22049
checkpoint
功能可以将运行中的容器状态冻结并保存为文件,并在将来可以从文件加载恢复此时的运行状态。
目前它所依赖的是 criu
这个工具,因此在 Linux 上需要先安装这个工具。(目前尚无法在 Docker for Mac 中使用 docker/for-mac#1059
)
如果未安装 criu
则会出现如下报错:
Errorresponsefromdaemon: Cannotcheckpointcontainermyapp1: rpcerror: code = 2 desc = exitstatus 1: "Unable to execute CRIU command: criu/n"
对于 Ubuntu 系统,可以执行下面的命令安装 criu
:
$ sudoapt-getinstall -y criu
由于这个是试验功能,因此需要在 docker.service
中 ExecStart=
这行后面添加 --experimental
选项。其它试验功能也需如此配置。
然后不要忘了 systemctl daemon-reload
和 systemctl restart docker
。
执行 docker checkpoint create
就可以为容器创建 checkpoint
。
$ dockercheckpointcreatemyapp1checkpoint1 checkpoint1
可以为一个容器创建多个 checkpoint
,每个起不同的名字就是了。
然后可以用 docker checkpoint ls
来列出已经创建的 checkpoint
:
$ dockercheckpointlsmyapp1 CHECKPOINTNAME checkpoint1
如果不加 --leave-running
参数的话,容器就会在创建完 checkpoint
就会被停止运行。
然后我们可以通过 docker start --checkpoint
来从某个 checkpoint
恢复运行:
$ dockerstart --checkpointcheckpoint1myapp1
容器就会从 checkpoint1
这个点恢复并继续运行。
备份时可以用 --checkpoint-dir
指定具体的保存 checkpoint
的目录:
$ dockercheckpointcreate --checkpoint-dir $PWD/backup --leave-runningmyapp1checkpoint1 checkpoint1
然后我们可以在 backup
中看到实际保存的文件内容:
$ treebackup/ backup/ └── checkpoint1 ├── cgroup.img ├── config.json ├── core-1.img ├── core-54.img ├── criu.work │ ├── dump.log │ └── stats-dump ├── descriptors.json ├── fdinfo-2.img ├── fdinfo-3.img ├── fs-1.img ├── fs-54.img ├── ids-1.img ├── ids-54.img ├── inventory.img ├── ip6tables-9.img ├── ipcns-var-10.img ├── iptables-9.img ├── mm-1.img ├── mm-54.img ├── mountpoints-12.img ├── pagemap-1.img ├── pagemap-54.img ├── pages-1.img ├── pages-2.img ├── pipes-data.img ├── pipes.img ├── pstree.img ├── reg-files.img ├── seccomp.img ├── sigacts-1.img ├── sigacts-54.img ├── tmpfs-dev-46.tar.gz.img ├── tmpfs-dev-49.tar.gz.img ├── tmpfs-dev-50.tar.gz.img ├── unixsk.img └── utsns-11.img
docker stats
终于可以显示容器名了 https://github.com/docker/docker/pull/27797 https://github.com/docker/docker/pull/24987
docker stats
可以显示容器的资源占用情况,用来分析不同容器的开销很有帮助。不过一直以来有个很讨厌的问题, docker stats
不显示容器名:
$ dockerstats CONTAINER CPU % MEMUSAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS e8cb2945b156 0.00% 1.434 MiB / 488.4 MiB 0.29% 1.3 kB / 648 B 12.3 kB / 0 B 2 61aada055db8 0.00% 3.598 MiB / 488.4 MiB 0.74% 1.3 kB / 1.3 kB 2.29 MB / 0 B 2
这让人根本没办法知道到底谁是谁。于是有各种 变通的办法 ,比如:
$ dockerstats $(dockerps --format={{.Names}})
但是这个列表是静态的,容器增加、删除都得重新运行这个命令。
从 1.13
开始,虽然依旧默认没有容器名,但是增加了 --format
参数可以自己设计输出格式:
$ dockerstats --format 'table {{.Name}}/t{{.CPUPerc}}/t{{.MemUsage}}/t{{.MemPerc}}/t{{.NetIO}}/t{{.BlockIO}}/t{{.PIDs}}' NAME CPU % MEMUSAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS app2.1.5tij5sjvfpsft2lctxh8m8trn 0.00% 1.434 MiB / 488.4 MiB 0.29% 1.3 kB / 648 B 12.3 kB / 0 B 2 app1.1.mjmb8b0f0w5sy2v41jth3v9s4 0.00% 3.598 MiB / 488.4 MiB 0.74% 1.3 kB / 1.3 kB 2.29 MB / 0 B 2
docker ps
增加 is-task
过滤器 https://github.com/docker/docker/pull/24411
开始使用 Swarm Mode 后,经常碰到的一个问题就是, docker ps
所看到的这些容器到底哪些是服务容器?哪些是 docker run
跑起来的单独的容器?
从 1.13
开始,增加了 is-task
过滤器,以区分普通容器和 Swarm Mode 的服务容器:
dockerps -f 'is-task=true' CONTAINERID IMAGE COMMAND CREATED STATUS PORTS NAMES cdf0d35db1d3 nginx@sha256:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303 "nginx -g 'daemon ..." 44 secondsago Up 44 seconds 80/tcp, 443/tcp myservice.1.6rdwhkb84j6ioyqlvk6h6bql8
https://github.com/docker/docker/pull/27745
在以前,docker 客户端和服务端必须版本一致,否则就会报 Client and server don't have the same version
这类错误。后来增加了 DOCKER_API_VERSION
环境变量,在客户端高于服务端版本时,可以通过这个环境变量指定服务端 API 版本,从而避免这类错误。
从 1.13
开始,将进行一些版本判断来进行处理,从而不会因为版本不一致而报错了。
$ dockerversion Client: Version: 1.13.0-dev APIversion: 1.24 (downgradedfrom 1.25) Goversion: go1.7.3 Gitcommit: ec3a34b Built: WedOct 26 00:54:51 2016 OS/Arch: linux/amd64 Server: Version: 1.12.2 APIversion: 1.24 Goversion: go1.6.3 Gitcommit: bb80604 Built: TueOct 11 17:00:50 2016 OS/Arch: linux/amd64 Experimental: false
docker inspect
将可以查看任何 docker 对象 https://github.com/docker/docker/pull/23614
我们应该很熟悉 docker inspect
,我们经常用它查看镜像、容器。从 1.13
开始,这将变的更高级,可以查看任何 Docker 对象。从网络、task、service、volume到之前的镜像、容器等等。
比如,我们用 docker service ps
列出了服务对应的 task
列表,得到 task id
后,我们可以直接 docker inspect
这个 task id
。
$ dockerservicepsmyservice ID NAME IMAGE NODE DESIREDSTATE CURRENTSTATE ERROR PORTS 6rdwhkb84j6i myservice.1 nginx:latest d1 Running Running 13 minutes ago $ docker inspect 6rdwhkb84j6i [ { "ID": "6rdwhkb84j6ioyqlvk6h6bql8", "Version": { "Index": 17 }, "CreatedAt": "2017-01-18T14:40:40.959516063Z", "UpdatedAt": "2017-01-18T14:40:52.302378995Z", "Spec": { "ContainerSpec": { "Image": "nginx:latest@sha256:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303", "DNSConfig": {} }, "Resources": { "Limits": {}, "Reservations": {} }, "RestartPolicy": { "Condition": "any", "MaxAttempts": 0 }, "Placement": {}, "ForceUpdate": 0 }, "ServiceID": "u7bidaojbndhrsgyj29unv4wg", "Slot": 1, "NodeID": "5s5nvnif1i4frentwidiu97mn", "Status": { "Timestamp": "2017-01-18T14:40:52.252715087Z", "State": "running", "Message": "started", "ContainerStatus": { "ContainerID": "cdf0d35db1d37266af56b59dd8c3cd54de46442987e25e6fd25d38da1da7e459", "PID": 6563 }, "PortStatus": {} }, "DesiredState": "running" } ]
--experimental
参数 https://github.com/docker/docker/pull/27223
以前我们如果希望测试当前试验功能,必须添加试验分支源,重装 docker
。这给测试试验分支带来了困难。现在变得简单了,不在分为两组可执行文件构建,合并为一个。如果需要测试试验功能,直接在 dockerd
后添加 --experimental
即可。
overlay2
存储驱动使用于 xfs
时可以添加磁盘配额 https://github.com/docker/docker/pull/24771
在 1.13 之前,只有块设备文件系统驱动(如 devicemapper
, xfs
, zfs
等)支持磁盘配额能力,而所有 Union FS
的驱动,都不支持配额。现在针对使用 XFS
为后端的 overlay2
驱动支持了磁盘配额,理论上同样的方式可以在将来移植到 AUFS
。
docker system
命令 https://github.com/docker/docker/pull/26108 https://github.com/docker/docker/pull/27525
很多人在以前搞不懂自己的镜像到底占了多少空间、容器占了多少空间,卷占了多少空间。怎么删除不用的东西以释放资源。从 1.13 开始,Docker 提供了一组 system
命令来帮助系统管理上的问题。
$ dockersystem Usage: dockersystemCOMMAND ManageDocker Options: --help Printusage Commands: df Showdockerdiskusage events Getrealtimeeventsfromtheserver info Displaysystem-wideinformation prune Removeunuseddata Run 'docker system COMMAND --help' for moreinformationon a command.
docker system df
是显示磁盘使用情况:
$ dockersystemdf TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 3 3 700.3 MB 123 MB (17%) Containers 3 3 15 B 0 B (0%) LocalVolumes 1 1 219.4 MB 0 B (0%)
显示的列表中列出了镜像、容器、本地卷所占用的磁盘空间,以及可能回收的磁盘空间。比如,我们看到镜像有 123MB 的空间可以回收,从 1.13 开始, docker
提供了一组 prune
命令,分别是:
docker image prune
:删除无用的镜像 docker container prune
:删除无用的容器 docker volume prune
:删除无用的卷 docker network prune
:删除无用的网络 docker system prune
:删除无用的镜像、容器、卷、网络
还记得之前删除这些资源所用的 docker rmi $(docker images -f dangling=true -aq)
这种命令么?现在可以简单地 docker image prune
即可删除。
此外,从上面已经可以看到,从 1.13 开始,命令都开始归类于各个子命令了。之前默认的 docker info
, docker ps
, docker rm
, docker run
都开始归类于对应的 docker image
, docker container
, docker system
下了。目前之前的命令依旧可以使用,会继续保持一段时间。但是从 1.13 开始,推荐使用各个子命令的版本了。
overlay2
的优先级 https://github.com/docker/docker/pull/27932
由于 overlay2
在 4.+ 内核的系统上趋于稳定,因此将其优先级提到 devicemapper
之上(优先级最高的依旧是 aufs
)
docker exec -t
自动添加 TERM 环境变量 https://github.com/docker/docker/pull/26461
对于在容器中使用 vi
、 htop
之类工具的人来说是比较方便的。之前由于默认没有定义 TERM
,这些需要终端页面布局的程序执行可能会不正常。比如:
$ htop Erroropeningterminal: unknown.
现在直接为 docker exec -t
选项添加了继承自当前的 TERM
变量,可以让这类工具可以正常使用。
Dockerfile
中的 USER
了; syslog
日志系统; fluentd
日志系统; overlay
网络了; docker stats
了; docker top
了; docker stack
1.12 中引入了二代 Swarm,也就是 Swarm Mode。由于基础理念变化很大,因此先行实现比较基本的服务( service
),但是针对应用/服务栈( stack
)没有成熟,只是试行使用 .DAB
文件进行集群部署。但是 DAB
是 JSON
文件,而且撰写较为复杂。相对大家已经习惯的 docker-compose.yml
却无法在 docker stack
中直接使用。只可以用 docker-compose bundle
命令将 docker-compose.yml
转换为 .dab
文件,然后才能拿到集群部署,而且很多功能用不了。
从 1.13 开始,将允许直接使用 docker-compose.yml
文件来进行部署( #27998
),大大方便了习惯了 docker compose
的用户。不过需要注意的是,由于理念的演化,原有的 docker-compose.yml
v2
格式无法使用,必须使用 v3
格式。
幸运的是 v3
和 v2
格式差距不大。
volumes_from
,需要共享数据用命名卷; volume_driver
,这种服务全局的东西没有必要,直接针对每个卷使用 volume
键下的 driver
即可; cpu_shares
, cpu_quota
, cpuset
, mem_limit
, memswap_limit
移到 deploy
下的 resources
下进行管控,毕竟这是部署资源控制的部分。 具体差异可以看官方文档:https://github.com/docker/docker.github.io/blob/vnext-compose/compose/compose-file.md#upgrading
用 我的 LNMP 的示例
为例子,显然第一行的 version: '2'
需要换成 version: '3'