第07章:Docker 网络模型
本章目标:理解 Docker 的四种网络模式,掌握容器间通信、DNS 解析和自定义网络的配置方法。
7.1 Docker 网络架构概览
7.1.1 网络层次
┌────────────────────────────────────────────────────────┐
│ Docker 网络层次 │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 应用层(容器内) │ │
│ │ App A (port 80) App B (port 8080) App C (...) │ │
│ └──────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌──────────────────────┴───────────────────────────┐ │
│ │ 网络抽象层(libnetwork) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ bridge │ │ host │ │ none │ ... │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌──────────────────────┴───────────────────────────┐ │
│ │ 系统层(Linux Kernel) │ │
│ │ Network Namespaces / veth pairs / iptables │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
7.1.2 查看网络
bash
# 列出所有 Docker 网络
docker network ls
# NETWORK ID NAME DRIVER SCOPE
# abc123def456 bridge bridge local
# def456abc123 host host local
# ghi789jkl012 none null local
# 查看网络详细信息
docker network inspect bridge
# 查看容器的网络配置
docker inspect --format='{{json .NetworkSettings.Networks}}' <container>
7.2 四种网络模式详解
7.2.1 bridge(桥接网络)------ 默认模式
bridge 网络原理:
┌─────────────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────┐│
│ │ 容器 A │ │ 容器 B │ │ 容器 C ││
│ │ eth0 │ │ eth0 │ │ eth0 ││
│ │ 172.17.0.2 │ │ 172.17.0.3 │ │ 172.17.0.4││
│ └──────┬───────┘ └──────┬───────┘ └─────┬─────┘│
│ │ │ │ │
│ ┌────┴─────────────────┴─────────────────┴────┐ │
│ │ docker0 网桥 │ │
│ │ 172.17.0.1 │ │
│ └──────────────────────┬───────────────────────┘ │
│ │ │
│ ┌──────────────────────┴───────────────────────┐ │
│ │ eth0 (宿主机网卡) │ │
│ │ 192.168.1.100 │ │
│ └──────────────────────┬───────────────────────┘ │
│ │ │
└───────────────────────────┼──────────────────────────┘
│
┌────┴────┐
│ 路由器 │
└────┬────┘
│
┌────┴────┐
│ 互联网 │
└─────────┘
bash
# 使用默认 bridge 网络
docker run -d --name web1 nginx
docker run -d --name web2 nginx
# 查看容器 IP
docker inspect --format='{{.NetworkSettings.IPAddress}}' web1
# 172.17.0.2
docker inspect --format='{{.NetworkSettings.IPAddress}}' web2
# 172.17.0.3
# 默认 bridge 网络的限制:
# 1. 容器间不能通过名称互相访问(只能用 IP)
# 2. 需要手动配置端口映射
# 3. 所有容器共享同一个 bridge 网络
7.2.2 host(主机网络)
host 网络原理:
┌──────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 容器 A │ │ 容器 B │ │
│ │ (使用宿主机 │ │ (使用宿主机 │ │
│ │ 网络栈) │ │ 网络栈) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ └────────┬────────┘ │
│ │ │
│ ┌───────────────┴──────────────────────────┐│
│ │ eth0 (宿主机网卡) ││
│ │ 192.168.1.100 ││
│ └───────────────┬──────────────────────────┘│
│ │ │
└──────────────────┼─────────────────────────────┘
│
┌────┴────┐
│ 路由器 │
└─────────┘
bash
# 使用 host 网络
docker run -d --network host --name web nginx
# 容器直接使用宿主机的网络
# Nginx 监听宿主机的 80 端口
# 访问宿主机 IP:80 即可访问
# 查看容器网络
docker inspect --format='{{.NetworkSettings.Networks}}' web
# map[host:0xc000123456]
# host 网络的特点:
# ✅ 性能最好(没有 NAT 转换)
# ✅ 网络配置简单
# ❌ 端口冲突风险(多个容器不能监听同一端口)
# ❌ 网络隔离性差
7.2.3 none(无网络)
bash
# 使用 none 网络(完全隔离)
docker run -d --network none --name isolated nginx
# 容器只有 loopback 接口
docker exec isolated ip addr
# 1: lo: <LOOPBACK,UP,LOWER_UP> ...
# inet 127.0.0.1/8 scope host lo
# none 网络的适用场景:
# 1. 安全敏感的应用(完全网络隔离)
# 2. 不需要网络的批处理任务
# 3. 自定义网络配置
7.2.4 overlay(覆盖网络)
overlay 网络原理(跨主机通信):
┌────────────────────────────┐ ┌────────────────────────────┐
│ 主机 A │ │ 主机 B │
│ │ │ │
│ ┌──────────┐ ┌──────────┐│ │ ┌──────────┐ ┌──────────┐│
│ │ 容器 A │ │ 容器 B ││ │ │ 容器 C │ │ 容器 D ││
│ │(overlay) │ │(overlay) ││ │ │(overlay) │ │(overlay) ││
│ └────┬─────┘ └────┬─────┘│ │ └────┬─────┘ └────┬─────┘│
│ │ │ │ │ │ │ │
│ ┌────┴─────────────┴────┐ │ │ ┌────┴─────────────┴────┐ │
│ │ overlay network │◄├──┤►│ overlay network │ │
│ │ 10.0.0.0/24 │ │ │ │ 10.0.0.0/24 │ │
│ └───────────┬───────────┘ │ │ └───────────┬───────────┘ │
│ │ │ │ │ │
│ ┌───────────┴───────────┐ │ │ ┌───────────┴───────────┐ │
│ │ docker_gwbridge │ │ │ │ docker_gwbridge │ │
│ │ 172.18.0.0/16 │ │ │ │ 172.18.0.0/16 │ │
│ └───────────┬───────────┘ │ │ └───────────┬───────────┘ │
│ │ │ │ │ │
│ ┌───────────┴───────────┐ │ │ ┌───────────┴───────────┐ │
│ │ eth0 │◄├──┤►│ eth0 │ │
│ │ 192.168.1.101 │ │ │ │ 192.168.1.102 │ │
│ └───────────────────────┘ │ │ └───────────────────────┘ │
└────────────────────────────┘ └────────────────────────────┘
bash
# 创建 swarm 集群(overlay 需要 swarm 模式)
docker swarm init
# 创建 overlay 网络
docker network create -d overlay my-overlay
# 在 swarm 服务中使用 overlay 网络
docker service create --name web --network my-overlay nginx
# overlay 网络的特点:
# ✅ 支持跨主机容器通信
# ✅ 自动 DNS 解析
# ✅ 支持服务发现
# ❌ 需要 Docker Swarm 或外部存储(如 Consul)
7.2.5 macvlan(MAC 地址虚拟化)
bash
# macvlan 让容器拥有独立的 MAC 地址
# 容器在网络中就像独立的物理设备
# 创建 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
my-macvlan
# 使用 macvlan 网络
docker run -d --network my-macvlan --ip 192.168.1.100 --name web nginx
# macvlan 的特点:
# ✅ 容器有独立的 IP 和 MAC 地址
# ✅ 性能好(无 NAT)
# ❌ 需要物理网络支持
# ❌ 配置复杂
7.3 自定义网络
7.3.1 创建自定义网络
bash
# 创建 bridge 类型的自定义网络
docker network create my-network
# 创建并配置参数
docker network create \
--driver bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.1 \
--ip-range 192.168.100.0/25 \
--opt "com.docker.network.bridge.name"="my-bridge" \
my-network
# 查看网络详情
docker network inspect my-network
7.3.2 自定义网络的优势
bash
# 1. 自动 DNS 解析(关键优势!)
docker network create my-net
docker run -d --name web-server --network my-net nginx
docker run -d --name app-server --network my-net myapp
# app-server 容器内可以直接通过 "web-server" 名称访问
# curl http://web-server:80 ✅ 自动解析!
# 2. 更好的隔离性
docker network create net-a
docker network create net-b
docker run -d --name web --network net-a nginx
docker run -d --name app --network net-b myapp
# web 和 app 互相隔离,不能通信
# 3. 灵活的网络配置
docker network create \
--subnet 10.10.0.0/16 \
--ipv6 \
my-network-v6
7.3.3 将容器连接到多个网络
bash
# 一个容器可以连接到多个网络
docker network create front-net
docker network create back-net
docker run -d --name web --network front-net nginx
docker run -d --name app --network back-net myapp
# 动态添加网络连接
docker network connect back-net web
# 现在 web 同时连接 front-net 和 back-net
# web 可以与两个网络中的容器通信
# 动态断开网络连接
docker network disconnect back-net web
7.4 容器 DNS 解析
7.4.1 自定义网络中的 DNS
bash
# 创建自定义网络
docker network create app-net
# 启动多个容器
docker run -d --name db --network app-net mysql:8.0
docker run -d --name redis --network app-net redis:7
docker run -d --name web --network app-net myapp
# 在 web 容器中可以直接使用容器名访问
docker exec web ping db # ✅ 解析到 db 容器的 IP
docker exec web ping redis # ✅ 解析到 redis 容器的 IP
# 还可以使用网络别名
docker run -d --name db-primary --network app-net \
--network-alias primary-db \
mysql:8.0
# 使用别名访问
docker exec web ping primary-db # ✅ 解析到 db-primary 容器
7.4.2 DNS 配置
bash
# 自定义 DNS 服务器
docker run -d --dns 8.8.8.8 --dns 8.8.4.4 nginx
# 自定义 DNS 搜索域
docker run -d --dns-search example.com nginx
# 自定义 hosts 文件
docker run -d --add-host myhost:192.168.1.100 nginx
# 查看容器的 DNS 配置
docker exec <container> cat /etc/resolv.conf
7.5 端口映射详解
7.5.1 端口映射语法
bash
# 基本语法
docker run -d -p <host_port>:<container_port> nginx
# 多端口映射
docker run -d \
-p 80:80 \
-p 443:443 \
-p 8080:8080 \
nginx
# 指定协议
docker run -d -p 80:80/tcp -p 80:80/udp nginx
# 指定绑定地址
docker run -d -p 127.0.0.1:8080:80 nginx # 仅本机访问
docker run -d -p 0.0.0.0:8080:80 nginx # 所有地址(默认)
docker run -d -p 192.168.1.100:8080:80 nginx # 指定网卡
# 随机端口
docker run -d -P nginx # 映射 EXPOSE 的所有端口
docker run -d -p 80 nginx # 主机随机端口 → 容器 80
# 查看端口映射
docker port <container>
# 80/tcp -> 0.0.0.0:8080
7.5.2 端口映射的实现原理
端口映射底层原理(iptables):
宿主机 容器
┌─────────────────────┐ ┌─────────────────┐
│ │ │ │
│ 访问 localhost:8080 │ │ nginx:80 │
│ │ │ │ ▲ │
│ ▼ │ │ │ │
│ iptables DNAT │ │ docker0 网桥 │
│ 8080 → 172.17.0.2:80│ ──────► │ 172.17.0.2 │
│ │ │ │
└─────────────────────┘ └─────────────────┘
DNAT (Destination Network Address Translation)
目标网络地址转换:将访问宿主机 8080 端口的流量转发到容器的 80 端口
bash
# 查看 iptables 规则(了解底层原理)
sudo iptables -t nat -L -n | grep 8080
# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
7.6 容器间通信实战
7.6.1 同一网络中的容器通信
bash
# 创建应用网络
docker network create app-net
# 启动 MySQL 数据库
docker run -d \
--name mysql-db \
--network app-net \
-e MYSQL_ROOT_PASSWORD=secret123 \
-e MYSQL_DATABASE=myapp \
mysql:8.0
# 启动 Redis 缓存
docker run -d \
--name redis-cache \
--network app-net \
redis:7
# 启动应用
docker run -d \
--name web-app \
--network app-net \
-p 8080:8080 \
-e DB_HOST=mysql-db \
-e DB_PORT=3306 \
-e REDIS_HOST=redis-cache \
-e REDIS_PORT=6379 \
myapp:latest
# 在 web-app 容器内测试连接
docker exec web-app ping mysql-db # ✅
docker exec web-app ping redis-cache # ✅
7.6.2 跨网络通信
bash
# 创建前后端网络
docker network create frontend
docker network create backend
# 启动 Nginx(前端)
docker run -d \
--name nginx \
--network frontend \
-p 80:80 \
nginx
# 启动应用(前后端都连接)
docker run -d \
--name api-server \
--network backend \
myapi:latest
# 将 nginx 连接到 backend 网络
docker network connect backend nginx
# 现在 nginx 可以通过 api-server:8080 访问后端
# 但外部网络只能访问 nginx,无法直接访问 api-server
7.7 网络故障排查
7.7.1 常用排查命令
bash
# 1. 查看容器网络配置
docker inspect --format='{{json .NetworkSettings}}' <container>
# 2. 进入容器检查网络
docker exec -it <container> ip addr
docker exec -it <container> ip route
docker exec -it <container> cat /etc/resolv.conf
# 3. 测试网络连通性
docker exec -it <container> ping <target>
docker exec -it <container> curl -v http://<target>:<port>
# 4. 查看 Docker 网络
docker network ls
docker network inspect <network>
# 5. 查看 iptables 规则
sudo iptables -t nat -L -n
sudo iptables -L -n
7.7.2 常见网络问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 容器间无法通信 | 不在同一网络 | 连接到同一网络 |
| 无法通过名称访问 | 使用了默认 bridge | 使用自定义网络 |
| 端口映射不生效 | 防火墙/iptables | 检查防火墙规则 |
| DNS 解析失败 | DNS 配置错误 | 检查 /etc/resolv.conf |
| 容器无法上网 | 网络配置问题 | 检查网桥和路由 |
7.8 动手实验
实验 7.1:网络模式对比
bash
# 1. bridge 模式(默认)
docker run -d --name bridge-test nginx
docker inspect --format='{{.NetworkSettings.Networks}}' bridge-test
# map[bridge:...]
# 2. host 模式
docker run -d --name host-test --network host nginx
docker inspect --format='{{.NetworkSettings.Networks}}' host-test
# map[host:...]
# 3. none 模式
docker run -d --name none-test --network none nginx
docker exec none-test ip addr
# 只有 lo 接口
# 清理
docker rm -f bridge-test host-test none-test
实验 7.2:自定义网络 DNS 解析
bash
# 1. 创建自定义网络
docker network create demo-net
# 2. 启动服务器容器
docker run -d --name server1 --network demo-net nginx
docker run -d --name server2 --network demo-net nginx
# 3. 在 server1 中测试 DNS 解析
docker exec server1 ping server2
# PING server2 (172.18.0.3): 56 data bytes
# 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.089 ms
# 4. 使用网络别名
docker run -d --name server3 --network demo-net --network-alias myserver nginx
docker exec server1 ping myserver
# ✅ 解析到 server3
# 清理
docker rm -f server1 server2 server3
docker network rm demo-net
实验 7.3:端口映射
bash
# 1. 多端口映射
docker run -d --name multi-port \
-p 8080:80 \
-p 8443:443 \
-p 8081:8080 \
nginx
# 2. 查看端口映射
docker port multi-port
# 80/tcp -> 0.0.0.0:8080
# 443/tcp -> 0.0.0.0:8443
# 8080/tcp -> 0.0.0.0:8081
# 3. 测试访问
curl http://localhost:8080
curl https://localhost:8443 -k
# 清理
docker rm -f multi-port
7.9 本章小结
| 网络模式 | 特点 | 适用场景 |
|---|---|---|
| bridge | 默认模式,NAT 转换 | 单机多容器 |
| host | 共享宿主机网络栈 | 高性能需求 |
| none | 完全隔离 | 安全敏感场景 |
| overlay | 跨主机通信 | Swarm/Kubernetes |
| macvlan | 独立 MAC 地址 | 需要独立 IP 的场景 |
7.10 课后练习
- 基础题:创建自定义网络,启动两个容器,验证 DNS 解析功能。
- 进阶题:配置前后端分离的应用网络(frontend + backend)。
- 排错题:故意制造网络故障(断开网络、修改 DNS),练习排查步骤。
📖 下一章:Docker 数据持久化 ------ 掌握容器数据的存储和管理