Docker: 容器间通信模式

最后更新:2026-08-26

容器不只是在自己的网络里运行——它们需要互相发现、互相通信。理解容器间通信模式是构建微服务架构的基础。

1. 你将学到


2. 一个微服务开发者的真实故事

(1) 痛点:三个微服务网络不通

Charlie 部署了三个微服务容器:API Gateway、用户服务和订单服务。API Gateway 能访问用户服务,但请求总是超时。排查了 2 小时后发现:API Gateway 暴露了端口但防火墙没开,用户服务用了错误的容器名,订单服务在不同的网络里。

(2) 系统化网络排查的解法

Bob 教他一套网络排查流程:容器名 → DNS → 网络 → 端口。

BASH
# Step 1: Verify DNS resolution
docker exec api nslookup user-service

# Step 2: Test network connectivity
docker exec api ping -c 2 user-service

# Step 3: Test port connectivity
docker exec api nc -zv user-service 8080

(3) 收益:网络排查从 2 小时→10 分钟

有了系统化的排查流程,Charlie 的网络问题排查时间从 2 小时降到 10 分钟。


3. 容器间通信三种方式

(1) 方式对比

100%
graph TB
    subgraph Method1["① --link (Legacy, Deprecated)"]
        L1["Container A"] -->|"env vars + /etc/hosts"| L2["Container B"]
    end
    subgraph Method2["② Custom Network + DNS (Recommended)"]
        D1["Container A"] -->|"DNS auto-resolve"| D2["Container B"]
    end
    subgraph Method3["③ Exposed Port + Host IP"]
        E1["Container A"] -->|"host:port"| E2["Container B<br/>(via host bridge)"]
    end
方式 原理 DNS 状态 推荐度
--link 环境变量 + hosts 注入 ❌ 废弃
自定义网络 DNS Docker 内置 DNS ✅ 推荐 ⭐⭐⭐
主机端口转发 容器→主机→容器 可用 ⭐⭐

BASH
# Legacy link: B can reach A by hostname
docker run -d --name db postgres:15-alpine
docker run -d --name web --link db:database nginx:alpine

# web can use "database" as hostname (via /etc/hosts)
docker exec web cat /etc/hosts
⚠️ 注意: --link 已废弃,仅用于理解历史。它只支持单向连接(web→db,不能 db→web),且容器重启后 IP 变化时 hosts 文件不更新。始终用自定义网络替代。**


5. 自定义网络 DNS 详解

(1) DNS 解析流程

100%
graph LR
    A["Container A<br/>ping db"] --> B["Docker DNS<br/>127.0.0.11"]
    B -->|db → 172.18.0.2| C["Container B<br/>172.18.0.2"]

▶ 示例:--network-alias 设置别名(难度⭐⭐)

BASH
# Start container with network alias
docker run -d --name my-postgres \
  --network app-net \
  --network-alias=database \
  --network-alias=db \
  postgres:15-alpine

# Both names resolve to the same container
docker exec api ping -c 1 database  # resolves to my-postgres
docker exec api ping -c 1 db        # same IP

(1) 容器名 vs 网络别名

方式 定义 作用域 优先级
--name 容器名 所有网络
--network-alias 网络别名 仅指定网络
Docker Compose service 名 服务名 Compose 网络
💡 提示: --network-alias 允许同一容器在不同网络中有不同名字。例如数据库在 backend-net 中叫 primary-db,在 admin-net 中叫 database


6. 端口暴露策略

(1) --expose vs -p vs -P

参数 作用 外部可访问 适用场景
--expose 3306 声明端口(文档) ❌ 不映射 容器间通信
-p 3306:3306 映射到主机 ✅ 外部可访问 对外服务
-P 随机映射 EXPOSE 端口 ✅ 随机端口 开发调试

▶ 示例:docker port 查看映射(难度⭐)

BASH
# Check port mappings for a container
docker port web

# Output example
80/tcp -> 0.0.0.0:8080

7. 网络故障排查

(1) 排查决策树

100%
graph TB
    START["Container A<br/>cannot reach Container B"] --> DNS{"DNS 解析?"}
    DNS -->|失败| FIX1["同一自定义网络?<br/>用 --name 或 --network-alias"]
    DNS -->|成功| PING{"Ping 通?"}
    PING -->|失败| FIX2["同一网络?<br/>docker network connect"]
    PING -->|成功| PORT{"端口通?<br/>nc -zv B port"]
    PORT -->|失败| FIX3["端口暴露?<br/>B 是否监听正确端口?"]
    PORT -->|成功| APP{"应用协议?<br/>curl/wget 测试"]
    APP -->|失败| FIX4["检查应用配置<br/>环境变量/URL"]
    APP -->|成功| OK["✅ 通信正常"]

▶ 示例:容器内网络排查命令(难度⭐⭐)

BASH
# Step 1: Check DNS resolution
docker exec api nslookup db
docker exec api getent hosts db

# Step 2: Test basic connectivity
docker exec api ping -c 2 db

# Step 3: Test specific port
docker exec api nc -zv db 5432
# or with wget
docker exec api wget -qO- http://api:8080/health

# Step 4: Check container's network interfaces
docker exec api ip addr

# Step 5: Check routing table
docker exec api ip route

▶ 示例:docker network connect 动态加入网络(难度⭐⭐)

BASH
# Connect a running container to another network
docker network connect backend-net web

# Disconnect from a network
docker network disconnect frontend-net web

# Verify container's networks
docker inspect web --format='{{json .NetworkSettings.Networks}}' | python3 -m json.tool

8. 安全组隔离设计

(1) 三层隔离模型

网络层 容器 可访问 对外端口
Frontend Net Nginx/CDN Backend Net only 80, 443
Backend Net API/Worker DB Net only 无(通过 Nginx 代理)
DB Net PostgreSQL/Redis 无外部访问
🔒 安全: 数据库只在 DB Net 中,Frontend 容器无法直接访问数据库——必须经过 Backend API。这是"最小权限网络"原则。


9. 完整示例:微服务网络配置与排查

BASH
# ============================================
# Complete walkthrough: Microservice networking
# Covers: networks, aliases, isolation, debugging
# ============================================

# 1. Create isolated networks
docker network create frontend-net
docker network create backend-net
docker network create db-net

# 2. Start database (db-net only)
docker run -d --name postgres \
  --network db-net \
  --network-alias=database \
  --network-alias=primary-db \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  postgres:15-alpine

# 3. Start API server (backend-net + db-net)
docker run -d --name api \
  --network backend-net \
  --network-alias=api-server \
  -e DATABASE_URL="postgresql://postgres:secret@primary-db:5432/myapp" \
  myapp-api:1.0

docker network connect db-net api

# 4. Start Nginx (frontend-net + backend-net)
docker run -d --name nginx \
  --network frontend-net \
  --network-alias=gateway \
  -p 8080:80 \
  nginx:1.25-alpine

docker network connect backend-net nginx

# 5. Debug: verify connectivity
echo "=== DNS Resolution ==="
docker exec nginx nslookup api-server
docker exec api nslookup primary-db

echo "=== Port Connectivity ==="
docker exec nginx nc -zv api-server 5000
docker exec api nc -zv primary-db 5432

echo "=== Isolation Check ==="
docker exec nginx sh -c "timeout 2 nc -zv primary-db 5432 2>&1 || echo 'BLOCKED: nginx cannot reach db directly (expected)'"

# 6. Clean up
docker stop postgres api nginx
docker rm postgres api nginx
docker network rm frontend-net backend-net db-net

❓ 常见问题

Q --link 已经废弃了吗?
A 是的。Docker 官方明确废弃了 --link,推荐用自定义网络 + DNS。--link 的问题:单向连接、重启后 IP 不更新、不支持 Compose。自定义网络解决了所有这些问题。
Q 容器名在不同网络间唯一吗?
A 容器名在 Docker 主机全局唯一。但 DNS 解析是网络级别的——只有同一网络中的容器才能通过容器名互相解析。跨网络用 docker network connect 加入后才能解析。
Q 怎么让容器只能被特定容器访问?
A 用网络隔离。把被保护的服务(如数据库)放在专用网络中,只有需要访问的容器才加入该网络。例如数据库在 db-net,只有 API 加入 db-net,Nginx 无法直接访问数据库。
Q 容器 DNS 超时怎么办?
A DNS 超时通常因为:① 容器不在同一网络(最常见);② 容器名拼错;③ DNS 缓存问题(重启容器解决)。排查:docker exec <container> nslookup <target> 看解析结果。
Q 怎么看到容器的实际 IP?
A docker inspect <container> --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'。或进入容器执行 ip addr / hostname -I。但记住:IP 可能变,生产代码用容器名而不是 IP。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建两个自定义网络,各启动一个容器,验证同网络容器名 DNS 解析正常。
  2. 进阶题(难度⭐⭐):验证跨网络容器无法 ping 通,然后用 docker network connect 连通,再断开。
  3. 挑战题(难度⭐⭐⭐):用 docker exec + nc / wget 排查一个容器无法访问另一个容器服务的根因,写出排查步骤和结论。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏