📋 目录
核心概念
网络架构
容器网络通信
实战示例
常见问题
诊断命令
核心概念
1. Docker网络的三大组件
① 虚拟网卡对 (veth pair)
概念: 一对虚拟网卡,像一根虚拟网线连接容器和宿主机
1 2 3 4
| 容器内部 | 宿主机 | eth0 ←═══════════════════→ vethxxxxxx 172.18.0.5 | (连接到网桥)
|
特点:
查看命令:
1 2 3 4 5
| ip link show | grep veth
docker exec 容器名 ip addr show eth0
|
② 网桥 (Bridge)
概念: 虚拟的网络交换机,连接多个容器
1 2 3 4 5 6 7
| ┌─────────── 网桥 (br-abc123) ───────────┐ │ │ │ veth1234 ←→ veth5678 ←→ veth9abc │ │ │ │ │ │ └──────┼───────────┼───────────┼─────────┘ │ │ │ [容器A] [容器B] [容器C]
|
作用:
转发数据包(类似物理交换机)
维护MAC地址表
隔离不同网络的容器
查看命令:
1 2 3 4 5
| brctl show
docker network ls
|
③ 网络命名空间 (Network Namespace)
概念: 每个容器有独立的网络栈
1 2 3 4 5 6
| 容器A命名空间 容器B命名空间 ┌────────────┐ ┌────────────┐ │ 127.0.0.1 │ │ 127.0.0.1 │ ← 各自独立 │ eth0 │ │ eth0 │ │ 路由表 │ │ 路由表 │ └────────────┘ └────────────┘
|
隔离内容:
网络架构
Docker网络类型
1. bridge(默认网络)
特点:
所有 docker run 创建的容器默认加入
网桥名称:docker0
网段:通常 172.17.0.0/16
容器间可以通过IP互访,但不能用容器名
2. 自定义网络(推荐)
1 2 3 4 5
| docker network create my_network
docker-compose up
|
特点:
网桥名称:br-xxxxxxxx(随机ID)
可以自定义网段
容器间可以用容器名互访(内置DNS)
更好的隔离性
完整网络架构图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| ┌──────────────────────────────────────────────────────────────────┐ │ 宿主机 │ │ │ │ 物理网卡: ens20 (192.169.1.121) │ │ │ │ │ │ (外部流量) │ │ ↓ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ iptables / NAT 规则 │ │ │ │ 端口映射: -p 5001:5001 → 172.18.0.8:5001 │ │ │ └────────────────┬───────────────────────────────────┘ │ │ ↓ │ │ ╔═══════════════════════════════════════════════════╗ │ │ ║ docker0 网桥 (默认bridge) ║ │ │ ║ 172.17.0.0/16 ║ │ │ ║ ║ │ │ ║ veth001f34c ←→ [GWAgent容器] ║ │ │ ║ ↑ 172.17.0.2 ║ │ │ ║ 宿主机侧 容器内 eth0 ║ │ │ ╚═══════════════════════════════════════════════════╝ │ │ │ │ ╔═══════════════════════════════════════════════════╗ │ │ ║ br-43ebdd777e58 (docker_default) ║ │ │ ║ 172.18.0.0/16 ║ │ │ ║ ║ │ │ ║ veth510a281 ←→ [Dify-API] 172.18.0.8 ║ │ │ ║ veth0d9257b ←→ [Dify-DB] 172.18.0.9 ║ │ │ ║ vethae6b5f8 ←→ [Dify-Redis] 172.18.0.10 ║ │ │ ║ ... (更多容器) ║ │ │ ╚═══════════════════════════════════════════════════╝ │ │ │ │ ╔═══════════════════════════════════════════════════╗ │ │ ║ br-2d6e1e6b461e (ssrf_proxy_network) ║ │ │ ║ 172.19.0.0/16 ║ │ │ ║ ║ │ │ ║ veth236b89c ←→ [Proxy容器] ║ │ │ ║ vethf1c8fce ←→ [Dify-API的eth1] ← 多网卡! ║ │ │ ╚═══════════════════════════════════════════════════╝ │ └──────────────────────────────────────────────────────────────────┘
|
容器网络通信
场景1:同一网络内的容器通信(推荐)
1 2 3 4 5 6 7 8 9 10
| ┌─────────── docker_default 网络 ───────────┐ │ │ │ [GWAgent] 172.18.0.5 │ │ │ │ │ │ curl [http: │ ↓ │ │ 通过网桥转发 │ │ ↓ │ │ [Dify-API] 172.18.0.8:5001 │ └────────────────────────────────────────────┘
|
流量路径:
1 2 3 4 5 6 7 8 9
| GWAgent容器 (eth0: 172.18.0.5) ↓ 数据包发送到网桥 ↓ 网桥查MAC地址表 ↓ 转发到目标容器的veth ↓ Dify容器 (eth0: 172.18.0.8)
|
访问方式:
1 2 3 4 5 6 7 8
| curl [http://dify-api:5001/v1/workflows/run](http://dify-api:5001/v1/workflows/run)
curl [http://172.18.0.8:5001/v1/workflows/run](http://172.18.0.8:5001/v1/workflows/run)
curl [http://localhost:5001](http://localhost:5001/)
|
特点:
⚡ 速度最快(~1-2ms延迟)
🔒 内部隔离,外部无法直接访问
🚫 不经过宿主机网络协议栈
🚫 不经过NAT转换
场景2:跨网络容器通信(需要手动连接)
1 2 3 4 5 6
| ┌─── bridge网络 ───┐ ┌─── docker_default ───┐ │ │ │ │ │ [GWAgent] │ ✗ 不通 │ [Dify-API] │ │ 172.17.0.2 │ ←─────→ │ 172.18.0.8 │ │ │ │ │ └───────────────────┘ └───────────────────────┘
|
解决方案:把容器加入目标网络
1 2 3 4 5 6 7 8 9 10
| docker inspect dify-api | grep -A 10 Networks
docker network connect docker_default gwagent
docker exec gwagent ip addr
|
连接后的架构:
1 2 3 4 5 6 7 8 9
| ┌─── bridge网络 ───┐ ┌─── docker_default ───┐ │ │ │ │ │ [GWAgent] │ │ [GWAgent] ← 同一容器 │ eth0: 172.17.0.2 │ │ eth1: 172.18.0.5 │ │ │ │ │ │ └───────────────────┘ │ ↓ 可以访问 │ │ [Dify-API] │ │ 172.18.0.8 │ └───────────────────────┘
|
场景3:宿主机访问容器
方式A:直接访问容器IP
1 2
| curl [http://172.18.0.8:5001](http://172.18.0.8:5001/)
|
流量路径:
1 2 3 4 5 6 7 8 9
| 宿主机 ↓ 路由表判断: 172.18.0.8 在 br-43ebdd777e58 ↓ 发送到网桥 ↓ 网桥转发到目标veth ↓ 容器
|
特点:
✅ 简单直接
⚠️ 容器重启后IP可能变化
🔒 只能在宿主机本地访问
方式B:通过端口映射(对外暴露)
1
| docker run -p 5001:5001 dify-api
|
流量路径:
1 2 3 4 5 6 7 8 9 10 11
| 外部客户端 (192.169.1.100) ↓ 访问: [http: ↓ 宿主机物理网卡 (ens20) ↓ iptables NAT规则: 5001 → 172.18.0.8:5001 ↓ 网桥转发 ↓ 容器 (172.18.0.8:5001)
|
特点:
🌍 外部可访问
🐌 经过NAT,稍慢(~5-10ms)
🔓 需要考虑安全性
场景4:容器访问外部网络
1 2 3 4 5 6 7 8 9 10 11 12
| 容器 (172.18.0.8) ↓ 请求: [http: ↓ 网桥的默认网关 (172.18.0.1) ↓ iptables NAT (源地址转换) 172.18.0.8 → 192.169.1.121 ↓ 宿主机物理网卡 (ens20) ↓ 外部互联网
|
关键配置:
1 2 3 4 5
| iptables -t nat -L -n
|
实战示例
示例1:将GWAgent加入Dify网络
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| docker inspect dify-api | grep -A 10 '"Networks"'
docker network connect docker_default gwagent
docker exec gwagent ip addr
docker exec gwagent curl [http://dify-api:5001/v1/health](http://dify-api:5001/v1/health)
|
示例2:创建自定义网络并运行容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| docker network create \ --driver bridge \ --subnet 172.20.0.0/16 \ --gateway 172.20.0.1 \ my_custom_network
docker run -d \ --name app1 \ --network my_custom_network \ --ip 172.20.0.10 \ my_image
docker run -d \ --name app2 \ --network my_custom_network \ --ip 172.20.0.11 \ my_image
docker exec app1 ping app2 docker exec app1 curl [http://app2:8080](http://app2:8080/)
|
示例3:使用docker-compose管理网络
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| version: '3.8'
services: gwagent: image: gwagent:latest container_name: gwagent networks: - default
dify-api: image: dify-api:latest container_name: dify-api networks: - default - ssrf_proxy
dify-db: image: postgres:15 networks: - default
networks: default: driver: bridge ipam: config: - subnet: 172.18.0.0/16
ssrf_proxy: driver: bridge ipam: config: - subnet: 172.19.0.0/16
|
启动后的效果:
1 2 3 4 5 6 7 8 9
| docker-compose up -d
docker exec gwagent curl [http://dify-api:5000](http://dify-api:5000/)
docker exec dify-api ip addr
|
常见问题
Q1: 为什么 curl ``[localhost:5001](http://localhost:5001/) 访问不到其他容器?
答: [localhost](http://localhost/) / 127.0.0.1 永远指向容器自己
1 2 3 4 5 6 7 8 9 10 11 12
| ┌─────────────────────────────────────────┐ │ 容器内部 │ │ │ │ 127.0.0.1 ──→ 只能访问本容器 │ │ 172.18.0.8 ──→ 这才是对外的IP │ │ │ │ curl [http: │ → 访问本容器的5001端口 │ │ │ │ curl [http: │ → 访问其他容器 ✅ │ └─────────────────────────────────────────┘
|
Q2: 容器IP会变吗?
答: 会!容器重启后IP可能改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| docker run --name app nginx docker inspect app | grep IPAddress
docker restart app docker inspect app | grep IPAddress
docker rm -f app docker run --name app nginx docker inspect app | grep IPAddress
|
解决方案:
✅ 使用容器名(Docker DNS自动更新)
✅ 使用docker-compose指定固定IP
❌ 不要在代码里写死IP
Q3: 同一网络可以用IP访问吗?
答: 可以,但不推荐
1 2 3 4 5
| curl [http://172.18.0.8:5001](http://172.18.0.8:5001/)
curl [http://dify-api:5001](http://dify-api:5001/)
|
原因:
容器名稳定,IP可能变
容器名更易读
Docker DNS自动解析
Q4: 如何判断两个容器是否在同一网络?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| docker network inspect docker_default
docker inspect gwagent | grep -A 10 Networks docker inspect dify-api | grep -A 10 Networks
|
Q5: 容器能访问宿主机服务吗?
答: 可以,使用特殊的主机名
Linux (Docker 20.10+)
1 2 3 4 5
| curl [http://host.docker.internal:8080](http://host.docker.internal:8080/)
curl [http://172.18.0.1:8080](http://172.18.0.1:8080/)
|
查看网关IP
1 2
| docker network inspect docker_default | grep Gateway
|
诊断命令
1. 查看网络列表
1 2 3 4 5 6 7 8
| docker network ls
|
2. 查看网络详情
1 2 3 4 5 6
| docker network inspect docker_default
|
3. 查看容器的网络配置
1 2 3 4 5 6 7
| docker inspect 容器名 | grep -A 20 NetworkSettings
docker exec 容器名 ip addr docker exec 容器名 ip route docker exec 容器名 cat /etc/resolv.conf
|
4. 查看宿主机的网桥和veth
1 2 3 4 5 6 7 8 9 10
| brctl show
ip link show type bridge
ip addr show br-43ebdd777e58
ip link show | grep veth
|
5. 测试容器间连通性
1 2 3 4 5 6 7 8
| docker exec 容器A ping 容器B
docker exec 容器A curl [http://容器B:端口](http://xn--b-y59a66n/:端口)
docker exec 容器名 ip route
|
6. 查看网络流量(抓包)
1 2 3 4 5 6 7 8
| tcpdump -i br-43ebdd777e58 -nn
tcpdump -i veth510a281 -nn
tcpdump -i br-43ebdd777e58 port 5001 -nn
|
7. 查看iptables规则
1 2 3 4 5 6 7 8
| iptables -t nat -L -n -v
iptables -L FORWARD -n -v
iptables -t nat -L DOCKER -n
|
8. 排查网络问题的完整流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| docker inspect 容器名 | grep -A 10 Networks
docker network inspect 网络名
docker exec 容器名 nslookup 目标容器名 docker exec 容器名 cat /etc/resolv.conf
docker exec 容器名 ping 目标容器名 docker exec 容器名 curl [http://目标容器名:端口](http://xn--eqrr8cw6g8xo88r/:端口)
docker exec 容器名 ip addr docker exec 容器名 ip route
iptables -L -n | grep 容器IP
|
最佳实践
✅ DO(推荐)
使用自定义网络
使用容器名访问
使用docker-compose管理网络
只暴露必要的端口
❌ DON’T(避免)
不要使用默认bridge网络(容器无法用名称互访)
不要在代码里写死IP地址(IP会变)
不要使用 [localhost](http://localhost/) 访问其他容器
**不要暴露不必要的端口到 ****0.0.0.0**
总结
核心要点
每个容器都有独立的网络命名空间
veth pair 连接容器和宿主机
网桥负责转发同一网络的流量
同一网络的容器可以用容器名互访
不同网络的容器默认隔离
127.0.0.1** 永远只访问容器自己**
通信方式对比
文档生成时间: 2025-12-23
适用版本: Docker 20.10+