SWARM大法好——Docker1.12 引擎使用体验

背景

凭借敏捷开发部署理念的推行,相信对于很多人来说docker这项容器技术已经并不陌生,Docker 1.12引擎发布了快两个月,新引擎中包含了许多特性。诸如: Swarm模式,容器集群的健康检查,节点的身份加密,docker Service API调用,容器启动的过滤匹配方式(constraint), docker的内建路由,以及支持在多平台系统上运行docker(MAC、Windows、AWS、AZURE),以及一些插件升级等等. 特性之多,就连Docker 自己的产品经理也表示这次的新版本可能是公司有史以来变化最大的一次产品发布。

很长一段时间里,docker在集群模式的管理上一直广受外界诟病。Docker服务自身只能在单台host上进行操作,官方并没有真正意义上的集群管理方案。直到现在1.12的出现, 引擎在多主机、多容器的集群管理上才有了进一步的改进和完善,版本自身内嵌了swarm mode集群管理模式。


本文主要是介绍一下swarm 集群管理模式的新特性,以及如何该模式下如何实现集群的搭建和服务部署。

Swarm cluster 模式新特性介绍

1. 批量创建服务

1.12引擎中多了docker service命令,和之前的docker run命令类似,但不同的是它能同时对多主机中的容器进行管理操作。下面就以1台manager节点,5台worker节点的swarm集群来阐述这些特性。

首先看下容器的创建:

$ docker network create -d overlay mynet

$ docker service create –replicas 3 –name frontend –network mynet –publish 80:80/tcp frontend_image:latest

$ docker service create –name redis –network mynet redis:latest

建立容器之前先创建一个overlay的网络,用来保证在不同主机上的容器网络互通的网络模式,后面两条命令用来在同一个名叫mynet的overlay网络里新建三个相同的web容器副本,和一个 redis副本,并且每个web容器都提供统一的端口映射关系。就像这样:

2. 强大的集群的容错性

既然是集群,当然难免会出现某几个节点故障的情况:

当三个web副本中的其中两台web节点宕机后,cluster会根据自己的服务注册发现机制,以及之前设定的值–replicas 3,在集群中剩余的空闲节点上,重新拉起两个web副本。不难看出,docker service其实不仅仅是批量启动服务这么简单,而是在集群中定义了一种状态。Cluster会持续检测服务的健康状态并维护集群的高可用性。

新节点的分布示意图如下:

3. 服务节点的可扩展性

Swarm Cluster不光只是提供了优秀的高可用性,同时也提供了节点弹性扩展的功能。当web这个容器组想动态扩展至六个节点个数时,只需执行$ docker service scale frontend=6就能立刻复制出三个新的副本出来。

眼尖的朋友可能注意到了,所有扩展出来的新web副本节点都run在原先的web节点下面,如果有需求想在每台节点上都run一个相同的副本有没有办法呢?答案也是肯定的:

$ docker service create –mode=global –name extend_frontend frontend_image:latest

一条命令分分钟搞定!

4. 调度机制

Docker1.12的调度机制也值得一提。

所谓的调度其主要功能是cluster的server端去选择在哪个服务器节点上创建并启动一个容器实例的动作。它是由一个装箱算法和过滤器组合而成。每次通过过滤器(constraint)启动容器的时候,swarm cluster 都会调用调度机制筛选出匹配约束条件的服务器,并在这上面运行容器。

还是拿刚刚那个例子来说,再加上–constraint参数,就能指定容器只run在服务器硬盘是SSD的节点上(前提是加入到cluster的节点,在启动daemon时,本身需要加上参数 --label com.example.storage=”ssd”):

$ docker service create –replicas 3 –name frontend –network mynet –publish 80:80/tcp –constraint engine.labels.com.example.storage=ssd frontend_image:lastest

搭建一个swarm集群

有了以上这些介绍,我们对swarm cluster 的一些新特性应该有了初步的了解 ,下面再看一个模拟网站rolling_update的实例,相信这也是许多平时做版本发布的devops们真正想要看到的东西。

1. 搭建一个swarm集群

准备三台机器

Node1:192.168.133.129

Node2:192.168.133.137

Node3:192.168.133.139

在构建一个swarm cluster前,需在cluster节点的防火墙上放行2377/tcp(cluster 管理端口)、7946/udp(节点间通信端口)、4789/udp(overlay 网络端口)

首先在node1上运行 $docker swarm init 去启动一台cluster manager节点,然后在任意需要添加进集群的节点上运行docker swarm join –token *** 192.168.133.129:2377 就能将节点加入到cluser(加入到集群里的节点身份可在后面自由设置成worker或manager)。现在swarm cluster的节点就像下面的图一样,箱子都准备好了,就差货物往里面装了。

通过$docker node ls能看到所有swarm节点的运行状态:

P.S.Swarm cluster的创建过程包含以下三个步骤:

  1. 发现Docker集群中的各个节点,收集节点状态、角色信息,并监视节点状态的变化

  2. 初始化内部调度(scheduler)模块

  3. 创建并启动API监听服务模块

一旦创建好这个cluster,就可以用命令docker service批量对集群内的容器进行操作。搭建cluster只有两步,是不是非常酷?

2. 制作一个演示用的demo镜像

镜像中存放一个python写的简单的http web服务:env.py,目的是显示容器的containerID:

from flask import Flask

import os

app = Flask(__name__)

@app.route("/")

def env():

return os.environ["HOSTNAME"]

app.run(host="0.0.0.0")

3. 用swarm mode创建service task

有了这个镜像,然后通过docker service create命令去创建一个名叫test的task:

$ docker service create --name test -p 5000:5000 demo python env.py

用docker ps看一眼

欸?为什么没有起来呢?再用docker service ls 查看task的状态:

注意这个REPOLICAS的值,0/1说明docker create 已经创建了一个副本但是还没有起来,稍等一会再运行一遍命令:

补充:

一些情况下已经运行了容器,可是运行docker ps在本机还是看不到容器,为什么呢?

其实,docker 会根据当前每个swarm节点的负载判断,在负载最优的节点运行这个task任务,用docker service ps + taskID 可以看到任务运行在哪个节点上。

好了container已经起来了并且运行在node1上

用浏览器打开地址能看到容器对应的ID:

4. 增加service节点

有了单个容器实例之后,下一步再尝试下动态扩展实例个数

$ docker service scale test=6

Node1:

Node2

Node3

一条命令让现在swarm cluster里三台节点,每台都运行了两个test副本实例。

此时你是不是已经留意到,一个天然的HA集群出现了。docker会把对每个host的http请求依据轮询算法,均匀地发送到每个task副本上。

5. 模拟其中一个swarm cluster节点离线的情况

正常来讲让一个swarm cluster中的一个node退出集群的方式,是在要推出的节点上运行$ docker swarm leave命令,但是为了让实验更疯狂,我在node3上直接stop docker的daemon

再去剩余两个节点上任意一个查看task状态:

原本在node3上运行的两个test任务:test3、test4,分别在node1和node2两台host上被来起来了。整个副本迁移的过程无需人工干预,迁移后原本的集群的load balance依旧好使!

评论列表
June 2017-06-19 14:50:46
在swarm模式下创建服务时,如果我想使用宿主机存储数据该怎么办?
hiya chen 2016-09-16 13:24:44
y有微信群吗?
ccie 2016-09-15 16:09:56
新版本集群 Swarm 的功能介绍不错。还有一个问题,集群里面的三个 worker 节点有三个 IP 地址:
Node1:192.168.133.129
Node2:192.168.133.137
Node3:192.168.133.139
实验里面对外部提供的 test 服务,是通过哪个 IP 地址来进行访问的? 关闭的 test3、 test4 容器的服务地址是共享的同一个,还是各自有自己的IP地址?
1/ 1