Docker Swarm主机网络下的服务发现与跨服务通信问题求助
1. 通过Swarm API直接查询任务IP
Docker Swarm原生API可获取服务的所有任务详情,包括任务所在节点的公网/私有IP、端口映射信息。在任意Swarm管理节点执行以下命令:
# 获取目标服务ID(替换为你的服务名) SERVICE_ID=$(docker service inspect --format '{{.ID}}' your-service-name) # 查询该服务下所有运行中任务的详细信息 curl -s "http://localhost:2375/services/$SERVICE_ID/tasks?desired-state=running"
若需过滤关键信息(节点IP、已发布端口),可借助jq工具解析:
curl -s "http://localhost:2375/services/$SERVICE_ID/tasks?desired-state=running" | jq '.[] | {task_id:.ID, node_ip:.NodeStatus.Addr, published_ports:.Status.PortStatus.PublishedPorts}'
注意:默认Swarm API仅监听Unix Socket,需修改Docker daemon配置(
/etc/docker/daemon.json)开启TCP访问,重启服务后生效:{ "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"] }生产环境建议搭配TLS加密保障API安全。
2. 部署辅助服务实现DNS兼容
若需保留DNS访问能力,可通过轻量代理服务将host网络服务信息同步至Swarm可识别的DNS体系:
方案A:用Traefik做反向代理
部署Traefik作为Swarm服务,监听host网络服务的端口,其他服务通过Traefik路由域名访问目标服务:
docker service create \ --name traefik \ --constraint node.role==manager \ --publish 80:80 \ --publish 8080:8080 \ --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ traefik:v2.9 \ --providers.docker.swarmmode=true \ --providers.docker.exposedbydefault=false \ --entrypoints.web.address=:80
给host网络服务添加Traefik标签(更新服务时执行):
docker service update \ --label-add traefik.enable=true \ --label-add traefik.http.routers.your-service.rule=Host(`your-service.local`) \ --label-add traefik.http.services.your-service.loadbalancer.server.port=<your-service-port> \ your-service-name
之后其他服务即可通过your-service.local访问目标服务。
方案B:用Registrator同步到Consul
部署Consul和Registrator,Registrator会自动将host网络服务的端口注册到Consul,其他服务通过Consul DNS查询:
# 启动Consul服务 docker service create --name consul --publish 8600:8600/udp consul:latest agent -server -bootstrap-expect=1 -client=0.0.0.0 # 全局部署Registrator(每个节点运行一个实例) docker service create \ --name registrator \ --mode global \ --mount type=bind,source=/var/run/docker.sock,target=/tmp/docker.sock \ gliderlabs/registrator:latest \ -ip '{{.Node.Status.Addr}}' consul://consul:8500
其他服务可通过your-service-name.service.consul域名访问目标服务。
3. 替换Host网络为Macvlan网络
若host网络并非硬性需求,推荐用macvlan网络替代——macvlan允许容器直接接入物理网络,同时支持与overlay网络共存,服务可同时使用Swarm DNSRR和物理网络访问:
# 创建macvlan网络(替换为你的物理网卡、子网、网关) docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --gateway=192.168.1.1 \ -o parent=eth0 \ macvlan-network # 创建服务时同时加入macvlan和overlay网络 docker service create \ --name your-service \ --network macvlan-network \ --network your-overlay-network \ your-image:latest
此方案下,服务既可以通过macvlan获取物理网络IP,又能通过overlay网络的DNS名访问其他服务,也可正常使用DNSRR查询任务IP。
4. 在Host网络容器内配置DNS转发
若必须保留host网络,可在容器内配置DNS转发,让容器能解析Swarm overlay网络的服务域名:
在容器内安装dnsmasq,创建配置文件/etc/dnsmasq.d/swarm-dns.conf:
# 转发overlay网络的DNS查询到Swarm内置DNS server=/your-overlay-network/127.0.0.11
将容器的DNS设置为127.0.0.1,即可通过域名访问overlay网络的服务。
内容的提问来源于stack exchange,提问作者Prometheus

