Docker-Swarm速成

在生产环境使用swarm集群的注意事项

swarm集群的管理

https://docs.docker.com/engine/swarm/admin_guide/

swarm集群如何使用 docker-componse.yml 部署容器

如何操作

https://docs.docker.com/engine/swarm/stack-deploy/

docker stack 命令

https://docs.docker.com/engine/reference/commandline/stack/

如何编写支持 swarm 的 docker-componse.yml

https://docs.docker.com/compose/compose-file/compose-file-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
39
version: "3.9"
services:
db:
image: redis:3.0.5
deploy:
replicas: 6 # 启动实例数量
placement: # 配置容器实例位置------------
max_replicas_per_node: 2 # 每个节点最多运行容器实例数量
constraints: # 将容器分配到匹配标签的节点运行
- "node.role==manager"
- "engine.labels.operatingsystem==ubuntu 18.04"
preferences: # 将任务平均分配到不同类别的节点上
- spread: node.labels.zone
resources: # 资源限制------------
limits: # 占用上限
cpus: '0.50'
memory: 50M
reservations: # 启动占用
cpus: '0.25'
memory: 20M
restart_policy: # 重启策略------------
condition: on-failure # 发生失败时
delay: 5s # 重启时间间隔
max_attempts: 3 #最大尝试次数
window: 120s # 判断是否重启成功的等待时长
update_config: # 滚动更新的配置------------
parallelism: 2 # 同时更新的数量
delay: 10s # 每次更新间隔时间
monitor: 5s # 每次更新监控失败持续的时长
failure_action: 'pause' # 滚动更新出现错误时执行的操作: continue/rollback/pause
max_failure_ratio: # 允许的更新失败率
order: stop-first # 更新顺序 stop-first(旧任务在启动新任务之前停止)或start-first(新任务首先启动,运行中的任务会出现短暂重叠)
rollback_config: # 更新失败如何回滚------------
parallelism: 2 # 每次回滚的数量,如果为0则全部回滚
delay: 10s # 每次回滚间隔时间
monitor: 5s # 每次更新监控失败持续的时长
failure_action: 'pause' # 回滚出现错误时执行的操作: continue/rollback/pause
max_failure_ratio: # 允许的回滚失败率,默认为0
order: stop-first # 回滚顺序 stop-first(旧任务在启动新任务之前停止)或start-first(新任务首先启动,运行中的任务会出现短暂重叠)

docker-stack 不支持的docker-compose配置

  • build
  • cgroup_parent
  • container_name
  • devices
  • tmpfs
  • external_links
  • links
  • network_mode
  • restart
  • security_opt
  • userns_mode

节点管理

更多高级操作:

  • 给 Swarm 添加节点
  • 管理集群中的节点

创建一个新的 Manager Node

使用

docker swarm init 命令创建一个 Manager Node.

  • -advertise-addr 参数将 Manager Node 监听的IP设置为:

192.168.99.100.

注意,使用

  • -advertise-addr 默认监听的端口为
1
2377

swarm 中的其他 Node 必须能访问 Manager Node 的 IP.

输出包括将新节点加入 swarm 的命令。根据

  • -token 标志的值,节点将作为Master或Worker加入。
1
docker swarm init --advertise-addr ManagerIP地址

例:

1
2
3
4
5
6
7
8
root@u2004:/home/ubuntu# docker swarm init --advertise-addr 192.168.1.80
Swarm initialized: current node (9nxycsrinzgh5bgqwfus2ia8r) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-5qv7t73fvawvh795ckh3nxl9vnyo2hwwsqnnjwqyav3spj7ufu-1i7wir7oc3g9fh7yidg19i8p5 192.168.1.80:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

docker swarm join-token manager 命令用于获取添加新的 Manager Node 的命令参数

docker swarm join-token worker 命令用于获取添加新的 Worker Node 的命令参数

在生产环境 Manager Node 不推荐运行任何容器实例,但是 Swarm 调度器会分配给Manager Node,

因此我们可以通过 禁用节点 告诉 Swarm 调度器不要分配给 Manager Node 任何容器实例。

查看 swarm 当前状态

docker info

例:

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
root@u2004:/home/ubuntu# docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.6.3-docker)
scan: Docker Scan (Docker Inc., v0.9.0)
Server:
Swarm: active
NodeID: 9nxycsrinzgh5bgqwfus2ia8r
Is Manager: true
ClusterID: lu8frg6np6dmqf3bjr7jyl628
Managers: 1
Nodes: 1
Default Address Pool: 10.0.0.0/8
SubnetSize: 24
Data Path Port: 4789
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot Interval: 10000
Number of Old Snapshots to Retain: 0
Heartbeat Tick: 1
Election Tick: 10
Dispatcher:
Heartbeat Period: 5 seconds
CA Configuration:
Expiry Duration: 3 months
Force Rotate: 0
Autolock Managers: false
Root Rotation In Progress: false
Node Address: 192.168.1.80
Manager Addresses:
192.168.1.80:2377

查看节点列表

使用以下命令查看节点列表,节点

ID 旁边的 * 表示你当前已经连接到此节点

1
docker node ls

例:

1
2
3
root@u2004:/home/ubuntu# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
9nxycsrinzgh5bgqwfus2ia8r * u2004 Ready Active Leader 20.10.11

查看节点详细信息

使用以下命令查看节点的详情:

1
docker node inspect --pretty 节点名称

添加新的 Manager Node 到集群

在另一台机器运行 docker swarm join 命令加入已存在的集群中

1
root@u2004:/home/ubuntu# docker swarm join-token managerTo add a manager to this swarm, run the following command:    docker swarm join --token SWMTKN-1-5qv7t73fvawvh795ckh3nxl9vnyo2hwwsqnnjwqyav3spj7ufu-ca1v0jiu9xwb6o20dqqajl4n1 192.168.1.80:2377

Manager Node 必须是单数(Raft),生产环境推荐3台或5台作为 Manager Node

docker swarm join-token manager 命令用于获取添加新的 Manager Node 的命令参数

添加新的 Worker Node 到集群

在另一台机器运行

docker swarm join 命令加入已存在的集群中

1
docker swarm join --token SWMTKN-1-5qv7t73fvawvh795ckh3nxl9vnyo2hwwsqnnjwqyav3spj7ufu-1i7wir7oc3g9fh7yidg19i8p5 192.168.1.80:2377

docker swarm join-token worker 命令用于获取添加新的 Worker Node 的命令参数

禁用节点

在某些情况下我们想要将某个节点禁用或将节点中运行的容器清空,使用以下命令即可实现:

1
docker node update --availability drain 节点名称

被禁用的节点仍然存在集群中,只是不会被swarm调度运行容器实例

启用节点

禁用节点后使用以下命令即可启用节点:

1
docker node update --availability active 节点名称

更新节点

更新节点

1
docker node update --label-add foo --label-add bar=baz 节点名称

服务管理

更多高级操作:

https://docs.docker.com/engine/reference/commandline/service/

https://docs.docker.com/compose/compose-file/compose-file-v3/#placement

运行服务

连接到 Manager Node,使用

docker service create 命令创建服务.

例:

1
docker service create --replicas 1 --name helloworld alpine ping docker.com
  • -name 指定服务名称为 helloworld
  • -replicas 指定服务运行实例数量为 1
  • 参数 alpine 表示运行的镜像为 Alpine Linux
  • 参数 ping docker.com 表示在容器中执行的命令

查看运行的服务

在 Manager Node 运行此命令查看正在运行的服务列表:

1
docker service ls

例:

1
2
3
root@u2004:/home/ubuntu# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
jkj80hnr73rn helloworld replicated 1/1 alpine:latest

查看服务的详细信息

在 Manager Node 运行此命令查看服务的运行详情:

1
docker service inspect --pretty 服务名称

参数 --pretty 表示返回格式化后的详细信息,不加这个参数则打印 JSON 格式的信息

查看服务运行在那些节点

在 Manager Node 使用此命令查看服务都在那些节点运行:

1
docker service ps 服务名称

docker-swarm 中的服务实例由 swarm 调度。因此有部分服务的实例运行在 Manager Node 是正常表现。

伸缩服务

docker-swarm 支持对服务实例进行动态伸缩,使用以下命令即可实现:

1
docker service scale 服务名称=实例数量(最少为1)

例:

1
2
3
4
5
6
root@u2004:/home/ubuntu# docker service scale helloworld=2
helloworld scaled to 2
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged

删除服务

在 Manager Node 使用以下命令删除服务:

1
docker service rm 服务名称

注意,因为是集群的原因,集群中的Node将会存在延迟的情况,想确认服务是否被删除成功请使用 docker service ls 查看

滚动更新服务

创建服务

进入 Manager Node 创建一个redis服务用于演示滚动更新:

1
2
3
4
5
docker service create \
--replicas 3 \
--name redis \
--update-delay 10s \
redis:3.0.6

–update-dely 表示更新服务或服务集之间的时间延迟:1h10m3s,表示延迟1小时10分钟3秒。

调度器默认一次更新一个任务,可以通过 --update-parallelism 参数配置调度器同时更新服务数量。

默认情况下,当单个服务更新返回状态为 RUNNING,调度器会让另一个服务更新,直到所有服务都更新完成。

如果在更新期间某个服务返回 FAILED ,调度器会暂停更新,可以通过 --update-failure-action 参数配置控制当服务更新发生错误时的行为。

检查服务状态

1
docker service inspect --pretty redis

更新服务

1
docker service update --image redis:3.0.7 redis

默认情况下,调度器将按以下方式更新服务:

  • 停止一个服务
  • 更新已停止的服务
  • 启动已更新的服务

如果更新的服务返回 RUNNING ,等待指定的延迟时间后开始更新下一个服务

如果更新期间某个服务返回 FAILED ,则暂停服务更新

重新启动暂停的服务更新

1
docker service update redis

为了避免重复某些失败的更新,可以重新指定更新参数

查看服务的滚动更新

1
docker service ps redis

在swarm更新完成所有服务之前,你可以看到一些服务的镜像为 redis:3.0.6,另一些为 redis:3.0.7

路由网格

docker swarm支持路由网格。路由网格让处于swarm集群中的任意一个节点都可以作为被访问的入口,即使此节点没有运行任何服务。

要在 swarm 集群中使用使用路由网格,首先需要开启加入swarm集群的节点的以下端口:

  • 7946 :容器网络发现
  • 4789 :容器网络入口

其次需要将节点服务实例的端口公开,使服务可以被外部访问(例如使用nginx做负载均衡)

服务原理

1.2rv5sbkjzm.png

创建服务时公开端口

1
2
3
4
docker service create \
--name <SERVICE-NAME> \
--publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<IMAGE>

–publish 与 -p 效果相同,其中 --published 值为公布的端口,target 值为容器内部监听的端口。–publish 的写法

更新现有服务的公开端口

1
2
3
docker service update \
--publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<SERVICE>

查看服务发布的端口

1
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" 服务名称

只公开TCP或UDP端口

默认情况下公开端口都是 TCP 端口,你可以通过参数配置公开端口的类型:

仅TCP

1
2
3
docker service create --name dns-cache \
--publish published=53,target=53 \
dns-cache

1
2
3
docker service create --name dns-cache \
-p 53:53 \
dns-cache

仅UDP

1
2
3
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp \
dns-cache

1
2
3
docker service create --name dns-cache \
-p 53:53/udp \
dns-cache

TCP+UDP

1
2
3
4
docker service create --name dns-cache \
--publish published=53,target=53 \
--publish published=53,target=53,protocol=udp \
dns-cache

1
2
3
4
docker service create --name dns-cache \
-p 53:53 \
-p 53:53/udp \
dns-cache

绕过路由网格

要绕过 swarm 集群的路由网格,需要使用

  • -publish 参数设置 mode 值为host

下面的命令使用

host 模式创建全局服务并绕过路由网格:

1
2
3
4
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp,mode=host \
--mode global \
dns-cache

绕过路由网格后的注意事项:

  • 如果你访问未运行服务的节点,则无法访问此服务
  • 如果你希望在每个节点运行多个服务,就不能指定静态的端口。要么就允许docker随机分配一个公开端口(通过置空 published 参数的值实现)

配置管理

普通配置

https://docs.docker.com/engine/swarm/configs/

加密配置

https://docs.docker.com/engine/swarm/secrets/

锁定集群

https://docs.docker.com/engine/swarm/swarm_manager_locking/

默认情况下,swarm manager 使用的 Raft 日志在磁盘上是加密的。这种静态加密保护您的服务配置和数据免受攻击者访问加密的 Raft 日志。引入此功能的原因之一是支持Docker 机密功能。

当 Docker 重新启动时,用于加密 swarm 节点之间通信的 TLS 密钥和用于加密和解密磁盘上的 Raft 日志的密钥都被加载到每个管理器节点的内存中。Docker 有能力保护双向 TLS 加密密钥和用于加密和解密 Raft 静态日志的密钥,允许您拥有这些密钥并要求手动解锁您的管理器。此功能称为自动锁定

当 Docker 重新启动时,您必须先 解锁 swarm,使用 Docker 在 swarm 被锁定时生成的*密钥加密密钥。*您可以随时轮换此密钥加密密钥。

注意:当新节点加入 swarm 时,您不需要解锁 swarm,因为密钥通过双向 TLS 传播给它。