docker 集群(swarm)与服务编排(service orchestration)入门
服务集群管理与编排是云应用的基础。企业对云的期待已仅是资源弹性、成本优势等,业务的稳定性与灵活性是新的目标。本文使用 docker swarm mode 官方资料(略有调整),以案例体验为中心,介绍服务管理技术核心技术,包括:建立集群、部署服务、热按需部署、热更新、撤换节点、负载均衡等企业应用关切的需求,初步展现“Build, Ship and Run Any App, OnCloudy”。
1、概述
2016年初,docker 发布 V1.12 版本,它集成了 docker swarm 产品1,交付了服务编排(service orchestration)功能,直接引发了与 Google 的 K8s 大战23。作为企业云服务市场最重要产品之一,直接关系市场份额,重要性不言而喻。
为什么这么重要,做一点程序体验一下,总比吃瓜群众“听谣传谣”好。docker 官方文档列了十条重要的特性4,且官方号称原生并宣布在AWS上大规模测试表明比友商产品快若干倍5,大家自己翻译了就知道 google 为什么急了,“不给活路”阿!。本文以体验服务编排为先,原理就暂时略了。
2、概念、与环境准备
2.1 概念
一台或以上安装 docker 引擎 PC 或 虚拟机,它们组成一个集群(swarm)。
节点(node)是加入集群的机器。节点分为管理节点(manage node)和工作节点(worker node)。管理节点起协调作用,将任务(tasks)分配给工作节点。
服务(service)是运行于节点的容器,按配置数量自动分布的工作节点上,每个服务可执行若干任务。任务(task)由管理服务器分发到其中一个服务,服务执行为原子(atomic)操作,要么成功要么失败。
负载均衡(Load balancing)分为入口(ingress)负载均衡模式和内部(internal)负载均衡模式。
2.2 环境准备
三台 PC 或 虚拟机。官方要求:
- three networked host machines
- Docker Engine 1.12 or later installed
- the IP address of the manager machine
- open ports between the hosts
友情提示:三台机器建议都是新装系统,同一版本 docker 引擎。
检查设置:
- ssh 所有 VM
- VM 相互 ping 通
swarm 需要的网络端口是:
- TCP port 2377 集群管理通讯
- TCP and UDP port 7946 节点间通讯
- TCP and UDP port 4789 for overlay network traffic
3、集群初步体验
本部分参考文档6
3.1 创建集群
1、ssh 到 manager ,或 manager 是图形界面主机:
$ ssh root@192.168.56.100
2、创建 swarm 。执行
$ docker swarm init --advertise-addr 192.168.56.100
输出(请拷贝下来):
Swarm initialized: current node (avab30mxipj04s0rcqz9a9wyz) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-3fi89zq1yqz85t6kjdl33p034y0mkrxozwj3q6hmkec72t1bp5-2ab8ezanlqgzv95ukjssip5fz \
192.168.56.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
3、检查结果
$ docker info
找到:
Swarm: active
NodeID: dxn1zf6l61qsb1josjja83ngz
Is Manager: true
Managers: 1
Nodes: 1
...
4、检查节点
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
avab30mxipj04s0rcqz9a9wyz * contos1 Ready Active Leader
有一个 leader 管理者
3.2 添加节点
1、 ssh 到工作节点
$ ssh root@192.168.56.101
2、粘贴刚才记录的指令加入一个worker
$ docker swarm join \
--token SWMTKN-1-3fi89zq1yqz85t6kjdl33p034y0mkrxozwj3q6hmkec72t1bp5-2ab8ezanlqgzv95ukjssip5fz \
192.168.56.100:2377
系统反馈: This node joined a swarm as a worker.
如果你忘了添加 worker 节点命令,在 mananger 上输入 docker swarm join-token worker
3、如步骤 1-2 将 worker2 加入 swarm
4、在 manager 上检查
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
187iti8crczyi3d2yozofem22 worker2 Ready Active
1sp9df168rav5sb4qpglu1g4k worker1 Ready Active
8vv96sxi1j35ur7zresezusee * manager Ready Active Leader
3.3 部署服务
在 manager 上下载 alpine 镜像:
$ docker pull alpine
在 manager 上创建服务。
$ docker service create --replicas 5 --name helloworld alpine /bin/sh -c "ping 192.168.56.1"
其中:
- –replicas 5 :创建 5 个服务实例(容器)
- –name helloworld alpine :使用 alpine(5M 大小 OS),服务名称 helloworld
- /bin/sh -c “ping 192.168.56.1” :执行 shell 命令 ping 主机
使用 docker service ls
不断检查服务,看到5个服务逐步启动。
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
csdkmie5o2h5 helloworld 1/5 alpine /bin/sh -c ping 192.168.56.1
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
csdkmie5o2h5 helloworld 3/5 alpine /bin/sh -c ping 192.168.56.1
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
csdkmie5o2h5 helloworld 5/5 alpine /bin/sh -c ping 192.168.56.1
3.4 管理服务
1、查看服务概况
$ docker service inspect --pretty helloworld
ID: csdkmie5o2h5b5sya1zi44ae8
Name: helloworld
Mode: Replicated
Replicas: 5
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
ContainerSpec:
Image: alpine
Args: /bin/sh -c ping 192.168.56.1
不使用选项 --pretty
则返回 json 格式。
2、查看服务在 swarm 中分布
$ docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
2rr24m2eq584lrn1otqeg3p3n helloworld.1 alpine worker1 Running Running 16 minutes ago
8pyvlmwwl43orqkdxstv90ixe \_ helloworld.1 alpine worker2 Shutdown Rejected 17 minutes ago "No such image: alpine:latest"
bq9sq5rhcjce2o7vvgczl3jwc helloworld.2 alpine manager Running Running 18 minutes ago
f0znv54oif1llkpsh1l97dmw4 helloworld.3 alpine manager Running Running 17 minutes ago
eb3btpp1o639yh4pk8o88j6ao \_ helloworld.3 alpine worker1 Shutdown Rejected 17 minutes ago "No such image: alpine:latest"
e9no3prou4xdyl342x5v2p19l helloworld.4 alpine worker2 Running Running 17 minutes ago
c8fewl748f0bg3970im2wxck1 \_ helloworld.4 alpine worker1 Shutdown Rejected 17 minutes ago "No such image: alpine:latest"
eh2fcz28lyx7e2cv6by9o3y4l helloworld.5 alpine worker1 Running Running 16 minutes ago
b3bti3w1v8wif2vi3ytl5lu6c \_ helloworld.5 alpine worker2 Shutdown Rejected 17 minutes ago "No such image: alpine:latest"
这里看出,五个服务分布在不同的节点上。由于网络问题,在 worker 1 和 worker 2 上下载 alpine 镜像时超时,导致重新启动服务。建立私有镜像仓库很重要
3.5 按需配置服务(scale service)
在 manager 上:
$ docker service scale helloworld=3
神奇的时刻,看到了!!!
$ docker service ps helloworld
当然,你也可以在不同机器上使用 docker ps
看每个机器上的容器(服务)
3.6 服务热更新(rolling updates)
1、在每台机器上,新建 Dockerfile 升级一次 alpine
$ tee Dockerfile <<-'EOF'
FROM alpine
ADD . /home
EOF
然后 bulid 版本 your/alpine:up
$ docker build . -t your/alpine:up
检查、测试以下新版本:
$ docker images
$ docker run -it --rm your/alpine:up sh
2、升级 helloworld 服务
$ docker service update --image your/alpine:up helloworld
检查:
$ docker service inspect --pretty helloworld
要点看 Update status: 小结
- 查看服务分布
$ docker service ps helloworld
服务升级完成,旧服务都下线了。
3.7 关闭/撤出节点(drain node)
$ docker node update --availability drain worker1
检查关闭情况
$ docker node inspect --pretty worker1
... ...
Status:
State: Ready
Availability: Drain
... ...
查看服务分布,docker service ps helloworld
恢复节点
$ docker node update --availability active worker1
3.8 删除服务
$ docker service rm helloworld
检查:
$ docker service ps
$ docker ps
4、 负载均衡网(swarm routing mesh)
本部分文档7
4.1 nginx 镜像下载
将 nginx 镜像下载到每个机器
4.2 发布服务端口并启动
执行以下语句,创建了 my-web 服务,启动了 2 个 nginx 服务实例。服务对外端口 8080。执行之前用 docker images
检查镜像全称。本案例中是:myregistrydomain.com:5000/nginx
自动下载很慢
$ docker service create \
--name my-web \
--publish 8080:80 \
--replicas 2 \
myregistrydomain.com:5000/nginx
由于镜像已下载,启动很快:
$ docker service ps my-web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
4o8h6wksvpuikv7rc0mnllugu my-web.1 myregistrydomain.com:5000/nginx worker1 Running Running about a minute ago
0n3pmx03tlyphynzygvmqsjij my-web.2 myregistrydomain.com:5000/nginx worker2 Running Running about a minute ago
4.3 访问服务
在任意可以访问集群的机器上输入:
$ curl http://192.168.56.100:8080
$ curl http://192.168.56.101:8080
$ curl http://192.168.56.102:8080
发现访问集群任意机器都得到正确的结果,而我们只有 2 个实例。
docker 官方入口路由(ingress-routing)示意图:
4.4 使用外部负载均衡
上述案例中,集群内部负载均衡是非常好的。但是,如果关闭一个节点,例如:
docker node update --availability drain worker1
这时,尽管另一台机器启动了新服务实例,但是, worker1 对应端口就无法访问(curl 不可以,但浏览器可以,也许是缓存原因)。目前,docker官方给的方案是采用 HAProxy 做外部负载均衡。 HAProxy 配置如下:
global
log /dev/log local0
log /dev/log local1 notice
...snip...
# Configure HAProxy to listen on port 80
frontend http_front
bind *:80
stats uri /haproxy?stats
default_backend http_back
# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
balance roundrobin
server node1 192.168.99.100:8080 check
server node2 192.168.99.101:8080 check
server node3 192.168.99.102:8080 check
5、小结:
我们初步介绍了 docker swarm 在满足“热按需部署、热更新、撤换节点、负载均衡”等企业需求方面的应用,配合现有 HTTP API 网关、负载均衡服务器、服务发现技术,可以满足企业级别应用。
实验过程中,小BUG是很多的,在一周内 docker 引擎从 V1.13 变成 V1.15。产品向下兼容似乎没有,新东西是好,但有待继续完善。
docker 涉及三类命令:
- docker swarm,集群的创建,工作节点、管理节点的加入
- docker node,节点管理
- docker service,服务管理
- Docker 1.12: Now with Built-in Orchestration! https://blog.docker.com/2016/06/docker-1-12-built-in-orchestration/ ↩
- 容器,你还能只用Docker吗? http://www.shbear.com/2/lib/201612/15/20161215060.htm ↩
- 编排管理成容器云关键,Kubernetes和Swarm该选谁? http://ec.ctiforum.com/jishu/qiye/qiyetongxinjishu/yunjisuan/jishudongtai/498049.html ↩
- Swarm mode overview https://docs.docker.com/engine/swarm/ ↩
- Docker And K8S https://www.docker.com/cp/docker-and-k8s ↩
- Swarm mode overview https://docs.docker.com/engine/swarm/ ↩
- Use swarm mode routing mesh https://docs.docker.com/engine/swarm/ingress/ ↩