Docker Swarm:仅将请求转发至负载均衡器同主机的容器
让Docker Swarm负载均衡器仅转发请求到同一主机容器的实现方案
要实现Swarm只将请求转发到同一主机的容器,核心是绕过Swarm默认的VIP负载均衡机制,让本地的Caddy直接对接本地容器实例,以下是两种可靠的实现方式:
方法1:DNSRR模式 + 主机亲和性 + 本地服务发现
这种方法保留Swarm的调度能力,同时让Caddy精准访问本地容器:
修改Stack配置,关闭Swarm VIP负载均衡
在docker-compose.yml中为服务设置endpoint_mode: dnsrr,这样Swarm不会创建统一的VIP,而是通过DNS返回所有容器的IP记录;同时添加主机亲和性约束,确保服务实例被调度到目标主机:version: '3.8' services: my-app: image: your-app-image:latest deploy: mode: replicated replicas: 2 # 按主机数量设置副本数 update_config: order: start-first # 保留零停机更新特性 failure_action: rollback placement: constraints: - node.labels.local-app == true # 给需要运行服务的主机打此标签 endpoint_mode: dnsrr # 禁用Swarm VIP负载均衡 hostname: my-app-{{.Node.Hostname}} # 容器主机名绑定节点主机名 networks: - app-net networks: app-net: driver: overlay attachable: true配置本地Caddy访问对应容器
在每个主机的Caddy配置中,通过节点主机名匹配本地容器,确保只转发到当前主机的实例:your-domain.com { reverse_proxy my-app-{$HOSTNAME}:8080 { health_check /health # 复用已有的健康检查 lb_policy least_conn } }这里
{$HOSTNAME}会自动读取当前主机的主机名,匹配容器的hostname配置,实现精准的本地容器访问。
方法2:主机网络模式(简单直接但需注意端口冲突)
如果不需要Swarm的网络隔离特性,可以直接让容器使用主机网络栈,Caddy通过localhost访问本地容器:
services: my-app: image: your-app-image:latest deploy: mode: replicated replicas: 2 update_config: order: start-first placement: constraints: - node.labels.local-app == true network_mode: host # 容器使用主机网络 ports: - "8080:8080" # 需确保端口在主机上不冲突
Caddy配置直接指向localhost:8080即可,这种方式完全跳过Swarm的负载均衡,延迟最低,但端口管理需要额外注意。
核心逻辑说明
Swarm默认的VIP模式会将请求负载均衡到所有节点的容器,而我们通过dnsrr模式让服务DNS返回所有容器IP,再配合主机名绑定或主机网络,让本地Caddy只选择当前主机的容器实例,既保留了start-first的零停机更新能力,又避免了Swarm负载均衡带来的额外延迟。
内容的提问来源于stack exchange,提问作者Abdurrahman Arroisi
相关产品推荐
相关产品推荐

