Docker Swarm 之 栈(Stack)

摘要

Stack简介

  • 前面我们在Swarm中创建服务都是通过Service,每次创建一个,有没有类似docker compose的方式来创建多个服务呢?Docker Swarm为我们提供了Stack

  • 在 Docker Swarm 中,Stack(栈) 是用来定义和部署一组相关服务的集合。你可以把它看成是一个应用的整体,由多个服务(service)、网络(network)、卷(volume)等组成。

Stack 通常用 Docker Compose 文件(YAML 格式) 描述

  • Stack 完全兼容 Docker Compose 文件,并可以在 compose 文件中声明副本集等与Service相关的配置项。

  • 我用表格总结一下二者的差异,重点放在「Stack 支持的配置」上:

配置项 Docker Compose (本地) Docker Stack (Swarm 集群) 说明
name Stack 不支持 name 属性
build Stack 不支持 build 属性,只能使用image
deploy ❌(部分支持,通常被忽略) ✅(核心支持) Stack 支持用 deploy 定义副本数、资源限制、更新策略等
deploy.replicas 定义服务副本数
deploy.resources 定义 CPU、内存限制
deploy.placement 定义服务调度策略(在哪些节点上运行)
deploy.update_config 定义滚动更新的参数
deploy.restart_policy 定义重启策略
deploy.mode replicatedglobal
depends_on 🚫(被忽略) Stack 不支持容器启动顺序控制
build 🚫(被忽略) Stack 不支持直接构建镜像,只能用已存在的镜像
network.external 都支持外部网络
volumes.external 都支持外部卷
configs 🚫 Stack 支持 Config 对象,适合配置文件管理
secrets 🚫 Stack 支持 Secrets,用于安全存储敏感信息

Portainer 社区版 (CE)可让您在 Docker、Docker Swarm、Kubernetes 和 Azure ACI 中轻松构建和管理容器。

1
curl -L https://downloads.portainer.io/ce-lts/portainer-agent-stack.yml -o portainer-agent-stack.yml
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
version: "3.2" #  docker-compose版本,新版的docker已经不需要配置版本号了
services:
agent: # agent服务
image: portainer/agent:lts # 镜像,不能使用 Dockerfile
volumes: # 挂载卷
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks: # 挂载网络,必须是 overlay
- agent_network
deploy: # 部署策略,service 特有属性
mode: global # 全局模式
placement: # 部署条件
constraints: [node.platform.os == linux] # 运行在linux节点

portainer: # portainer服务
image: portainer/portainer-ce:lts # 镜像
command: -H tcp://tasks.agent:9001 --tlsskipverify # 启动参数
ports: # 端口映射
- "9443:9443" # 浏览器访问 https://localhost:9443
- "9000:9000"
- "8000:8000"
volumes: # 挂载卷
- portainer_data:/data
networks: # 挂载网络,与agent服务网络一致
- agent_network
deploy: # 部署配置
mode: replicated # 副本模式
replicas: 1 # 副本数量
placement: # 部署条件
constraints: [node.role == manager] # 节点角色为manager

networks: # 网络声明
agent_network: # 网络名称
driver: overlay # 网络驱动
attachable: true # 允许容器加入

volumes: # 挂载卷声明
portainer_data: # 挂载卷名称

Stack 命令

子命令 中文说明 示例命令
config 输出最终的配置文件(经过合并与变量替换后) docker stack config -c docker-compose.yml
deploy 部署新 stack 或更新已有 stack docker stack deploy -c docker-compose.yml mystack
ls 列出所有已部署的 stack docker stack ls
ps 查看 stack 中的所有任务(即各个容器实例) docker stack ps mystack
rm 删除一个或多个 stack docker stack rm mystack
services 列出某个 stack 中的所有服务 docker stack services mystack

docker stack config: 输出最终的配置文件

1
2
# 此命令也可以用来验证compose文件格式是否正确,只保证格式正确,不保证逻辑正确
docker stack config -c portainer-agent-stack.yml

docker stack deploy: 部署 stack

  • docker stack deploy == docker stack up

1
2
3
4
5
docker stack deploy -c portainer-agent-stack.yml portainer
## 输出
Creating network portainer_agent_network
Creating service portainer_agent
Creating service portainer_portainer

docker stack ls: 列出所有 stack

  • docker stack ls == docker stack list

1
2
3
4
docker stack ls
## 输出,stack名称为portainer,其内部有两个服务,agent和portainer
NAME SERVICES
portainer 2

docker stack services: 查看服务

1
2
3
4
5
6
7
8
9
10
11
12
docker stack services portainer
## 输出
ID NAME MODE REPLICAS IMAGE PORTS
h5foyujr6jq9 portainer_agent global 5/5 portainer/agent:lts
zcek2jtloe09 portainer_portainer replicated 1/1 portainer/portainer-ce:lts *:8000->8000/tcp, *:9000->9000/tcp, *:9443->9443/tcp

## 等效
docker service ls
## 输出
ID NAME MODE REPLICAS IMAGE PORTS
h5foyujr6jq9 portainer_agent global 5/5 portainer/agent:lts
zcek2jtloe09 portainer_portainer replicated 1/1 portainer/portainer-ce:lts *:8000->8000/tcp, *:9000->9000/tcp, *:9443->9443/tcp

docker stack ps: 列出 stack 下的所有服务实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
docker stack ps portainer
## 输出
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wshk9s6gyxh1 portainer_agent.hvzkh3ip5ef8gx973z1ywahbu portainer/agent:lts worker2 Running Running 30 seconds ago
n3jjzmr2fcv9 portainer_agent.kp2zerd28xgz5mmglnje0jp22 portainer/agent:lts manager1 Running Running 59 seconds ago
24yy1ew3tiya portainer_agent.oymi74epagdqeprah7s81tsa2 portainer/agent:lts manager2 Running Running 3 minutes ago
kpo4hhdvwcwd portainer_agent.r7388xl84nczjtnf53pwh7hla portainer/agent:lts manager3 Running Running 35 seconds ago
t8xjbotfuas0 portainer_agent.xkww4853bbdgv7bv8771xibob portainer/agent:lts worker1 Running Running 48 seconds ago
qox3kqypon69 portainer_portainer.1 portainer/portainer-ce:lts manager2 Running Running 2 minutes ago

## 等效
docker service ps portainer_agent portainer_portainer
## 输出
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wshk9s6gyxh1 portainer_agent.hvzkh3ip5ef8gx973z1ywahbu portainer/agent:lts worker2 Running Running 7 minutes ago
n3jjzmr2fcv9 portainer_agent.kp2zerd28xgz5mmglnje0jp22 portainer/agent:lts manager1 Running Running 8 minutes ago
24yy1ew3tiya portainer_agent.oymi74epagdqeprah7s81tsa2 portainer/agent:lts manager2 Running Running 10 minutes ago
kpo4hhdvwcwd portainer_agent.r7388xl84nczjtnf53pwh7hla portainer/agent:lts manager3 Running Running 7 minutes ago
t8xjbotfuas0 portainer_agent.xkww4853bbdgv7bv8771xibob portainer/agent:lts worker1 Running Running 7 minutes ago
qox3kqypon69 portainer_portainer.1 portainer/portainer-ce:lts manager2 Running Running 10 minutes ago

docker stack rm: 停止并删除 stack

  • docker stack rm == docker stack remove == docker stack down

1
docker stack rm portainer

deploy 参数详解

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
services:
my-service:
image: myapp:latest

deploy:
replicas: 3 # 指定副本数,仅在 mode: replicated 下有效。表示同时运行3个容器副本。

mode: replicated # 服务运行模式,可选值:
# - replicated:通过 replicas 指定副本数量(默认)
# - global:每个节点运行一个副本,忽略 replicas 配置

resources:
limits: # 容器的“硬限制”,超过会被强制限制
cpus: '1.0' # 限制每个容器最多使用1个逻辑 CPU
memory: 512M # 限制每个容器最多使用512MB内存

reservations: # 容器的“软限制”,Swarm调度时预留资源参考值(不会强制限制)
cpus: '0.25' # 建议每个容器至少分配0.25个CPU
memory: 128M # 建议每个容器至少分配128MB内存

restart_policy:
condition: on-failure # 控制容器重启行为,可选值:
# - none:不重启
# - on-failure:失败时重启(非0退出码)
# - any:无论是否失败都重启
delay: 5s # 重启前等待时间
max_attempts: 3 # 最多重启3次
window: 60s # 判断失败次数的时间窗口(60秒内最多失败3次)

placement:
constraints: # 指定容器调度到哪些节点上运行,可用条件有:
# - node.role == manager/worker
# - node.hostname == xxx
# - node.labels.xxx == yyy
- node.role == worker # 只调度到 worker 节点

preferences: # 调度偏好(不是强约束)
- spread: node.labels.zone # 将服务均匀地分布在 zone 标签不同的节点上

update_config: # 控制服务滚动更新的行为
parallelism: 2 # 每次最多并发更新2个容器
delay: 10s # 每批更新之间等待10秒
failure_action: rollback # 更新失败时的处理方式,可选值:
# - pause:暂停更新(默认)
# - continue:继续更新
# - rollback:回滚到旧版本
order: stop-first # 控制更新顺序,可选值:
# - stop-first(先停后启,默认)
# - start-first(先启后停,适用于无状态服务)

rollback_config: # 回滚时的行为,字段与 update_config 类似
parallelism: 1 # 回滚时每次最多处理1个容器
delay: 5s # 每批回滚之间等待5秒
failure_action: pause # 回滚失败时暂停
order: stop-first # 回滚时先停再启