如何让全局模式Docker Swarm服务在同一主机直接通信?
解决Docker Swarm中全局Prometheus抓取同节点Promtail指标的问题
问题根源
- Swarm默认服务发现(如
promtail:9080)会随机路由到任意节点的Promtail实例,无法保证同节点抓取 - 同时使用
host网络和Swarm overlay网络会触发报错,因为容器不能同时共享主机网络命名空间和连接其他网络
方案一:纯Host网络部署(最简单直接)
直接让两个服务都使用主机网络,完全避免跨节点路由:
- 修改Promtail部署配置,仅使用host网络:
services: promtail: image: grafana/promtail:latest deploy: mode: global network_mode: host command: -config.file=/etc/promtail/config.yml volumes: - ./promtail-config.yml:/etc/promtail/config.yml - /var/log:/var/log - /var/lib/docker/containers:/var/lib/docker/containers:ro # host网络下无需单独暴露端口,直接使用主机的9080端口 - 修改Prometheus部署配置,同样使用host网络,抓取本地端口:
services: prometheus: image: prom/prometheus:latest deploy: mode: global network_mode: host volumes: - ./prometheus-config.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus - 在Prometheus配置文件中,将抓取目标设为
localhost:9080/metrics:
这样每个节点的Prometheus只会抓取本机的Promtail实例,彻底解决跨节点路由问题。scrape_configs: - job_name: 'promtail' static_configs: - targets: ['localhost:9080']
方案二:保留Overlay网络,通过Relabeling过滤同节点目标
如果不想使用host网络,可借助Swarm服务元数据和Prometheus的relabel规则实现精准匹配:
- 给Promtail和Prometheus配置相同的Swarm overlay网络:
networks: monitoring: driver: overlay attachable: true services: promtail: image: grafana/promtail:latest deploy: mode: global networks: - monitoring ports: - 9080:9080 # 其他卷、命令配置... prometheus: image: prom/prometheus:latest deploy: mode: global networks: - monitoring environment: # 注入当前节点的主机名作为环境变量 - POD_NODE_NAME={{.Node.Hostname}} volumes: - ./prometheus-config.yml:/etc/prometheus/prometheus.yml - 修改Prometheus的抓取配置,通过DNS服务发现获取所有Promtail实例,再过滤同节点目标:
这个方案依赖Swarm的服务元数据传递,确保每个Prometheus实例只抓取和自己同节点的Promtail。scrape_configs: - job_name: 'promtail' dns_sd_configs: - names: ['tasks.promtail'] type: 'A' port: 9080 relabel_configs: # 从Swarm元数据中提取Promtail所在节点的名称 - source_labels: [__meta_docker_swarm_node_name] target_label: promtail_node # 将Prometheus自身的节点名注入标签 - source_labels: [__env_POD_NODE_NAME] target_label: prometheus_node # 只保留节点名匹配的目标 - action: keep source_labels: [promtail_node, prometheus_node] regex: '(.+);\1'
内容的提问来源于stack exchange,提问作者jah




