容器默认bridge网络不支持互通和dns解析,需创建自定义bridge网络(如mynet)并指定--network接入,才能通过容器名通信;启动顺序问题需应用层重试或健康检查,非网络配置问题。

容器默认使用 bridge 网络,但不同 docker run 启动的容器默认不互通
新启动的容器如果不指定 --network,会自动接入默认的 bridge 网络。但这个默认网络不支持容器名解析(即不能用 ping myapp),且部分宿主机防火墙或 iptables 规则可能拦截跨容器通信。你看到 curl: (7) Failed to connect 或 Connection refused,大概率不是服务没起来,而是网络没通。
解决办法是显式创建自定义 bridge 网络,它自带 DNS 解析和隔离能力:
- 运行
docker network create mynet创建一个叫mynet的桥接网络 - 启动容器时加
--network mynet,例如:docker run --network mynet --name db -d postgres:15 - 另一容器也加入同一网络:
docker run --network mynet --name app -e DB_HOST=db -d mywebapp
此时 app 容器内可以直接用 db 当主机名访问数据库,无需查 IP,也不用手动改 /etc/hosts。
多个容器想复用同一网络,但启动顺序不确定怎么办
容器名在启动时才注册进网络 DNS,如果 app 先启动、db 后启动,app 初始化时解析 db 会失败——这不是网络配置问题,而是应用层未做重试或健康等待。
常见应对方式有:
- 用
depends_on+ 自定义健康检查(仅 Compose v2.3+ 有效):depends_on: { db: { condition: service_healthy } } - 在应用启动脚本里加简单轮询,比如
until nc -z db 5432; do sleep 2; done - 避免依赖容器名启动:把
DB_HOST改成db:5432字符串传入,让应用自己处理连接失败重试
注意:depends_on 不保证端口就绪,只保证容器进程已启动;DNS 解析成功 ≠ 服务可连,这点容易被忽略。
想让容器既能访问内网服务,又能连外网,该选 host 还是自定义 bridge
host 模式确实能直通宿主机网络,但会丢失容器网络隔离、无法用容器名通信、端口冲突风险高,还可能绕过 Docker 的 iptables 链导致安全策略失效。绝大多数场景不该选它。
正确做法是保持自定义 bridge 网络,并确认以下两点:
- 该网络的
com.docker.network.bridge.enable_ip_masquerade属性为true(默认开启),保证出向 NAT 正常 - 宿主机没禁用
FORWARD链,比如某些云服务器厂商的默认安全组或 firewalld 规则会 DROP 转发包 - 如需容器访问宿主机上的服务(比如本地 MySQL),用特殊 DNS 名
host.docker.internal(Mac/Windows 原生支持;Linux 需加--add-host=host.docker.internal:host-gateway)
docker-compose.yml 中 network 配置写错的典型表现
写错最直接的结果是:容器启动成功,日志里却反复报 getaddrinfo EAI_AGAIN db 或 Connection refused,而 docker network inspect mynet 显示容器根本不在该网络里。
高频错误包括:
- 忘记在
services下声明networks:块,只在根级写了networks:定义 - 容器指定了
network_mode: "bridge",覆盖了networks:配置,退回到默认 bridge - 网络名拼错,比如写成
mynet和my-net混用,Docker 不报错但实际分属两个网络 - 用了
external: true却没提前docker network create mynet,导致 compose 启动失败
排查时优先跑 docker network inspect mynet | jq '.Containers',看目标容器 ID 是否在列表中——这是比查日志更快的验证手段。
自定义网络本身很简单,难的是理解“容器名 = DNS 记录”这个隐含契约,以及它只在同一个网络内生效。跨网络调用必须走 IP 或额外暴露端口,没有捷径。











