在DockerCon 2016上宣布的内置编排能力该如何玩?
Docker公司在DockerCon 2016上宣布Docker将提供内置的编排(Orchestration)能力,从而能使得Docker Engine原生支持集群管理和服务生命周期管理。这个宣布对每个Docker开发者和厂商都有重要影响,也会左右现有Docker编排市场格局。
昨天才从DockerCon大会归来,阿里云容器服务团队将为大家奉献一系列深入学习的文章来帮助大家了解Docker技术发展的最新动态。
在DockerCon第一天的Keynote里面,Docker CTO Solomon Hykes宣布Docker将提供内置的编排(Orchestration)能力,从而能使得Docker Engine原生支持集群管理和服务生命周期管理。Solomon把这称为自Docker发布以来最大的一次改变。这个宣布对每个Docker开发者和厂商都有重要影响,也会左右现有Docker编排市场格局。
Docker Swarm模式简介
在Docker 1.12中,其Docker内置编排包含以下功能
提供了Swarm模式
将一组Docker Engine构成一个集群统一管理、调度
集群环境内置Raft一致性协议,避免单点故障问题,也无需额外的类似于 Etcd/Consul/Zookeeper 的外部发现服务
自动选举出leader进行集群管理
节点身份加密 (Cryptographic node identity)
Docker节点加入集群时自动完成相应的安全配置
节点之间点对点通信通过TLS证书认证,同时支持TLS证书定时刷新
提供Service概念支持
提供服务状态的持续逼近
支持服务的不中断更新(rolling update)和其他发布策略
自定义服务的健康检查规则
当节点失效时,服务自动重新调度
内置路由机制(Routing Mesh)
通过 IPVS 实现内核空间的4层路由,实现可靠的负载均衡。
可以从任意节点访问集群中服务暴露出的服务端口。
Docker Swarm模式架构如下:
集群中的节点可以包括worker和manager两类不同的角色,它们之间可以通过promote和demote操作互相切换。在manager节点上可以进行集群的管理操作,其状态通过一个内部的Raft一致性协议实现进行同步和持久化。manager节点中会选举出一个leader来进行调度和编排。
Swarm模式支持新的Service/Task来进行容器的调度和执行。一个服务(service)描述了任务(task)如何在集群worker节点上的调度执行。Swarm支持自我复制服务(replicated service 指定副本数目)或全局服务(global service 在每个worker上执行)。一个任务(task)是原子化执行和调度单元,对应着Docker容器和其运行配置。manager节点负责根据service描述调度task到特定worker节点执行。同时manager会根据任务当前状态,自动逼近服务指定目标状态,实现最终一致性。
阿里云上创建Docker Swarm模式集群
为了在第一时间尝鲜体验一下Docker内置的编排能力,我们先在阿里云上操练起来。
Docker Machine是一个可以帮助开发者在自己本地电脑或云服务中创建Docker运行环境的的应用工具。使用它的阿里云ECS Driver,可以大大简化在阿里云环境下Docker运行环境的部署。
Docker Machine和阿里云ECS Driver的安装步骤如下:
https://help.aliyun.com/document_detail/26088.html
下面,我们来创建一个包含3个ECS节点的Docker集群,首先配置一些共用的环境变量
export DEBUG=true export ECS_ACCESS_KEY_ID=<您的Access Key ID>export ECS_ACCESS_KEY_SECRET=<您的Access Key Secret>export ECS_REGION=cn-beijingexport ECS_ZONE=cn-beijing-bexport ECS_SSH_PASSWORD=<ECS实例SSH密码>#export MACHINE_DOCKER_INSTALL_URL=https://test.docker.comexport MACHINE_DOCKER_INSTALL_URL=http://aliyungo.oss-cn-hangzhou.aliyuncs.com/test-intranetexport ENGINE_REGISTRY_MIRROR=https://6udu7vtl.mirror.aliyuncs.com
注:
您可以在ECS_REGION,ECS_ZONE环境变量中填写目标的Region和Zone
您的专属Docker Registry Mirror可以从
https://cr.console.aliyun.com/#/docker/booster获得
然后我们可以通过如下命令在阿里云上创建3个ECS节点,并安装最新的测试版Docker Engine
docker-machine create -d aliyunecs node1
docker-machine create -d aliyunecs node2
docker-machine create -d aliyunecs node3
我们可以通过如下命令登录到node1
docker-machine ssh node1
执行如下命令显示当前内网地址,并利用docker swarm命令集群和注册manager节点
ip addr show eth0
docker swarm initexit
屏幕输出如下
root@node1:~# ip addr show eth02: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3e:00:04:ea brd ff:ff:ff:ff:ff:ff inet 10.44.202.234/21 brd 10.44.207.255 scope global eth0
valid_lft forever preferred_lft forever
root@node1:~# docker swarm initSwarm initialized: current node (3bj13a80xdltndle20c6rzc55) is now a manager.
之后我们把node2和node3作为worker加入Docker Swarm集群,执行下面命令时要注意需要把MANAGER_IP替换为上面命令返回的"eth0"IP地址
docker-machine ssh node2 docker swarm join <MANAGER_IP>:2377
docker-machine ssh node3 docker swarm join <MANAGER_IP>:2377
这样整个Docker集群就已经创建成功了,是不是非常简单 :-)
下面我们将体验Docker的Swarm模式,如需进一步了解请参考Docker Swarm模式官方文档
管理集群节点
我们利用 docker-machine ssh node1命令登入node1节点,并用下面的命令查看集群节点
root@node1:~# docker node ls
ID NAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS
3bj13a80xdltndle20c6rzc55 * node1 Accepted Ready Active Leader
b5x26rpfbqhg18nn11arkxzdz node3 Accepted Ready Active
cqgyh1yv0rn6llckzi1hv84fa node2 Accepted Ready Active
部署管理
下面我们部署一个nginx服务到集群上
root@node1:~# docker service create --name nginx nginx:1.119wxstra98838kc0hbeeq0hliz
然后我们检查nginx服务状态和它包含的tasks信息
root@node1:~# docker service lsID NAME REPLICAS IMAGE COMMAND9wxstra98838 nginx 1/1 nginx:1.11 root@node1:~# docker service tasks nginxID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE86lnce96t55dempycyp4si0gm nginx.1 nginx nginx:1.11 Running 7 minutes Running node1
我们可以伸缩nginx服务到三个任务
root@node1:~# docker service scale nginx=3nginx scaled to 3
更新服务
下面我们部署一个redis服务到Swarm集群,采用redis:3.0.6镜像,其初始包含3个任务。我们还定义了服务的更新策略:每次更新1个Redis容器,更新延迟10s
root@node1:~# docker service create --replicas 3 --name redis --update-delay 10s --update-parallelism 1 redis:3.0.65dz319epmfflcmfoftn4w1uga
查看Service列表,并检查redis服务细节
root@node1:~# docker service inspect redis --prettyID: 5dz319epmfflcmfoftn4w1ugaName: redisMode: Replicated
Replicas: 3Placement:
Strategy: SpreadUpdateConfig:
Parallelism: 1
Delay: 10sContainerSpec:
Image: redis:3.0.6Resources:Reservations:Limits:
下面,我们可以更新redis服务的Docker镜像到redis:3.0.7。Swarm manager将依照之前的更新策略来更新服务:
root@node1:~# docker service update --image redis:3.0.7 redisredis
再次检查redis服务细节,和相应的task信息
root@node1:~# docker service inspect --pretty redisID: 5dz319epmfflcmfoftn4w1uga
Name: redis
Mode: Replicated
Replicas: 3Placement:
Strategy: Spread
UpdateConfig:
Parallelism: 1
Delay: 10s
ContainerSpec:
Image: redis:3.0.7Resources:
Reservations:
Limits:
root@node1:~# docker service tasks redisID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE
cjlgmwkzb092wor9nh2yinlvv redis.1 redis redis:3.0.7 Running 28 seconds Running node188mklyn50dun7telyn97m5grm redis.2 redis redis:3.0.7 Running 3 seconds Running node36l612n075rr95ditjdl6x2pe7 redis.3 redis redis:3.0.7 Running 15 seconds Running node3
集群可用性验证
我们可以利用下面命令把node2,node3也设置为集群的manager节点
root@node1:~# docker node promote node2Node node2 promoted to a manager in the swarm.
root@node1:~# docker node lsID NAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS3bj13a80xdltndle20c6rzc55 * node1 Accepted Ready Active Leader
b5x26rpfbqhg18nn11arkxzdz node3 Accepted Ready Active
cqgyh1yv0rn6llckzi1hv84fa node2 Accepted Ready Active Reachable
root@node1:~# docker node promote node3Node node3 promoted to a manager in the swarm.
root@node1:~# docker node lsID NAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS3bj13a80xdltndle20c6rzc55 * node1 Accepted Ready Active Leader
b5x26rpfbqhg18nn11arkxzdz node3 Accepted Ready Active
cqgyh1yv0rn6llckzi1hv84fa node2 Accepted Ready Active Reachable
当我们重启Docker服务来模拟Docker Engine故障时,我们可以发现leader已经被自动切换到其他节点上
root@node1:~# service docker restart
docker stop/waiting
docker start/running, process 7077root@node1:~# docker node ls
ID NAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS
3bj13a80xdltndle20c6rzc55 * node1 Accepted Ready Active Reachable
b5x26rpfbqhg18nn11arkxzdz node3 Accepted Ready Active Leader
cqgyh1yv0rn6llckzi1hv84fa node2 Accepted Ready Active Reachable
现在我们来模拟node3下线维护过程,现在node3上运行的节点有如下任务
root@node1:~# docker node tasks node3ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE88mklyn50dun7telyn97m5grm redis.2 redis redis:3.0.7 Running 5 minutes Running node36l612n075rr95ditjdl6x2pe7 redis.3 redis redis:3.0.7 Running 6 minutes Running node3
emxsw4qosd6qkahpyrq8hpx3n nginx.3 nginx nginx:1.11 Running 9 minutes Running node3
我们将node3设置为排水模式,让其下线并将其上运行中容器自动迁移到其他活跃节点
root@node1:~# docker node update --availability drain node3node3
我们可以看到所有的容器已经迁移到node1和node2上,
root@node1:~# docker node tasks node1ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE1pm1dyxuwrh57kysyh7j5s48w redis.1 redis redis:3.0.7 Running 5 minutes Running node17gstf6nn9ydwm8knbjwb7c0ag nginx.2 nginx nginx:1.11 Running 5 minutes Running node146l5e1zmdpbwn2ptcfqtrdpue redis.3 redis redis:3.0.7 Running 9 seconds Running node1
root@node1:~# docker node tasks node2ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE5tn4bgod6a76k4bjl886vprrb nginx.1 nginx nginx:1.11 Running 11 minutes Running node23lj30togrr1j19rya5wc9bxi7 redis.2 redis redis:3.0.7 Running 12 seconds Running node21hnvm1kuji5auegexd2u7lm4x nginx.3 nginx nginx:1.11 Running 12 seconds Running node2
root@node1:~# docker node tasks node3ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE
我们可以把node3再修改成为活跃(active)状态,之后系统可以在node3上创建或重新调度容器。
root@node1:~# docker node update --availability active node3node3
下面我们将测试当一个节点失效时集群的行为。
利用docker-machine我们可以对指定节点强制关机,打开另外一个终端窗口执行下面命令杀死node2节点
docker-machine kill node2
稍等一会儿,我们检查docker的节点和上面的任务状态
root@node1:~# docker node lsID NAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS3bj13a80xdltndle20c6rzc55 * node1 Accepted Ready Active Reachable
b5x26rpfbqhg18nn11arkxzdz node3 Accepted Ready Active Leader
cqgyh1yv0rn6llckzi1hv84fa node2 Accepted Down Active Reachable
root@node1:~# docker node tasks node1ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE1pm1dyxuwrh57kysyh7j5s48w redis.1 redis redis:3.0.7 Running 12 minutes Running node17gstf6nn9ydwm8knbjwb7c0ag nginx.2 nginx nginx:1.11 Running 12 minutes Running node146l5e1zmdpbwn2ptcfqtrdpue redis.3 redis redis:3.0.7 Running 7 minutes Running node1
root@node1:~# docker node tasks node3ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE
cb99d1ga8dsv2prwvsc3np1fq nginx.1 nginx nginx:1.11 Running 2 minutes Running node33r9hniyuq54j12mwtytm9x88k redis.2 redis redis:3.0.7 Running 2 minutes Running node39p9jik29urimlruo7alabfcmp nginx.3 nginx nginx:1.11 Running 2 minutes Running node3
我们可以发现这时候,node2节点是"Down"状态,并且所有容器已经被自动迁移到node1和node3之上。
总结
我们利用Docker Machine的ECS driver,可以方便地在阿里云上创建Docker环境。学习并体验了Docker在编排方面的最新特性:节点管理、服务管理和高可用性等。
注:目前,在本文所使用的Docker 1.12-rc2 版本中,内置路由机制还有一些问题。之后我们将根据最新进展更新本文。
客观地讲,Docker的Swarm模式确实极大简化了容器编排技术的部署和使用,这体现了Docker公司所强调的“democratize orchestration”的愿景,把容器编排变成为大众化的技术。但是这也会在某种程度上抑制技术的多样性,其他的编排技术的市场空间会受到很大影响。另外作为Docker内置编排方案的第一个版本,其还有很多不足和和可能变化的地方。在DockerCon上我们也和Docker的工程师探讨了是否能够提供扩展机制来定制不同的路由和发布策略等问题。我们期待Docker的进一步发展,同时也希望Docker社区能够更加多元化和健康发展。
阿里云容器服务完全兼容Docker原生的编排技术,目前支持Docker 1.11正式版本。它现在的容器化服务生命周期管理的方式和新的Swarm模式很接近。当Docker 1.12稳定版发布之后,我们会很快推出对新Swarm模式的支持。
更多深度技术内容,请关注云栖社区微信公众号:yunqiinsight。