Docker Swarm 之 服务(Service)
摘要
-
本文介绍 Docker Swarm 的 服务管理
Service 与 Task
什么是 Service?
-
Service 是用户定义的服务抽象,一个 Service 表示你希望在 Swarm 集群中运行的某个“应用”。
-
它定义了你要运行的容器镜像、启动命令、副本数量、网络配置、环境变量、端口映射等信息。
-
可以类比成 Kubernetes 中的 Deployment,代表的是“期望状态”。
什么是 Task?
-
Task 是 Service 的实际执行实例,Swarm 会根据 Service 的配置生成 Task。
-
Service中的每个副本对应一个 Task,每一个 Task 代表一个要在某个节点上运行的容器。
-
Task 的状态由 Swarm 管理,它负责启动、调度、重启等生命周期操作。
-
当某个 Task 崩溃,Swarm 会自动重新调度一个新的 Task 来替代它。
-
Task 是不可变的,一旦创建不能修改,更新 Service 会创建新的 Task。
示例
-
创建一个名为 nginx 的 Service,并指定镜像为 nginx:latest,并设置副本数为 3。
1 | docker service create --name nginx --replicas 3 nginx:latest |
-
这里创建了一个名为 nginx 的 Service,并设置了副本数为 3,即Swarm会创建3个Task来完成这个任务,每个 Task 最终会对应一个具体的nginx容器。
项目 | Service | Task |
---|---|---|
定义 | 用户定义的服务配置 | 服务配置生成的执行单元 |
数量关系 | 一个 Service 包含多个 Task | 一个 Task 属于一个 Service |
状态 | 描述“期望状态” | 代表“实际状态” |
生命周期 | 可以更新 | 不可变,更新意味着重新创建 |
管理者 | 由用户管理 | 完全由 Swarm 调度和管理 |
Service 相关命令
命令 | 中文说明 |
---|---|
create | 创建一个新的服务 |
inspect | 显示一个或多个服务的详细信息 |
logs | 获取服务或任务的日志 |
ls | 列出所有服务 |
ps | 列出一个或多个服务的任务(Task) |
rm | 删除一个或多个服务 |
rollback | 回滚服务的配置更改 |
scale | 扩缩一个或多个可复制服务的副本数量 |
update | 更新服务配置 |
docker service create
: 创建服务
-
常用参数说明
参数 | 说明 | 示例命令(含说明) |
---|---|---|
--name |
指定服务名称 | docker service create --name my-web nginx → 创建一个名为 my-web 的 nginx 服务 |
--replicas |
设置副本数量(仅适用于 replicated 模式) | docker service create --replicas 3 nginx → 启动 3 个 nginx 副本 |
--publish 或 -p |
映射端口(格式如 80:80 ) |
docker service create -p 8080:80 nginx → 将容器的 80 端口映射到主机 8080 |
--env 或 -e |
设置环境变量 | docker service create -e ENV=prod nginx → 设置环境变量 ENV=prod |
--mount |
设置数据卷挂载 | docker service create --mount type=bind,src=/data,target=/app nginx → 将主机的 /data 目录挂载到容器内 /app |
--constraint |
设置部署约束(如指定节点) | docker service create --constraint 'node.labels.type == web' nginx → 仅部署在带标签 type=web 的节点上 |
--network |
指定服务所属的网络(通常使用 overlay 网络) | docker service create --network my-net nginx → 将服务连接到自定义网络 my-net |
--detach 或 -d |
后台运行服务(默认行为) | docker service create -d nginx → 后台创建服务,不阻塞终端,因为是默认行为,所以不加 -d 也是一样的,service不支持像 docker run 那样支持前台运行 |
--limit-cpu / --limit-memory |
设置资源限制 | docker service create --limit-cpu 0.5 --limit-memory 256M nginx → 每个任务最多使用 0.5 个 CPU 和 256MB 内存 |
--restart-condition |
设置重启策略(如 on-failure、any、none) | docker service create --restart-condition on-failure nginx → 仅当容器失败时自动重启 |
--mode |
指定服务运行模式,支持:replicated 、global 、replicated-job 、global-job |
docker service create --mode global nginx → 在集群每个节点上运行一个 nginx 实例 |
-
服务运行模式(–mode)详解
模式名称 | 说明 | 使用场景示例 |
---|---|---|
replicated |
默认模式。用户指定需要运行多少个副本,Swarm 在合适的节点上调度这些副本。 | 典型的 Web 服务,如 nginx、Node.js、Java 应用等 |
global |
每个可用节点只部署一个任务实例,不需要用户指定副本数。 | 系统级服务,如日志收集器(Fluentd)、监控代理(Prometheus node exporter) |
replicated-job |
在多个节点上按副本数运行一次性任务,任务完成后即退出。 | 数据处理、批处理任务,如转换文件或跑 ETL |
global-job |
在所有节点上各运行一次的短暂任务,执行完毕即退出。 | 初始化脚本、每台机器上运行一次的数据清洗、初始化环境任务等 |
job 模式通常配合镜像中设定的入口命令使用,不适用于长期运行的服务。
replicated 和 global 模式适用于持续运行的服务,Swarm 会自动重启失败的任务。
-
服务重启策略(–restart-condition)详解
值 | 含义说明 |
---|---|
none |
不重启任务。即使任务失败,也不会尝试恢复。适用于短生命周期的任务或测试服务。 |
on-failure |
仅在任务异常失败时(exit code 非 0)自动重启。常用于可能偶发失败的服务。 |
any (默认) |
无论任务如何退出(包括正常退出或失败),都会尝试重启。适用于持续运行服务。 |
情景总结
情景 | none |
on-failure |
any |
---|---|---|---|
服务运行时崩溃(exit code ≠ 0) | ❌ 不重启 | ✅ 自动重启 | ✅ 自动重启 |
服务正常结束(exit code = 0) | ❌ 不重启 | ❌ 不重启 | ✅ 自动重启 |
持续运行型服务(如 nginx) | ❌ 不推荐 | 可用 | ✅ 推荐 |
一次性任务(如批处理、数据初始化) | ✅ 推荐 | 可用 | ❌ 不推荐 |
docker service create
使用示例
-
创建一个名为 my-nginx 的服务,并指定 3 个副本,将 80 端口映射到主机的 80 端口,并使用 nginx 镜像
1 | # 此时在浏览器中输入Swarm中任意节点的IP地址,即可访问到Nginx服务,即使任务没有被分配到这个节点,也能访问到Nginx服务,这就是Swarm的负载均衡功能 |
-
创建一个名为 log-agent 的全局服务,并使用 fluentd 镜像,即每个节点都会运行一个 fluentd 容器
1 | # global |
-
创建一个名称为 web-app 的服务,并设置环境变量 NODE_ENV=production ,挂载 /data 目录到容器的 /app/data 目录,并设置 2 个副本,并且指定启动容器的命令为 node server.js
1 | docker service create \ |
-
创建一个名称为 db 的服务,并指定运行在具有 role=db 标签的节点上,并且使用名为 db-data 的卷挂载数据
1 | # 创建数据卷 |
-
使用 on-failure 策略,仅在失败时自动重启
1 | docker service create \ |
-
指定网络,网络驱动类型为 overlay
1 | # 先在manager节点上创建一个 overlay 网络(适用于 Swarm 模式) |
小贴士
1 | docker network ls |
- 初始化Swarm集群后,会创建一个默认的 overlay 网络: ingress,如果我们创建服务时没有指定网络,那么服务就会加入 ingress 网络。
- 但是这个默认的 ingress 网络并不能用于服务之间通过服务名称互相访问,但可以通过IP或Hostname访问服务。
- 默认的 ingress 网络仅用于 ingress 负载均衡(即 -p 端口映射),不支持服务内部通信或 DNS 服务发现。
- 另外,初始化Swarm集群后,还会创建一个默认的 bridge 网络: docker_gwbridge,负责连接 Swarm 集群的 Overlay 网络与宿主机网络,负责跨节点的流量转发
- 当一个容器在 Overlay 网络里访问外部 IP,比如访问公网,流量最终通过 docker_gwbridge 网络出口出去。
- 节点间 VXLAN 隧道的流量也会借助此网络桥接到宿主机的物理网络接口。
docker service ls
: 列出所有服务
1 | docker service ls |
docker service inspect
: 查看服务详情
1 | docker service inspect my-nginx |
docker service log
: 查看服务日志
1 | # 查看指定服务下所有任务的日志 |
docker service ps
: 列出服务任务
1 | docker service ps my-nginx |
docker service scale
: 扩容/缩容服务
1 | # 启动一个服务 |
docker service update
: 更新服务
-
支持的参数
参数 | 说明 | 示例 |
---|---|---|
--image |
更新服务使用的镜像 | --image nginx:1.25 |
--replicas |
设置服务的副本数量(仅适用于 replicated 模式) | --replicas 5 |
--env-add |
添加环境变量 | --env-add DEBUG=true |
--env-rm |
移除环境变量 | --env-rm OLD_VAR |
--publish-add |
添加端口映射 | --publish-add published=8080,target=80 |
--publish-rm |
移除端口映射 | --publish-rm 80 |
--mount-add |
添加挂载 | --mount-add type=bind,src=/data,dst=/data |
--mount-rm |
移除挂载 | --mount-rm /data |
--constraint-add |
添加部署约束 | --constraint-add 'node.labels.zone==east' |
--constraint-rm |
移除部署约束 | --constraint-rm 'node.labels.zone==east' |
--limit-cpu |
设置 CPU 限制 | --limit-cpu 0.5 |
--limit-memory |
设置内存限制 | --limit-memory 256M |
--restart-condition |
设置重启策略(none、on-failure、any) | --restart-condition on-failure |
--update-delay |
设置任务更新之间的延迟 | --update-delay 10s |
--update-parallelism |
设置并发更新任务的数量 | --update-parallelism 2 |
--update-order |
设置更新顺序(start-first 或 stop-first) | --update-order start-first |
--update-failure-action |
更新失败后的动作(pause、continue、rollback) | --update-failure-action rollback |
--rollback |
回滚到上一次成功配置 | --rollback |
-
示例
1 | docker service update \ |
docker service rollback
: 回滚服务
-
会将服务回滚到上一次成功部署的版本,包括镜像、环境变量、部署约束等。
1 | # docker service rollback <service_name> |
docker service rm
: 删除服务
-
删除服务会停止服务并删除服务。
1 | # docker service rm <service_name> |
经验技巧
如何让任务运行在指定的节点上?
-
创建服务时,可以使用
--constraint
参数指定节点的标签,使其运行在具有指定标签的节点上。
1 | # 给结点加标签 |
-
只能运行在管理节点上
1 | # node.role 是 Swarm 的内置属性,表示节点的类型,值为 manager 或 worker。 |
-
Swarm 内置属性
属性名 | 示例值 | 说明 |
---|---|---|
node.id |
node.id == abcd1234 |
节点的唯一 ID(可用 docker node ls 查看) |
node.hostname |
node.hostname == manager-1 |
节点主机名 |
node.role |
node.role == manager 或 node.role == worker |
节点在 Swarm 中的角色(管理/工作) |
engine.labels.* |
engine.labels.disk == ssd |
Docker 引擎级别的标签(需手动设置) |
node.platform.os |
node.platform.os == linux |
节点操作系统类型 |
node.platform.arch |
node.platform.arch == x86_64 |
节点架构类型(如 arm64 , x86_64 ) |
如何访问Service服务?
1 | # 启动一个service,3个副本,镜像为 whoami,这个镜像会返回当前访问的容器的ID,即返回的Hostname |
-
此时我们通过curl访问 Swarm 集群中的任意一个节点的IP,都可以访问到这个服务,比如
curl 10.211.55.12
,这是 manager3 节点的 IP 地址,虽然这个服务并没有在 manager3 节点上运行,但是我们依旧可以访问到这个服务,不仅如此,每次运行命令返回的Hostname(就是容器ID)都会发生变化,其效果就是在各个运行的容器间轮询,这就是 Swarm 集群的负载均衡效果。
1 | curl http://10.211.55.12 |
-
在集群内部访问服务,建议将所有服务运行在相同的network中,这样可以不同的service之间可以通过服务名称访问服务,在集群外部,可以通过nginx等代理访问服务。
-
可以编写一个脚本方便查看service与container的运行关系,比如:docker_service_container
1 |
|
-
运行
1 | chmod +x /usr/local/bin/docker-swarm-service |