docker 集群(swarm)与服务编排(service orchestration)入门

时间:2022-04-24 17:38:09

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: 小结
  1. 查看服务分布
$ 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 镜像下载

搭建 Docker 私有仓库 Registry-v2

将 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)示意图:

docker 集群(swarm)与服务编排(service orchestration)入门

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,服务管理

  1. Docker 1.12: Now with Built-in Orchestration! https://blog.docker.com/2016/06/docker-1-12-built-in-orchestration/
  2. 容器,你还能只用Docker吗? http://www.shbear.com/2/lib/201612/15/20161215060.htm
  3. 编排管理成容器云关键,Kubernetes和Swarm该选谁? http://ec.ctiforum.com/jishu/qiye/qiyetongxinjishu/yunjisuan/jishudongtai/498049.html
  4. Swarm mode overview https://docs.docker.com/engine/swarm/
  5. Docker And K8S https://www.docker.com/cp/docker-and-k8s
  6. Swarm mode overview https://docs.docker.com/engine/swarm/
  7. Use swarm mode routing mesh https://docs.docker.com/engine/swarm/ingress/