Docker 容器间怎么通信?同一项目、跨项目和跨主机方案
两个容器要互相访问,怎么连通?同一个 compose 项目的容器用服务名直接访问,不同项目的容器需要共享网络,跨主机通信就得用 Overlay 网络。这篇按场景从简单到复杂讲清楚。
同一 docker-compose 项目:默认网络
Docker Compose 自动为每个项目创建一个网络,项目内的容器可以互相用服务名访问:
yaml# docker-compose.yml services: api: image: myapp-api ports: - "3000:3000" redis: image: redis:7 postgres: image: postgres:16
bash# api 容器内直接用服务名访问 curl http://redis:6379 # 访问 Redis curl http://postgres:5432 # 访问 PostgreSQL
不需要 IP,不需要 --link——Docker 内置 DNS 自动把服务名解析为容器 IP。
自定义网络名
默认网络名是 项目名_default。如果要自定义:
yamlservices: api: networks: - frontend - backend redis: networks: - backend networks: frontend: backend:
api 同时在 frontend 和 backend 两个网络里——可以访问两边。redis 只在 backend 里——frontend 网络的容器访问不到 redis,实现网络隔离。
不同 docker-compose 项目:外部网络
两个独立的 compose 项目需要通信时,共享一个外部网络:
bash# 创建共享网络 docker network create shared-net
yaml# 项目 A: docker-compose.yml services: api: networks: - shared-net networks: shared-net: external: true
yaml# 项目 B: docker-compose.yml services: worker: networks: - shared-net networks: shared-net: external: true
项目 A 的 api 和项目 B 的 worker 通过服务名互相访问。
容器访问宿主机
容器里需要访问宿主机上的服务(比如宿主机上的 MySQL):
bash# 专用 DNS 名 curl http://host.docker.internal:3306
host.docker.internal 是 Docker Desktop 提供的特殊 DNS,自动解析为宿主机 IP。Linux 上需要手动添加:
yamlservices: api: extra_hosts: - "host.docker.internal:host-gateway"
容器间直接用 IP
不推荐但有时需要:
bash# 查看容器 IP docker inspect myapp --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' # 查看所有容器的 IP docker network inspect bridge --format '{{range .Containers}}{{.Name}}: {{.IPv4Address}}{{end}}'
容器 IP 每次重启可能变化——硬编码 IP 是反模式,应该用服务名或 DNS。
端口映射:容器对外暴露服务
yamlservices: api: ports: - "3000:3000" # 宿主机 3000 → 容器 3000 - "8080:80" # 宿主机 8080 → 容器 80 - "127.0.0.1:3306:3306" # 只允许本机访问
127.0.0.1:3306:3306 这种写法限制了只监听 loopback 接口——外部无法访问,只有宿主机本身可以连。适合数据库等不需要对外暴露的服务。
端口冲突排查
bash# 查看宿主机端口占用 lsof -i :3000 # 或 ss -tlnp | grep 3000 # Docker 占用的端口 docker port myapp
网络模式选择
| 模式 | 说明 | 适用场景 |
|---|---|---|
| bridge(默认) | 容器有独立 IP,通过 NAT 访问外部 | 大部分场景 |
| host | 容器直接用宿主机网络栈,无隔离 | 需要极致网络性能 |
| none | 无网络 | 离线计算任务 |
| overlay | 跨主机容器通信 | Docker Swarm / 多主机 |
host 模式
yamlservices: api: network_mode: host
host 模式下容器没有独立 IP,直接用宿主机的端口和网络。好处是没有 NAT 性能损耗,坏处是端口冲突风险高(容器和宿主机共享端口空间)。
不要在生产环境用 host 模式——失去了网络隔离,一个容器被攻破等于宿主机被攻破。
跨主机通信:Overlay 网络
Docker Swarm 多主机环境下,不同主机上的容器需要通信:
bash# 创建 Overlay 网络 docker network create -d overlay my-overlay # 在 Overlay 网络上启动服务 docker service create --network my-overlay --name api myapp docker service create --network my-overlay --name worker myworker
Overlay 网络底层用 VXLAN 隧道——api 和 worker 即使跑在不同的物理机上,也能通过服务名直接通信,和单机体验一致。
DNS 排查
容器间访问不通时,先排查 DNS:
bash# 进入容器测试 DNS 解析 docker exec myapp nslookup redis docker exec myapp ping redis # 查看 DNS 配置 docker exec myapp cat /etc/resolv.conf # 临时指定 DNS docker run --dns 8.8.8.8 myapp
常见问题:自定义了 docker-compose.yml 的 networks 但忘了在服务里引用,或者两个服务不在同一个网络里。