Docker 1.13 新增功能

原文来路:http://blog.lab99.org/post/docker-2016-11-14-what-is-new-in-docker-1-13.html

前言

2017年1月19日更新

Docker 1.13 在 2017 年 1 月 18 日宣布了。从 2016 年 7 月 29 日宣布 1.12 宣布以来,已过去 5 个多月了,对活泼的 Docker 社区来讲,已很久了,让我们看看都 1.13 都新增了甚么内容吧。

1.13一千四百多个 issue/pull request,五千多个 commits,是 Docker 历史上最高的宣布版本。这其实不是一个简略的小版本变更,里面有大批的更新。

在宣布以后,可以直接安装最新版本。在一个新的 Ubuntu / CentOS 体系中直接履行:

1
curl -fsSL https://get.docker.com/ | sh -s -- --mirror AzureChinaCloud

Top 10 新增功效

  • 1、正式支撑服务栈 docker stack
  • 2、正式支撑插件:docker plugin
  • 3、添加在 Swarm 集群环境下对密码、密钥管理的 secret 管理服务:docker secret
  • 4、增长 docker system 命令
  • 5、可以直接应用 docker-compose.yml 进行服务安排
  • 6、添加 docker service 转动升级出故障后回滚的功效
  • 7、增增强迫再宣布选项 docker service update --force
  • 8、许可 docker service create 映照宿主端口,而不是边界负载均衡网络端口
  • 9、许可 docker run 连入指定的 swarm mode 的 overlay 网络
  • 10、解决我国 GFW 墙掉 docker-engine apt/yum 源的问题

让我们来详细解读一下 1.13.0 新增功效 吧。

Docker 镜像构建

从已有镜像获得缓存

https://github.com/docker/docker/pull/26839

我们都知道应用 Dockerfile 构建镜像的时候,会充足应用分层存储的特征进行缓存,之前构建过的层,如果没有变更,那末会直接应用缓存的内容,避免没成心义的反复构建。不过应用缓存的条件条件是曾在本地构建过这个镜像。这在 CI 进行集群构建时是一个比拟麻烦的问题,由于构建义务可能会被分配到不同的机器上,而该机器没有构建过该镜像,因此缓存总是用不上,因此大批的时光糟蹋在了反复构建已构建过的层上了。

1.13 中,为 docker build 增长了一个新的参数 --cache-from,应用镜像中的 History 来断定该层是不是和之前的镜像一致,从而避免反复构建。

比如我们先下载获得作为缓存的镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ docker pull mongo:3.2
3.2: Pulling from library/mongo
386a066cd84a: Pull complete
524267bc200a: Pull complete
476d61c7c43a: Pull complete
0750d0e28b90: Pull complete
4bedd83d0855: Pull complete
b3b5d21a0eda: Pull complete
7354b6c26240: Pull complete
db792d386b51: Pull complete
a867bd77950c: Pull complete
Digest: sha256:532a19da83ee0e4e2a2ec6bc4212fc4af26357c040675d5c2629a4e4c4563cef
Status: Downloaded newer image for mongo:3.2

然后我们应用更新后的 Dockerfile 构建镜像时,如果加上 --cache-from mongo:3.2 后,会发明如果是已在 mongo:3.2 中存在并没有修正的层,就会用 mongo:3.2 中的该层做缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ docker build --cache-from mongo:3.2 -t mongo:3.2.1 .
Sending build context to Docker daemon 4.608 kB
Step 1/18 : FROM debian:jessie
---> 73e72bf822ca
Step 2/18 : RUN groupadd -r mongodb && useradd -r -g mongodb mongodb
---> Using cache
---> 0f6297900a5e
Step 3/18 : RUN apt-get update && apt-get install -y --no-install-recommends numactl && rm -rf /var/lib/apt/lists/*
---> Using cache
---> a465f2e906fc
Step 4/18 : ENV GOSU_VERSION 1.7
---> Using cache
---> 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

1
2
3
4
5
6
FROM busybox
RUNecho hello > /hello
RUN echo world >> /hello
RUN touch remove_me /remove_me
ENV HELLO world
RUN rm /remove_me

如果我们正常的构建的话,比如 docker build -t my-not-squash .,其 history 是这模样的:

1
2
3
4
5
6
7
8
9
$ docker history my-not-squash
IMAGE CREATED CREATED BY SIZE COMMENT
305297a526e2 About a minute ago /bin/sh -c rm /remove_me 0 B
60b8e896d443 About a minute ago /bin/sh -c #(nop) ENV HELLO=world 0 B
a21f3c75b6b0 About a minute ago /bin/sh -c touch remove_me /remove_me 0 B
038bca5b58cb About a minute ago /bin/sh -c echo world >> /hello 12 B
f81b1006f556 About a minute ago /bin/sh -c echo hello > /hello 6 B
e02e811dd08f 5 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0 B
<missing> 5 weeks ago /bin/sh -c #(nop) ADD file:ced3aa7577c8f97... 1.09 MB

而如果我们用 --squash 构建:

1
docker build -t mysquash --squash .

history 则是这模样:

1
2
3
4
5
6
7
8
9
10
$ docker history mysquash
IMAGE CREATED CREATED BY SIZE COMMENT
a557e397ff56 15 seconds ago 12 B merge sha256:305297a526e218e77f1b4b273442f8ac6283e2907e6513ff36e9048aa130dea6 to sha256:e02e811dd08fd49e7f6032625495118e63f597eb150403d02e3238af1df240ba
<missing> 15 seconds ago /bin/sh -c rm /remove_me 0 B
<missing> 15 seconds ago /bin/sh -c #(nop) ENV HELLO=world 0 B
<missing> 15 seconds ago /bin/sh -c touch remove_me /remove_me 0 B
<missing> 16 seconds ago /bin/sh -c echo world >> /hello 0 B
<missing> 16 seconds ago /bin/sh -c echo hello > /hello 0 B
<missing> 5 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0 B
<missing> 5 weeks ago /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 内容为:

1
2
FROM ubuntu
RUNcat /etc/hosts

内容很简略,就是看看构建时的 /etc/hosts 的内容是甚么。假定我们宿主的 /etc/hosts 中包括了一条 1.2.3.4example.com 的映照关系。

1
1.2.3.4  example.com

如果我们犹如以往,应用默许网络进行构建。那末成果会是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker build --no-cache -t build-network .
Sending build context to Docker daemon 2.048 kB
Step 1/2 : FROM ubuntu
---> 104bec311bcd
Step 2/2 : RUN cat /etc/hosts
---> Running in 42f0c014500f
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 2866979c4d77
---> 5f0b3dd56a32
Removing intermediate container 42f0c014500f
Successfully built 5f0b3dd56a32

可以注意到,这次构建所看到的是容器默许网络的 /etc/hosts,其内没有宿主上添加的条目 1.2.3.4 example.com

然后我们应用 docker build --network=host 来应用宿主网络构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ docker build --no-cache -t build-network --network=host .
Sending build context to Docker daemon 2.048 kB
Step 1/2 : FROM ubuntu
---> 104bec311bcd
Step 2/2 : RUN cat /etc/hosts
---> Running in 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.localdomain d1
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-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
Removing intermediate container b990c4e55424
Successfully built 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat Dockerfile
FROM ubuntu
RUN env
$ docker build -t myapp --build-arg VERSION=1.2.3 --no-cache .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu
---> 104bec311bcd
Step 2 : RUN env
---> Running in 81f4ba452a49
HOSTNAME=2866979c4d77
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
---> f78b4696a1ca
Removing intermediate container 81f4ba452a49
One or more build-args [VERSION] were not consumed, failing build.

其背后的思想是,如果 --build-arg 指定了,但是没用,那末极多是由于拼写毛病、或忘却了应当应用这个变量而涌现的问题。最初 docker build 对这类情形的处置,是直接报错退出,构建失败。

但是在上面的 CI 的案例中,--build-arg 只是定义一些可能用到的环境变量,其实不强迫应用,这类情形下,如果由于 Dockerfile 没有应用可能用到的变量就报错就有些过了。因此在 1.13 中,将其降为正告,其实不终止构建,只是提示用户有些变量未应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ docker build --no-cache -t myapp --build-arg VERSION=1.2.3 .
Sending build context to Docker daemon 2.048 kB
Step 1/2 : FROM ubuntu
---> 104bec311bcd
Step 2/2 : RUN env
---> Running in bb5e605cb4d0
HOSTNAME=2866979c4d77
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
---> 97207d784048
Removing intermediate container bb5e605cb4d0
[Warning] One or more build-args [VERSION] were not consumed
Successfully built 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,所以不会支撑阿里云))。应用方法以下,将原来官网安装命令:

1
curl -sSL https://get.docker.com/ | sh

调换为:

1
curl -sSL https://get.docker.com/ | sh -s -- --mirror AzureChinaCloud

增长更多的体系支撑

在这次宣布中,增长了 Ubuntu 16.10 的安装包,而且对 Ubuntu 体系增长了 PPC64LEs390x 构架的安装包。另外,还正式支撑了 VMWare Photon OS 体系RPM 安装包,和在 https://get.docker.com 的支撑。并且支撑了 Fedora 25,乃至开端支撑 arm64。同时也由于一些体系性命周期的停止,而被移除支撑,比如 Ubuntu 15.10Fedora 22 都不在支撑了。

网络

许可 docker run 连入指定的 swarm mode 的网络

https://github.com/docker/docker/pull/25962

在 Docker 1.12 宣布新的 Swarm Mode 以后,很多人都问过这样的问题,怎样能力让 docker run 的容器连入 Swarm Mode 服务的 overlay 网络中去?答案是不可以,由于 swarmoverlay 网络是为了 swarm mode service 预备的,相对更硬朗,而直接应用 docker run,会损坏了这里面的安全模型。

但是由于大家需求很多,因而供给了一种调和的方法。1.13 许可树立网络的时候,设定该网络为 attachable,许可以后的 docker run 的容器衔接到该网络上。

我们创立一个默许的、不准可以后 attach 的网络:

1
2
$ docker network create -d overlay mynet1
xmgoco2vfrtp0ggc5r0p5z4mg

然后再创立一个许可 attach 的网络,这里会应用 1.13 新参加的 --attachable 参数:

1
2
$ docker network create -d overlay --attachable mynet2
yvcyhoc6ni0436jux9azc4cjt

然后我们启动一个 web 服务,连入这两个网络:

1
2
3
4
5
6
$ docker service create \
--name web \
--network mynet1 \
--network mynet2 \
nginx
vv91wd7166y80lbl833rugl2z

现在我们用 docker run 启动一个容器连入第一个网络:

1
2
$ docker run -it --rm --network mynet1 busybox
docker: Error response from daemon: Could not attach to network mynet1: rpc error: code = 7 desc = network mynet1 not manually attachable.

由于 mynet1 不准可手动 attach 所以这里报错了。

在 1.12 的情形下,会报告该网络没法给 docker run 应用:

1
2
docker: Error response from daemon: swarm-scoped network (mynet1) is not compatible with `docker create` or `docker run`. This network can only be used by a docker service.
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: 支撑 tcpudp
  • mode: 支撑 ingresshost
  • target: 容器的端口号
  • published: 映照到宿主的端口号

比如,与 -p 8080:80 等效的 --publish 新格局选项为:

1
--publish protocol=tcp,mode=ingress,published=8080,target=80

固然我们可以持续应用 -p 8080:80,但是新的选项格局增长了更多的可能。比如,应用 1.13 开端参加的 host 映照模式:

1
2
3
[email protected]:~$ docker service create --name web \
--publish mode=host,published=80,target=80 \
nginx

运行胜利后,查看一下服务容器运行的节点:

1
2
3
4
5
6
7
8
[email protected]:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
ntjybj51u6zp44akeawuf3i05 d2 Ready Active
tp7icvjzvxla2n18j3nztgjz6 d3 Ready Active
vyf3mgcj3uonrnh5xxquasp38 * d1 Ready Active Leader
[email protected]:~$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
5tij5sjvfpsf web.1 nginx:latest d3 Running Running 5 minutes ago *:80->80/tcp

我们可以看到,集群有3个节点,而服务就一个副本,跑到了 d3 上。如果这是之前的应用边界负载均衡的网络 ingress 的话,那末我们拜访任意节点的 80 端口都会看到页面。

但是,host 模式不同,它只映照容器所在宿主的端口。因此,如果我们 curl d1 的话,应当甚么看不到网页,而 curl d3 的话就会看到页面:

1
2
[email protected]:~$ curl localhost
curl: (7) Failed to connect to localhost port 80: Connection refused
1
2
3
4
5
6
[email protected]:~$ curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to 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 将显示衔接到了这个网络的节点(宿主)有哪些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ 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"
}
]
}
]

从上面的例子可以看出,一共有两个宿主连入了这个 mynetoverlay 网络,分离为 138.197.213.116138.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 插件作为正式功效供给了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ docker plugin

Usage: docker plugin COMMAND

Manage plugins

Options:
--help Print usage

Commands:
create Create a plugin from a rootfs and config
disable Disable a plugin
enable Enable a plugin
inspect Display detailed information on one or more plugins
install Install a plugin
ls List plugins
push Push a plugin to a registry
rm Remove one or more plugins
set Change settings for a plugin

Run "docker plugin COMMAND --help" for more information on a command.

相比于 1.12 的试验版本而言,最主要的是增长了 docker plugin create 命令,可以指定一个包括有 config.json 文件和 rootfs 目录的目录来创立插件。

1
2
3
4
5
6
7
8
9
10
11
$ ls -ls /home/pluginDir

4 -rw-r--r-- 1 root root 431 Nov 7 01:40 config.json
0 drwxr-xr-x 19 root root 420 Nov 7 01:40 rootfs

$ docker plugin create plugin /home/pluginDir
plugin

$ docker plugin ls
ID NAME TAG DESCRIPTION ENABLED
672d8144ec02 plugin latest A sample plugin for Docker false

命令行

checkpoint 功效(试验功效)

https://github.com/docker/docker/pull/22049

checkpoint 功效可以将运行中的容器状况冻结并保留为文件,并在将来可以从文件加载恢复此时的运行状况。

预备工作

目前它所依附的是 criu 这个工具,因此在 Linux 上须要先安装这个工具。(目前尚没法在 Docker for Mac 中应用 docker/for-mac#1059)

如果未安装 criu 则会涌现以下报错:

1
Error response from daemon: Cannot checkpoint container myapp1: rpc error: code = 2 desc = exit status 1: "Unable to execute CRIU command: criu\n"

对 Ubuntu 体系,可以履行下面的命令安装 criu

1
$ sudo apt-get install -y criu

由于这个是试验功效,因此须要在 docker.serviceExecStart= 这行后面添加 --experimental 选项。其它试验功效也需如此配置。

然后不要忘了 systemctl daemon-reloadsystemctl restart docker

创立 Checkpoint 及恢复

履行 docker checkpoint create 便可认为容器创立 checkpoint

1
2
$ docker checkpoint create myapp1 checkpoint1
checkpoint1

可认为一个容器创立多个 checkpoint,每一个起不同的名字就是了。

然后可以用 docker checkpoint ls 来列出已创立的 checkpoint

1
2
3
$ docker checkpoint ls myapp1
CHECKPOINT NAME
checkpoint1

如果不加 --leave-running 参数的话,容器就会在创立完 checkpoint 就会被停止运行。

然后我们可以通过 docker start --checkpoint 来从某个 checkpoint 恢复运行:

1
$ docker start --checkpoint checkpoint1 myapp1

容器就会从 checkpoint1 这个点恢复并持续运行。

备份时可以用 --checkpoint-dir 指定具体的保留 checkpoint 的目录:

1
2
$ docker checkpoint create --checkpoint-dir $PWD/backup --leave-running myapp1 checkpoint1
checkpoint1

然后我们可以在 backup 中看到实际保留的文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ tree backup/
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 不显示容器名:

1
2
3
4
$ docker stats
CONTAINER CPU % MEM USAGE / 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

这让人基本没方法知道到底谁是谁。因而有各种变通的方法,比如:

1
$ docker stats $(docker ps --format={{.Names}})

但是这个列表是静态的,容器增长、删除都得重新运行这个命令。

1.13 开端,虽然照旧默许没有容器名,但是增长了 --format 参数可以自己设计输出格局:

1
2
3
4
$ docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"
NAME CPU % MEM USAGE / 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 的服务容器:

1
2
3
docker ps -f "is-task=true"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cdf0d35db1d3 [email protected]:33ff28a2763feccc1e1071a97960b7fef714d6e17e2d0ff573b74825d0049303 "nginx -g "daemon ..." 44 seconds ago 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 开端,将进行一些版本断定来进行处置,从而不会由于版本不一致而报错了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker version
Client:
Version: 1.13.0-dev
API version: 1.24 (downgraded from 1.25)
Go version: go1.7.3
Git commit: ec3a34b
Built: Wed Oct 26 00:54:51 2016
OS/Arch: linux/amd64

Server:
Version: 1.12.2
API version: 1.24
Go version: go1.6.3
Git commit: bb80604
Built: Tue Oct 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ docker service ps myservice
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE 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:[email protected]: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 命令来赞助体系管理上的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker system

Usage: docker system COMMAND

Manage Docker

Options:
--help Print usage

Commands:
df Show docker disk usage
events Get real time events from the server
info Display system-wide information
prune Remove unused data

Run "docker system COMMAND --help" for more information on a command.

docker system df 是显示磁盘应用情形:

1
2
3
4
5
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 3 3 700.3 MB 123 MB (17%)
Containers 3 3 15 B 0 B (0%)
Local Volumes 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 infodocker psdocker rmdocker 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

对在容器中应用 vihtop 之类工具的人来讲是比拟便利的。之前由于默许没有定义 TERM,这些须要终端页面布局的程序履行可能会不正常。比如:

1
2
$ htop
Error opening terminal: unknown.

现在直接为 docker exec -t 选项添加了继承自当前的 TERM 变量,可让这类工具可以正常应用。

Windows 内置的运行 Windows 程序的 Docker on Windows 的改良

  • #28415:支撑 Dockerfile 中的 USER 了;
  • #25736:支撑 syslog 日志体系;
  • #28189:支撑 fluentd 日志体系;
  • #28182:终究支撑 overlay 网络了;
  • #22208:支撑自定义网络指定静态IP了;
  • #23391:支撑存储层驱动的磁盘配额;
  • #25737:终究可以用 docker stats 了;
  • #25891:终究可以用 docker top 了;
  • #27838:Windows 终究可以用 Swarm Mode 跑集群了;

Swarm Mode

正式支撑 docker stack

1.12 中引入了二代 Swarm,也就是 Swarm Mode。由于基本理念变更很大,因此先行实现比拟基本的服务(service),但是针对应用/服务栈(stack)没有成熟,只是试行应用 .DAB 文件进行集群安排。但是 DABJSON 文件,而且撰写较为庞杂。相对大家已习惯的 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 格局。

荣幸的是 v3v2 格局差距不大。

  • 将一些过时的东西去掉,如 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" ????。

然后,服务里的 build 明显用不了了。那末改成 v3 格局,就应当是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
version: "3"
services:
nginx:
image: "twang2218/lnmp-nginx:v1.2"
ports:
- "80:80"
networks:
- frontend
deploy:
replicas: 2
depends_on:
- php
php:
image: "twang2218/lnmp-php:v1.2"
networks:
- frontend
- backend
environment:
MYSQL_PASSWORD: Passw0rd
deploy:
replicas: 4
depends_on:
- mysql
mysql:
image: mysql:5.7
volumes:
- mysql-data:/var/lib/mysql
environment:
TZ: "Asia/Shanghai"
MYSQL_ROOT_PASSWORD: Passw0rd
command: ["mysqld", "--character-set-server=utf8"]
networks:
- backend
volumes:
mysql-data:
networks:
frontend:
backend:

可以注意到,在 nginxphp 这两个服务中,增长了之前没有的 deploy 配置:

1
2
deploy:
replicas: 4

这是 v3 新增的安排相干的内容,在这里我指定了集群安排的副本数目。还有其他参数可以配置,具体请参考官方文档:

https://github.com/docker/docker.github.io/blob/vnext-compose/compose/compose-file.md#deploy

如果在 swarm 环境安排该服务栈的话,应用命令:

1
2
3
4
5
6
7
$ docker stack deploy --compose-file docker-compose.yml lnmp
Creating network lnmp_frontend
Creating network lnmp_backend
Creating network lnmp_default
Creating service lnmp_mysql
Creating service lnmp_nginx
Creating service lnmp_php

然后可以用 docker stack lsdocker stack ps 来查看服务栈状况:

1
2
3
4
5
6
7
8
9
10
11
12
$ docker stack ls
NAME SERVICES
lnmp 3
$ docker stack ps lnmp -f "desired-state=Running"
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
1x6qiieam21p lnmp_mysql.1 mysql:5.7 d1 Running Running 52 seconds ago
7irrc6v9xnbo lnmp_nginx.1 twang2218/lnmp-nginx:v1.2 d1 Running Running about a minute ago
2bq2kjm6xacn lnmp_php.1 twang2218/lnmp-php:v1.2 d1 Running Running about a minute ago
edp0ed1k6u9w lnmp_nginx.2 twang2218/lnmp-nginx:v1.2 d1 Running Running 58 seconds ago
1hlmkgtpf1pa lnmp_php.2 twang2218/lnmp-php:v1.2 d2 Running Running about a minute ago
0xjjyu3tyewp lnmp_php.3 twang2218/lnmp-php:v1.2 d2 Running Running about a minute ago
e9lgn25kyepx lnmp_php.4 twang2218/lnmp-php:v1.2 d1 Running Running about a minute ago

可以看到,由于配置文件中的 replicas 项目,主动安排了 2 个 nginx 服务容器副本,和 4 个 php 服务容器副本。

由于默许应用的就是 ingress 边界负载均衡网络映照的 80 端口,因此我们可以拜访任意节点来查看页面,享受二代 Swarm 给我们带来的利益。

删掉 stack,只须要简略地 docker stack rm lnmp 便可。不过须要注意的是,所有的命名卷不会被删除 (#29158),如需删除,须要手动的去各个容器所在节点去 docker volume rm 卷。

添加 secret 管理

https://github.com/docker/docker/pull/27794

从 1.13 开端,Docker 供给了集群环境的 secret 管理机制,从而可以更好地在集群环境中管理密码、密钥等敏感信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
docker secret --help

Usage: docker secret COMMAND

Manage Docker secrets

Options:
--help Print usage

Commands:
create Create a secret using stdin as content
inspect Inspect a secret
ls List secrets
rm Remove a secret

Run "docker secret COMMAND --help" for more information on a command.

docker secret create 从尺度输入读取信息,并且存入指定名称:

1
$ echo "MySuperSecretPassword" | docker secret create mysql_password

在将来启动服务的时候,便可以够通过 --secret 选项来指定须要应用哪些 secret

1
$  docker service create --name privateweb --secret mysql_password nginx

所指定的 secret 会以文件情势挂载于 /var/run/secrets/ 目录下:

1
2
3
4
5
[email protected]:/# ls -al /var/run/secrets/
total 8
drwxrwxrwt 2 root root 60 Dec 6 03:16 .
drwxr-xr-x 4 root root 4096 Dec 6 03:16 ..
-r--r--r-- 1 root root 22 Dec 6 03:16 mysql_password

secret 的权限是 444 因此容器中的非 root 用户也能够拜访其内容,读取所需的密码或密钥,这对非 root 用户启动的服务很主要。

1
2
[email protected]:/# cat /var/run/secrets/mysql_password
MySuperSecretPassword

添加负载均衡和DNS记载对新增的健康检讨的支撑

https://github.com/docker/docker/pull/27279

Docker 1.10 开端引入了 DNS 服务发明,然后在 1.11 进一步支撑了 DNS 负载均衡,1.12 开端引入了 VIP 负载均衡。而 1.12 同时还供给了 HEALTHCHECK 容器健康检讨的能力。但是服务发明和健康检讨这两个功效在 1.12 时并没有联合起来。因此可能会涌现,容器启动进程中,负载均衡就已将流量开端导流给这个容器了,从而致使升级进程中部份服务会拜访失败。

在 1.13 开端,将应用 Dockerfile 中定义的健康检讨功效,来检讨容器健康情形。如果容器还没有处于健康状况,所有的负载均衡和 DNS 服务发明将不会把流量转发给这个新启动的容器,它们会一直等到容器确切已可以供给服务时,再更新负载均衡和服务发明。

添加转动升级回滚的功效

https://github.com/docker/docker/pull/26421

当 Docker 1.12 供给了 Swarm Mode 的转动升级后,大家都很高兴,内置的转动升级让延续宣布变得更加轻松。1.12 供给了当服务升级涌现故障时,超太重试次数则停止升级的功效,这也很便利,避免让毛病的应用替换现有正常服务。但是有一个问题虽然提出,但并未能在 1.12 解决,就是出故障后回滚的问题。当产生故障后,如何让服务回滚到之前的版本?难道是再宣布一个更新,不过更新的是旧版本么?那末旧版本究竟是哪一个版本?这些问题在主动化处置的时候,是一些比拟麻烦的问题。

在 1.13 里,开端支撑 docker service update --rollback 功效,当产生故障停止后,可以由管理员履行该命令将服务回滚到之前的版本:

1
2
3
4
$ docker service update \
--rollback \
--update-delay 0s \
my_web

弥补了一些 docker service create 所缺失的参数

Docker 1.12 宣布 Swarm Mode 开端,docker service create 在某种水平上成了新的 docker run,但是相对 docker run 的定制参数而言,docker service create 要显得薄弱的多。固然,由于 docker service create 是面向集群环境,因此不可能把 docker run 上所有的参数都照搬过来,须要逐一甄别,有的须要重新实现,有的须要重新设计。在 Docker 1.13,随同着新增的一些参数,还有很多这类参数也被添加回来了。

添加命令 docker service logs 以查看服务日志(试验功效)

https://github.com/docker/docker/pull/28089

Swarm Mode 启动服务还有一个麻烦的问题就是查看日志很麻烦。在 docker-compose 中,可以直接 docker-compose logs <服务名> 便可查看日志,即便服务是跑在不同节点上,乃至是多个服务副本。但是 docker service 不支撑 logs 命令。因此,现在查看日志比拟麻烦,须要 docker service ps 查看各个容器都在哪些节点上,然后再一个个进去先 docker ps 找到容器 ID,然后在 docker logs <容器ID> 查看具体日志。非常繁琐。

从 1.13 开端,试验性的供给了 docker service logs 命令,用以到达相似的功效。不过这是试验功效,因此必需在启用试验模式后(dockerd --experimental),才可以应用。

增增强迫再宣布选项 docker service update --force

https://github.com/docker/docker/pull/27596

在制造环境应用 docker swarm mode 的进程中,极可能会碰到这样的问题,当一个节点挂掉了,修复重启该节点后,发明原来该节点跑的服务被调度到了别的节点上。这是正常的,swarm manager 的参与保证了服务的可用性。可是节点恢复后,除非运行新的服务,或某个别的节点挂掉,否则这个新修复的节点就一直闲着,由于服务副本数满足需求,所以 swarm manager 不会参与重新调度。

这个问题在集群扩容后,问题就更加显著,新扩容的节点,最初都是空闲的。在 1.12 唯一的解决方法就是我们改点儿甚么东西,从而触发 swarm 的升级行动。但是这明显不是好方法。

在 1.13,引入了 docker service update --force 功效,可以在服务未产生转变时,强迫触发再宣布的流程,也就是强迫重新 pull 该镜像、停止容器,重新调度运行容器。这样会让由于各种保护致使的集群负载不平衡的情形得到减缓,再次平衡集群。由于这是 docker service update 命令,因此也会遵守所指定的 --update-parallelism--update-delay 的设置,进行转动更新。

放弃

  • 放弃 docker daemon 命令,用 dockerd 取代。其实 1.12 已换了
  • 移除对 Ubuntu 15.10、Fedora 22 的支撑,由于这两个都 EOL 了。
  • 放弃 Dockerfile 中的 MAINTAINER 指令,如果须要可以用 LABEL maintainer=<...> 取代