在 docker swarm 中利用 label 实现灰度发布与测试,核心做法是部署多版本服务并配合 docker service update 命令的 --label-add 参数动态修改路由标签。通过为不同版本的服务实例设置如 version=stable 和 version=canary 等互斥标签,结合外部负载均衡器(如 nginx)读取这些标签进行流量分发,即可在不重启集群的情况下将特定比例的请求引导至新版本进行测试。

如何创建带有版本标签的多版本服务
要实现灰度环境,首先需要同时运行两个相同功能但不同镜像或配置的服务副本。关键在于使用 docker service create 时的 --label 参数来标记服务的身份标识。例如,创建一个名为 app-stable 的服务并打上 version=stable 标签,再创建一个名为 app-canary 的服务并打上 version=canary 标签。这样,Swarm 调度器会将这两个服务视为独立的实体,而负载均衡器可以根据这些标签决定将流量指向哪一个。

docker service create \ --name app-stable \ --label version=stable \ --replicas 2 \ nginx:latest docker service create \ --name app-canary \ --label version=canary \ --replicas 1 \ nginx:latest
上述命令执行后,Swarm 集群中将存在两个独立的服务。可以通过 docker service inspect --format '{{.Spec.Labels}}' app-stable' 验证标签是否生效。此时,如果直接访问 Swarm 的 VIP,默认会轮询所有可用的服务任务,无法区分版本。因此,必须引入外部流量入口来解析这些标签。
如何通过外部负载均衡器根据标签分流流量
Docker Swarm 内置的负载均衡器不支持基于标签的路由规则,因此需要借助 Nginx 等反向代理作为前端入口。Nginx 可以通过 resolver 指令动态解析 Swarm DNS,并利用 lua-nginx-module 或简单的 upstream 映射来实现基于标签的分流。更简单的做法是利用 Swarm 的 DNS 特性,将不同标签的服务映射到不同的上游组,或者在 Nginx 配置中硬编码不同版本的 VIP 地址比例。

upstream stable_backend {
server app-stable:80;
}
upstream canary_backend {
server app-canary:80;
}
server {
listen 80;
location / {
# 90% 流量去稳定版,10% 去灰度版
set $backend stable_backend;
if ($request_uri ~* "test") {
set $backend canary_backend;
}
proxy_pass http://$backend;
}
}
在实际操作中,通常会在 Nginx 配置中定义两个 upstream,分别指向 app-stable 和 app-canary 服务的 DNS 名称。通过调整 proxy_pass 的目标或使用加权轮询,可以控制进入灰度版本的流量比例。当测试完成且新版本稳定后,只需更新 app-canary 的镜像并增加其副本数,同时将 app-stable 的副本数减少,即可完成平滑过渡。
动态更新服务标签以切换灰度状态
当灰度测试阶段需要调整流量比例或切换主版本时,无需删除重建服务,可以直接使用 docker service update 命令修改现有服务的标签。例如,若要将 app-canary 提升为主版本,可以将其标签从 version=canary 改为 version=stable,同时更新 app-stable 的标签为 version=old 或将其下线。这种动态标签更新机制允许运维人员在运行时实时调整路由策略,而无需中断正在进行的请求。
docker service update \ --label-rm version=canary \ --label-add version=main \ app-canary docker service update \ --label-rm version=stable \ --label-add version=legacy \ app-stable
执行上述命令后,Nginx 或其他负载均衡器需要能够感知到标签的变化。如果使用的是基于 DNS 解析的方案,可能需要等待 DNS TTL 过期或手动刷新缓存。如果使用的是 Lua 脚本动态查询 Swarm API,则可以立即生效。这种灵活性使得灰度发布过程更加可控,能够快速回滚或推广新版本。











