07 - 网络模型
07 - 网络模型
理解 Docker 的网络模式、容器间通信、端口映射与自定义网络配置。
7.1 Docker 网络基础
Docker 容器默认是网络隔离的,每个容器拥有独立的网络命名空间(Network Namespace)。
容器网络全景:
┌─────────────────────────────────────────────┐
│ 宿主机 (Host) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 容器 A │ │ 容器 B │ │ 容器 C │ │
│ │ 172.17 │ │ 172.17 │ │ 172.18 │ │
│ │ .0.2 │ │ .0.3 │ │ .0.2 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴──────────────┴───┐ ┌─────┴─────┐ │
│ │ docker0 (bridge) │ │ my-net │ │
│ │ 172.17.0.1 │ │ 172.18.0.1│ │
│ └───────────┬───────────┘ └─────┬─────┘ │
│ │ │ │
│ ┌────┴──────────────────────┴──┐ │
│ │ NAT / iptables │ │
│ └────────────┬─────────────────┘ │
│ │ │
│ 物理网卡 eth0 │
└──────────────────────┬──────────────────────┘
│
Internet
7.2 网络驱动类型
| 驱动 | 名称 | 说明 | 适用场景 |
|---|---|---|---|
| bridge | 桥接网络 | 默认模式,容器通过虚拟网桥通信 | 单机多容器 |
| host | 主机网络 | 容器直接使用宿主机网络栈 | 高性能需求 |
| overlay | 覆盖网络 | 跨主机容器通信 | Swarm/K8s 集群 |
| macvlan | MAC 地址分配 | 容器拥有独立 MAC 地址 | 需要直连物理网络 |
| none | 无网络 | 完全禁用网络 | 安全隔离场景 |
7.3 Bridge 网络(默认)
默认 bridge 网络
默认 bridge 网络:
┌─────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 容器 A │ │ 容器 B │ │ 容器 C │ │
│ │ eth0 │ │ eth0 │ │ eth0 │ │
│ │172.17.0.2│ │172.17.0.3│ │172.17.0.4│ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ veth-pair │ veth-pair │ │
│ ┌────┴──────────────┴──────────────┴───┐ │
│ │ docker0 (172.17.0.1) │ │
│ └──────────────────┬───────────────────┘ │
│ │ NAT │
│ 物理网卡 │
└─────────────────────┬───────────────────────┘
│
Internet
# 查看默认 bridge 网络
docker network ls
# 查看 bridge 网络详情
docker network inspect bridge
# 在默认 bridge 中运行容器
docker run -d --name web1 nginx:alpine
docker run -d --name web2 nginx:alpine
# 查看容器 IP
docker inspect --format '{{.NetworkSettings.IPAddress}}' web1
# 172.17.0.2
# 容器间通过 IP 通信
docker exec web1 ping 172.17.0.3
用户自定义 bridge 网络(推荐)
# 创建自定义 bridge 网络
docker network create my-net
# 创建指定子网和网关的网络
docker network create \
--driver bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.1 \
my-custom-net
# 在自定义网络中运行容器
docker run -d --name app --network my-net nginx:alpine
docker run -d --name db --network my-net postgres:16
# 自定义网络支持 DNS 解析(容器名即域名)
docker exec app ping db # ✅ 可以通过容器名解析
docker exec app ping db.my-net # 也可以用完整域名
默认 bridge vs 自定义 bridge
| 特性 | 默认 bridge | 自定义 bridge |
|---|---|---|
| DNS 解析 | ❌ 仅用 IP | ✅ 容器名即域名 |
| 自动连接 | ✅ 新容器自动加入 | ❌ 需指定 --network |
| 网络隔离 | 所有容器共享 | 按网络分组隔离 |
| 配置灵活性 | 有限 | 可自定义子网、网关等 |
| 推荐场景 | 临时测试 | 生产环境推荐 |
7.4 端口映射(Port Mapping)
基本语法
# 映射单个端口
docker run -d -p 8080:80 nginx:alpine
# 宿主机 8080 → 容器 80
# 映射多个端口
docker run -d -p 8080:80 -p 8443:443 nginx:alpine
# 指定绑定地址
docker run -d -p 127.0.0.1:8080:80 nginx:alpine
# 仅本机可访问
# 映射 UDP 端口
docker run -d -p 5353:53/udp dns-server:latest
# 随机分配宿主机端口
docker run -d -p 80 nginx:alpine
# 映射端口范围
docker run -d -p 8080-8085:80-85 my-app:latest
# 查看端口映射
docker port my-container
# 80/tcp -> 0.0.0.0:8080
端口映射原理
端口映射的底层机制 (iptables NAT):
外部请求 → 宿主机:8080
↓ iptables DNAT 规则
转发 → 172.17.0.2:80 (容器)
↓ 容器处理请求
响应 → 原路返回
查看 iptables 规则:
sudo iptables -t nat -L -n | grep 8080
7.5 Host 网络
# 使用 host 网络模式
docker run -d --network host nginx:alpine
# 容器直接使用宿主机网络,无需 -p 映射端口
# 容器内监听 80 端口 = 宿主机 80 端口
Host 网络模式:
┌──────────────────────────────┐
│ 宿主机网络栈 │
│ eth0: 192.168.1.100 │
│ ┌──────────────────────┐ │
│ │ 容器 (共享网络栈) │ │
│ │ nginx 监听 :80 │ │
│ │ = 宿主机 :80 │ │
│ └──────────────────────┘ │
└──────────────────────────────┘
| 优势 | 劣势 |
|---|---|
| 最高网络性能(无 NAT 开销) | 端口冲突风险 |
| 无需端口映射 | 失去网络隔离 |
| 延迟最低 | 无法限制容器网络访问 |
适用场景:对网络性能要求极高的场景,如监控 Agent、日志收集器。
7.6 None 网络
# 完全禁用网络
docker run -d --network none alpine:latest sleep 3600
# 验证:容器没有网络接口
docker exec <container_id> ip addr
# 只有 lo (loopback) 接口
适用场景:安全敏感的任务,如密码处理、密钥生成等。
7.7 Overlay 网络(跨主机通信)
Overlay 网络用于 Docker Swarm 集群中跨主机的容器通信。
Overlay 网络:
┌──────────── Host A ────────────┐ ┌──────────── Host B ────────────┐
│ │ │ │
│ ┌──────────┐ ┌──────────┐ │ │ ┌──────────┐ │
│ │ 容器 1 │ │ 容器 2 │ │ │ │ 容器 3 │ │
│ │10.0.0.2 │ │10.0.0.3 │ │ │ │10.0.0.4 │ │
│ └────┬─────┘ └────┬─────┘ │ │ └────┬─────┘ │
│ └──────┬───────┘ │ │ │ │
│ overlay 网络 │ │ overlay 网络 │
│ │ │ │ │ │
│ VXLAN 隧道 │ │ VXLAN 隧道 │
└──────────────┼────────────────┘ └────────┼────────────────────────┘
└────────────────────────────┘
物理网络
# 初始化 Swarm(必要前提)
docker swarm init
# 创建 overlay 网络
docker network create --driver overlay my-overlay
# 创建可被外部容器加入的 overlay 网络
docker network create --driver overlay --attachable my-attachable
# 在 Swarm 服务中使用
docker service create --name web --network my-overlay --replicas 3 nginx:alpine
7.8 Macvlan 网络
Macvlan 让容器拥有独立的 MAC 和 IP 地址,直接出现在物理网络上。
# 创建 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
my-macvlan
# 运行容器并分配静态 IP
docker run -d --name mv-web \
--network my-macvlan \
--ip 192.168.1.100 \
nginx:alpine
| 特性 | macvlan | bridge |
|---|---|---|
| 独立 IP | ✅ 物理网络分配 | 虚拟子网 |
| 独立 MAC | ✅ | ❌ |
| 性能 | 接近原生 | 有 NAT 开销 |
| 跨主机通信 | ✅ 无需 VXLAN | 需要 overlay |
| 使用难度 | 较高 | 简单 |
7.9 容器间通信
同一网络内通信
# 创建网络
docker network create app-net
# 运行应用容器和数据库容器
docker run -d --name app --network app-net my-app:v1
docker run -d --name db --network app-net -e POSTGRES_PASSWORD=secret postgres:16
# 容器间通过容器名通信
docker exec app ping db
docker exec app curl http://db:5432
跨网络通信
# 容器连接到多个网络
docker network create frontend
docker network create backend
docker run -d --name api --network frontend my-api:v1
docker run -d --name db --network backend postgres:16
# 将 API 容器连接到 backend 网络
docker network connect backend api
# 现在 api 可以访问 db
docker exec api ping db
# 断开网络
docker network disconnect backend api
多网络连接:
┌──────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────────────────┐ │
│ │ API 容器 │ │
│ │ eth0: frontend 网络 │ │
│ │ eth1: backend 网络 │ │
│ └────┬────────────┬────────┘ │
│ │ │ │
│ ┌────┴────┐ ┌────┴─────┐ │
│ │frontend │ │ backend │ │
│ │ 网络 │ │ 网络 │ │
│ └─────────┘ └────┬─────┘ │
│ │ │
│ ┌────┴────┐ │
│ │ DB │ │
│ └─────────┘ │
└──────────────────────────────────┘
7.10 DNS 与服务发现
# 自定义 DNS 服务器
docker run -d --dns 8.8.8.8 --dns 114.114.114.114 nginx:alpine
# 添加 DNS 搜索域
docker run -d --dns-search example.com nginx:alpine
# 添加 hosts 记录
docker run -d --add-host myhost:192.168.1.100 nginx:alpine
docker run -d --add-host host.docker.internal:host-gateway nginx:alpine
Docker 内置 DNS
Docker 内嵌 DNS 服务器 (127.0.0.11):
容器 A (app) 请求 "db"
↓
Docker DNS (127.0.0.11)
↓
解析为同一网络中的 db 容器 IP
↓
返回 172.18.0.3
7.11 网络管理命令
# 列出所有网络
docker network ls
# 查看网络详情
docker network inspect my-net
# 创建网络
docker network create \
--driver bridge \
--subnet 10.10.0.0/16 \
--ip-range 10.10.1.0/24 \
--opt "com.docker.network.bridge.name"="br-custom" \
custom-net
# 连接容器到网络
docker network connect my-net my-container
# 指定 IP 连接
docker network connect --ip 10.10.1.100 my-net my-container
# 断开网络
docker network disconnect my-net my-container
# 删除网络
docker network rm my-net
# 删除所有未使用的网络
docker network prune
# 删除指定时间前的未使用网络
docker network prune --filter "until=24h"
7.12 高级网络配置
自定义 docker0 网桥
// /etc/docker/daemon.json
{
"bip": "10.0.0.1/16",
"fixed-cidr": "10.0.0.0/16",
"default-address-pools": [
{ "base": "172.20.0.0/14", "size": 24 }
]
}
容器内抓包调试
# 获取容器的 namespace PID
PID=$(docker inspect --format '{{.State.Pid}}' my-container)
# 使用 nsenter 在容器网络中抓包
sudo nsenter -t $PID -n tcpdump -i eth0 -w /tmp/capture.pcap
# 或者在容器内安装 tcpdump
docker exec my-container apk add tcpdump
docker exec my-container tcpdump -i eth0 -c 10
要点回顾
| 要点 | 核心内容 |
|---|---|
| 网络模式 | bridge(默认)、host、overlay、macvlan、none |
| 自定义网络 | 推荐使用自定义 bridge,支持 DNS 容器名解析 |
| 端口映射 | -p 宿主机端口:容器端口,注意安全暴露 |
| 服务发现 | Docker 内置 DNS,容器名即域名 |
| 多网络 | 容器可连接多个网络,实现网络分层隔离 |
注意事项
端口安全:
-p 0.0.0.0:8080:80会将端口暴露给所有网络接口。生产环境建议限制绑定地址(如-p 127.0.0.1:8080:80)。
bridge 网络性能: bridge 模式有 NAT 开销。对延迟敏感的应用可考虑 host 模式。
Overlay 网络: 需要额外的 VXLAN 封装开销,且需要开放 UDP 4789 端口。
下一步
→ 08 - 数据持久化:学习 Docker 卷和数据管理策略。