07 - Docker网络¶
本章核心: 理解Docker网络模型,掌握容器间通信和网络配置
📖 章节导航¶
前序章节: 05-网络模式详解.md → 06-云服务与CDN.md 后续章节: 08-实战应用场景.md → 09-AI网络专题.md 快速参考: 网络工具箱.md 第1章 故障排查: 故障排查手册.md 第3章
📚 目录¶
1. 引言¶
🎯 为什么需要理解Docker网络?¶
想象一下,你在开发一个Web应用,它由多个服务组成: - 一个前端服务(React应用) - 一个后端API服务(Node.js) - 一个数据库服务(MySQL) - 一个缓存服务(Redis)
这些服务需要相互通信才能正常工作。Docker网络就是让这些容器能够安全、高效地相互通信的机制。
理解Docker网络的重要性:
✅ 容器间通信:让不同的容器能够互相访问和交换数据 ✅ 服务部署:在生产环境中正确配置服务之间的连接 ✅ 网络隔离:保证不同应用或环境的网络安全性 ✅ 性能优化:合理配置网络可以提高应用性能 ✅ 故障排查:当出现网络问题时,能够快速定位和解决
💡 简单类比¶
把Docker网络想象成一个公司的内部电话系统: - 每个容器就像一个员工 - Docker网络就像公司的电话交换机 - 网络驱动就像不同的电话线路类型(内线、外线、专线等) - 端口映射就像设置分机号码
2. Docker网络基础¶
🌐 Docker网络的作用和重要性¶
Docker网络的核心作用是解决容器之间的通信问题。默认情况下,每个容器都有自己的独立网络空间,就像每个员工有自己的办公室一样。
主要功能:
- 容器互联:让容器之间可以互相访问
- 外部访问:允许外部网络访问容器服务
- 网络隔离:将不同的应用隔离开来
- 跨主机通信:支持容器在不同主机间通信
🔒 容器与宿主机的网络隔离¶
Docker使用网络命名空间(Network Namespace)来实现网络隔离。这意味着:
┌─────────────────────────────────────────┐
│ 宿主机网络空间 │
│ IP: 192.168.1.100 │
│ ┌───────────────────────────────────┐ │
│ │ 容器A网络空间 │ │
│ │ IP: 172.17.0.2 │ │
│ │ 完全隔离的网络环境 │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────┐ │
│ │ 容器B网络空间 │ │
│ │ IP: 172.17.0.3 │ │
│ │ 完全隔离的网络环境 │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
隔离的好处: - 安全性:不同容器互不干扰 - 灵活性:每个容器可以有不同的网络配置 - 可移植性:容器在任何主机上都能保持相同的网络配置
🏗️ Docker网络架构(CNM:Container Network Model)¶
Docker使用容器网络模型(Container Network Model)来管理网络。CNM由三个核心组件组成:
┌─────────────────────────────────────────────────┐
│ CNM 架构 │
├─────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Sandbox │ │Network │ │
│ │ (容器) │◄────────┤ (网络) │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ │ │ │
│ │ ┌─────────▼──────┐ │
│ └────────►│ Endpoint │ │
│ │ (网络端点) │ │
│ └────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
CNM三大组件:
- Sandbox(沙箱)
- 代表一个容器的网络栈
- 包含网络接口、路由表、DNS配置等
-
每个容器有自己的Sandbox
-
Endpoint(端点)
- 连接Sandbox和Network的桥梁
-
类似于网络插头,将容器连接到网络
-
Network(网络)
- 一组可以相互通信的Endpoint
- 由Driver(驱动)管理
- 可以是Bridge、Overlay、Macvlan等类型
3. Docker网络驱动¶
Docker支持多种网络驱动,每种驱动适用于不同的场景:
🌉 1. Bridge驱动(默认桥接网络)¶
特点: - ✅ Docker默认网络模式 - ✅ 适合单主机上的容器通信 - ✅ 通过NAT访问外网 - ❌ 不支持跨主机通信
使用场景: - 开发环境 - 单机部署的微服务 - 需要容器间通信的应用
┌──────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ docker0 网桥 │ │
│ │ IP: 172.17.0.1 │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 容器A │ │ 容器B │ │ │
│ │ │.2 │ │.3 │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────┘ │
│ │
│ 通过NAT访问外网 │
└──────────────────────────────────────────────┘
🏠 2. Host驱动(使用宿主机网络)¶
特点: - ✅ 容器使用宿主机的网络栈 - ✅ 性能最好(无网络开销) - ✅ 端口直接暴露 - ❌ 网络隔离性差 - ❌ 端口冲突风险高
使用场景: - 网络性能要求极高的应用 - 需要直接访问宿主机网络接口的服务 - 监控和日志收集工具
网络结构:
┌──────────────────────────────────────┐
│ 宿主机网络 │
│ │
│ ┌──────────────────────────────┐ │
│ │ 容器(共享宿主机网络) │ │
│ │ 使用相同的IP和端口 │ │
│ └──────────────────────────────┘ │
│ │
│ 直接使用宿主机的网络接口 │
└──────────────────────────────────────┘
🚫 3. None驱动(无网络)¶
特点: - ✅ 完全隔离的网络环境 - ✅ 安全性最高 - ❌ 无法访问外网 - ❌ 无法与其他容器通信
使用场景: - 高安全性的批处理任务 - 不需要网络的数据处理 - 离线计算任务
网络结构:
┌──────────────────────────────────────┐
│ 宿主机网络 │
│ │
│ ┌──────────────────────────────┐ │
│ │ 容器(无网络) │ │
│ │ 只有lo回环接口 │ │
│ └──────────────────────────────┘ │
│ │
│ 完全隔离,无网络连接 │
└──────────────────────────────────────┘
🌐 4. Overlay驱动(跨主机网络)¶
特点: - ✅ 支持跨主机容器通信 - ✅ 适合分布式系统 - ✅ 自动加密通信 - ❌ 配置相对复杂 - ❌ 需要额外的键值存储(如etcd、Consul)
使用场景: - Docker Swarm集群 - Kubernetes环境 - 分布式微服务架构
┌──────────────────────┐ ┌──────────────────────┐
│ 主机A │ │ 主机B │
│ │ │ │
│ ┌──────────────┐ │ │ ┌──────────────┐ │
│ │ 容器A1 │ │ │ │ 容器B1 │ │
│ │ 10.0.0.2 │ │ │ │ 10.0.0.3 │ │
│ └──────┬───────┘ │ │ └──────┬───────┘ │
│ │ │ │ │ │
│ ┌──────▼───────┐ │ │ ┌──────▼───────┐ │
│ │ Overlay网络 │◄─┼────────┼──►│ Overlay网络 │ │
│ └──────────────┘ │ │ └──────────────┘ │
│ │ │ │
└──────────────────────┘ └──────────────────────┘
│ │
└──────── 物理网络 ──────────────┘
📡 5. Macvlan驱动(物理网络接口)¶
特点: - ✅ 容器拥有独立的MAC地址 - ✅ 直接连接到物理网络 - ✅ 性能接近原生网络 - ❌ 需要物理网络支持 - ❌ 配置复杂度高
使用场景: - 需要直接接入物理网络的容器 - 传统应用迁移到容器 - 网络监控和管理工具
# 创建macvlan网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 my-macvlan-net
网络结构:
┌──────────────────────────────────────────┐
│ 物理网络 │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 容器A │ │ 容器B │ │
│ │MAC:AA:BB │ │MAC:CC:DD │ │
│ │IP: .100 │ │IP: .101 │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ 物理交换机 │ │
│ └─────────────┘ │
└──────────────────────────────────────────┘
📊 网络驱动对比表¶
| 驱动类型 | 适用场景 | 优点 | 缺点 | 跨主机 |
|---|---|---|---|---|
| Bridge | 单机开发部署 | 简单易用,默认支持 | 性能一般 | ❌ |
| Host | 高性能需求 | 性能最好,无开销 | 隔离性差 | ❌ |
| None | 离线任务 | 安全性高 | 无法联网 | ❌ |
| Overlay | 分布式集群 | 跨主机通信 | 配置复杂 | ✅ |
| Macvlan | 物理网络集成 | 直接接入物理网络 | 需要网络支持 | ✅ |
4. Bridge网络详解¶
🔍 Bridge网络的工作原理¶
Bridge网络是Docker最常用的网络模式,它使用Linux网桥技术来实现容器间的通信。
工作原理:
┌────────────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ docker0 网桥 │ │
│ │ (虚拟交换机) │ │
│ │ IP: 172.17.0.1/16 │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │veth1 │ │veth2 │ │ │
│ │ │(虚拟网卡) │ │(虚拟网卡) │ │ │
│ │ └────┬─────┘ └────┬─────┘ │ │
│ │ │ │ │ │
│ └────────┼───────────────┼────────────────┘ │
│ │ │ │
│ │ │ │
│ ┌────────▼─────┐ ┌─────▼────────┐ │
│ │ 容器A │ │ 容器B │ │
│ │ eth0 │ │ eth0 │ │
│ │ 172.17.0.2 │ │ 172.17.0.3 │ │
│ └───────────────┘ └───────────────┘ │
│ │
│ 通过NAT规则访问外网 │
└────────────────────────────────────────────────────┘
通信流程:
- 容器创建时:Docker为每个容器创建一对虚拟网卡(veth pair)
- 一端在容器内:命名为
eth0,容器使用它进行网络通信 - 一端在宿主机:连接到
docker0网桥 - 容器间通信:通过
docker0网桥进行二层转发 - 访问外网:通过宿主机的NAT规则进行地址转换
🌉 docker0网桥的作用¶
docker0是Docker默认创建的网桥,它就像一个虚拟的交换机:
主要功能:
- 连接容器:将所有容器连接到同一个虚拟网络
- IP分配:为容器分配IP地址
- 数据转发:在容器之间转发数据包
- NAT网关:作为容器访问外网的网关
查看docker0信息:
# 查看网桥信息
ip addr show docker0
# 输出示例:
# 4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
# link/ether 02:42:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
# inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
📝 容器IP地址分配¶
Docker使用IPAM(IP Address Management)来管理IP地址分配:
分配规则:
查看容器IP:
# 方法1:使用docker inspect
docker inspect <容器名> | grep IPAddress
# 方法2:在容器内查看
docker exec <容器名> ip addr show eth0
# 方法3:查看网络详情
docker network inspect bridge
IP分配示例:
# 启动第一个容器
docker run -d --name container1 nginx
# 分配IP:172.17.0.2
# 启动第二个容器
docker run -d --name container2 nginx
# 分配IP:172.17.0.3
# 启动第三个容器
docker run -d --name container3 nginx
# 分配IP:172.17.0.4
🔄 容器间通信流程图¶
场景:容器A访问容器B的80端口
步骤详解:
┌──────────────┐
│ 容器A │
│ 172.17.0.2 │
│ │
│ 应用请求 │
│ 172.17.0.3 │
└──────┬───────┘
│
│ 1. 发送数据包
│ 目标IP: 172.17.0.3
│ 目标端口: 80
│
▼
┌──────────────────────────────────────┐
│ docker0 网桥 │
│ │
│ 2. 查找ARP表,找到172.17.0.3的MAC │
│ 3. 转发数据包到容器B的veth接口 │
└──────────────────────────────────────┘
│
│ 4. 数据包到达
│
▼
┌──────────────┐
│ 容器B │
│ 172.17.0.3 │
│ │
│ 5. 接收请求 │
│ 6. 处理请求 │
│ 7. 返回响应 │
└──────────────┘
实际操作验证:
# 启动两个容器
docker run -d --name web1 nginx
docker run -d --name web2 nginx
# 获取容器B的IP
WEB2_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web2)
echo "Web2 IP: $WEB2_IP"
# 从容器A访问容器B
docker exec web1 curl http://$WEB2_IP
# 输出:Welcome to nginx!
5. Docker网络命令¶
🆕 创建网络:docker network create¶
基本语法:
常用选项:
| 选项 | 说明 | 示例 |
|---|---|---|
-d, --driver | 指定网络驱动 | -d bridge |
--subnet | 指定子网CIDR | --subnet 192.168.1.0/24 |
--gateway | 指定网关IP | --gateway 192.168.1.1 |
--ip-range | 指定IP分配范围 | --ip-range 192.168.1.100/24 |
创建自定义Bridge网络:
# 创建自定义网络
docker network create \
--driver bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.1 \
my-app-network
# 查看创建的网络
docker network ls
# 查看网络详情
docker network inspect my-app-network
创建Overlay网络(需要Swarm集群):
# 初始化Swarm集群
docker swarm init
# 创建Overlay网络
docker network create \
--driver overlay \
--subnet 10.0.0.0/24 \
--attachable \
my-overlay-network
📋 查看网络:docker network ls¶
基本用法:
# 列出所有网络
docker network ls
# 输出示例:
# NETWORK ID NAME DRIVER SCOPE
# abc123def456 bridge bridge local
# 789ghi012jkl host host local
# mno345pqr678 none null local
# stu789vwx012 my-app-network bridge local
过滤网络:
# 只查看bridge类型的网络
docker network ls --filter driver=bridge
# 查看特定名称的网络
docker network ls --filter name=my-app-network
🔗 连接容器到网络:docker network connect¶
基本语法:
常用选项:
| 选项 | 说明 | 示例 |
|---|---|---|
--alias | 为容器添加网络别名 | --alias web |
--ip | 指定容器的IP地址 | --ip 192.168.100.10 |
使用示例:
# 启动一个容器(使用默认网络)
docker run -d --name myapp nginx
# 将容器连接到自定义网络
docker network connect my-app-network myapp
# 连接时指定IP
docker network connect \
--ip 192.168.100.50 \
my-app-network myapp
# 连接时添加别名
docker network connect \
--alias web \
my-app-network myapp
容器连接多个网络:
# 创建两个网络
docker network create network-a
docker network create network-b
# 启动容器
docker run -d --name multi-net-app nginx
# 连接到多个网络
docker network connect network-a multi-net-app
docker network connect network-b multi-net-app
# 查看容器的网络连接
docker inspect multi-net-app | grep -A 10 Networks
🔍 查看网络详情:docker network inspect¶
基本用法:
输出信息说明:
# 查看网络详情
docker network inspect my-app-network
# 输出示例(JSON格式):
{
"Name": "my-app-network",
"Id": "abc123def456...",
"Created": "2024-01-15T10:30:00Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Config": [
{
"Subnet": "192.168.100.0/24",
"Gateway": "192.168.100.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {
"container1-id": {
"Name": "myapp",
"IPv4Address": "192.168.100.2/24",
"MacAddress": "02:42:ac:11:00:02"
}
},
"Options": {}
}
提取特定信息:
# 只查看子网信息
docker network inspect my-app-network --format '{{.IPAM.Config}}'
# 查看连接的容器
docker network inspect my-app-network --format '{{range .Containers}}{{.Name}} {{end}}'
# 查看容器的IP地址
docker network inspect my-app-network --format '{{range .Containers}}{{.Name}}: {{.IPv4Address}}{{end}}'
❌ 断开容器连接:docker network disconnect¶
基本用法:
使用示例:
# 断开容器与网络的连接
docker network disconnect my-app-network myapp
# 强制断开(容器正在运行时)
docker network disconnect -f my-app-network myapp
🗑️ 删除网络:docker network rm¶
基本用法:
使用示例:
# 删除单个网络
docker network rm my-app-network
# 删除多个网络
docker network rm network-a network-b
# 删除所有未使用的网络
docker network prune
# 强制删除所有网络(包括正在使用的)
docker network prune -f
📊 常用命令速查表¶
| 命令 | 说明 | 示例 |
|---|---|---|
docker network create | 创建网络 | docker network create my-net |
docker network ls | 列出网络 | docker network ls |
docker network inspect | 查看网络详情 | docker network inspect my-net |
docker network connect | 连接容器到网络 | docker network connect my-net container |
docker network disconnect | 断开容器连接 | docker network disconnect my-net container |
docker network rm | 删除网络 | docker network rm my-net |
docker network prune | 清理未使用的网络 | docker network prune |
6. 端口映射¶
🤔 为什么需要端口映射?¶
问题场景:
┌──────────────────────────────────────────────┐
│ 宿主机 (192.168.1.100) │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ 容器A (nginx) │ │
│ │ 内部IP: 172.17.0.2 │ │
│ │ 监听端口: 80 │ │
│ └──────────────────────────────────────┘ │
│ │
│ 问题:外部用户如何访问容器内的nginx服务? │
└──────────────────────────────────────────────┘
答案:通过端口映射!
端口映射将宿主机的端口映射到容器的端口,让外部用户可以通过宿主机IP和端口访问容器服务。
🔧 端口映射的原理¶
工作原理:
外部访问流程:
用户浏览器
│
│ 访问 http://192.168.1.100:8080
│
▼
┌──────────────────────────────────────────────┐
│ 宿主机 (192.168.1.100) │
│ │
│ iptables规则: │
│ 宿主机:8080 → 容器:80 │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ 容器A (nginx) │ │
│ │ 内部IP: 172.17.0.2 │ │
│ │ 监听端口: 80 │ │
│ └──────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────┘
技术实现:
Docker使用iptables的NAT(网络地址转换)规则来实现端口映射:
# 查看Docker创建的iptables规则
iptables -t nat -L -n -v | grep DOCKER
# 示例规则:
# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
📝 常用端口映射命令¶
基本语法:
使用示例:
# 1. 映射单个端口
docker run -d -p 8080:80 nginx
# 访问:http://宿主机IP:8080
# 2. 映射多个端口
docker run -d \
-p 8080:80 \
-p 8443:443 \
nginx
# 3. 绑定到特定IP
docker run -d -p 127.0.0.1:8080:80 nginx
# 只能通过localhost访问
# 4. 绑定到所有网络接口
docker run -d -p 0.0.0.0:8080:80 nginx
# 可以通过任何IP访问
# 5. 随机端口映射
docker run -d -p 80 nginx
# Docker自动分配宿主机端口
查看端口映射:
# 查看容器的端口映射
docker ps
# 输出示例:
# CONTAINER ID IMAGE PORTS
# abc123 nginx 0.0.0.0:8080->80/tcp, 0.0.0.0:8443->443/tcp
# 查看详细信息
docker port <容器名>
# 输出示例:
# 80/tcp -> 0.0.0.0:8080
# 443/tcp -> 0.0.0.0:8443
🚫 端口映射的局限性¶
常见问题:
- 端口冲突
# 问题:端口已被占用
docker run -d -p 8080:80 nginx
# Error: bind: address already in use
# 解决方法:
# 1. 使用其他端口
docker run -d -p 8081:80 nginx
# 2. 查看占用端口的进程
netstat -tulnp | grep 8080
# 或
lsof -i :8080
- 性能开销
- 只支持TCP/UDP
# ❌ 不支持其他协议
docker run -d -p 8080:80/icmp nginx
# Error: invalid protocol
# ✅ 只支持TCP和UDP
docker run -d -p 8080:80/tcp nginx
docker run -d -p 53:53/udp nginx
- 安全性考虑
# ⚠️ 谨慎绑定到0.0.0.0
docker run -d -p 0.0.0.0:8080:80 nginx
# 任何人都可以访问
# ✅ 更安全的做法
docker run -d -p 127.0.0.1:8080:80 nginx
# 只能本地访问
# ✅ 或使用防火墙规则
iptables -A INPUT -p tcp --dport 8080 -s 允许的IP -j ACCEPT
📊 端口映射对比表¶
| 映射方式 | 语法 | 访问方式 | 安全性 | 适用场景 |
|---|---|---|---|---|
| 指定端口 | -p 8080:80 | 宿主机:8080 | 中 | 开发环境 |
| 绑定特定IP | -p 127.0.0.1:8080:80 | localhost:8080 | 高 | 内部服务 |
| 绑定所有IP | -p 0.0.0.0:8080:80 | 任何IP:8080 | 低 | 公开服务 |
| 随机端口 | -p 80 | 宿主机:随机端口 | 中 | 测试环境 |
7. 实战案例¶
🎯 案例1:创建自定义Bridge网络¶
场景: 为一个Web应用创建独立的网络环境
步骤:
# 1. 创建自定义网络
docker network create \
--driver bridge \
--subnet 192.168.200.0/24 \
--gateway 192.168.200.1 \
web-app-network
# 2. 验证网络创建
docker network ls
docker network inspect web-app-network
# 3. 在自定义网络中启动容器
docker run -d \
--name web-server \
--network web-app-network \
nginx
# 4. 启动另一个容器
docker run -d \
--name app-server \
--network web-app-network \
node:14
# 5. 验证容器间通信
docker exec web-server ping app-server
docker exec app-server curl http://web-server
# 6. 查看容器IP
docker inspect web-server | grep IPAddress
docker inspect app-server | grep IPAddress
网络结构:
┌──────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ web-app-network (192.168.200.0/24) │ │
│ │ 网关: 192.168.200.1 │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │web-server│ │app-server│ │ │
│ │ │.2 │ │.3 │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
🎯 案例2:部署多容器应用(Web + Database)¶
场景: 部署一个包含Web服务器和数据库的完整应用
步骤:
# 1. 创建应用网络
docker network create app-network
# 2. 启动数据库容器
docker run -d \
--name mysql-db \
--network app-network \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=myapp \
-e MYSQL_USER=appuser \
-e MYSQL_PASSWORD=apppassword \
mysql:8.0
# 3. 等待数据库启动
sleep 10
# 4. 启动Web应用容器
docker run -d \
--name web-app \
--network app-network \
-p 8080:80 \
-e DB_HOST=mysql-db \
-e DB_NAME=myapp \
-e DB_USER=appuser \
-e DB_PASSWORD=apppassword \
your-web-app-image
# 5. 验证连接
docker exec web-app ping mysql-db
docker exec web-app nc -zv mysql-db 3306
# 6. 查看日志
docker logs web-app
docker logs mysql-db
通信流程:
外部用户
│
│ http://宿主机:8080
│
▼
┌──────────────────────────────────────────────┐
│ 宿主机 │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ app-network │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ web-app │ │ mysql-db │ │ │
│ │ │ :8080 │─────►│ :3306 │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
测试数据库连接:
# 进入Web应用容器
docker exec -it web-app bash
# 测试数据库连接
mysql -h mysql-db -u appuser -papppassword myapp
# 在MySQL中执行
SHOW DATABASES;
SELECT * FROM information_schema.tables;
🎯 案例3:配置容器间通信¶
场景: 三个服务相互通信(Web、API、Cache)
步骤:
# 1. 创建网络
docker network create multi-tier-network
# 2. 启动Redis缓存
docker run -d \
--name redis-cache \
--network multi-tier-network \
redis:alpine
# 3. 启动API服务
docker run -d \
--name api-service \
--network multi-tier-network \
-e REDIS_HOST=redis-cache \
-e REDIS_PORT=6379 \
your-api-image
# 4. 启动Web前端
docker run -d \
--name web-frontend \
--network multi-tier-network \
-p 80:80 \
-e API_URL=http://api-service:3000 \
your-web-image
# 5. 验证通信
# Web → API
docker exec web-frontend curl http://api-service:3000/health
# API → Redis
docker exec api-service redis-cli -h redis-cache ping
# Web → Redis(不应该直接访问,验证隔离)
docker exec web-frontend redis-cli -h redis-cache ping
服务架构:
┌─────────────────────────────────────────────────────┐
│ multi-tier-network │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ web-frontend │────►│ api-service │ │
│ │ :80 │ │ :3000 │ │
│ └──────────────┘ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ redis-cache │ │
│ │ :6379 │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────┘
🎯 案例4:使用Docker Compose管理网络¶
场景: 使用Docker Compose一键部署多容器应用
docker-compose.yml:
version: '3.8'
services:
# 数据库服务
db:
image: mysql:8.0
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
networks:
- app-network
volumes:
- db-data:/var/lib/mysql
restart: unless-stopped
# Redis缓存
redis:
image: redis:alpine
container_name: redis-cache
networks:
- app-network
restart: unless-stopped
# 后端API
api:
image: your-api-image:latest
container_name: api-service
environment:
DB_HOST: db
DB_NAME: myapp
DB_USER: appuser
DB_PASSWORD: apppassword
REDIS_HOST: redis
REDIS_PORT: 6379
networks:
- app-network
depends_on:
- db
- redis
restart: unless-stopped
# 前端Web
web:
image: your-web-image:latest
container_name: web-frontend
ports:
- "80:80"
- "443:443"
environment:
API_URL: http://api-service:3000
networks:
- app-network
depends_on:
- api
restart: unless-stopped
# 定义网络
networks:
app-network:
driver: bridge
ipam:
config:
- subnet: 192.168.200.0/24
# 定义数据卷
volumes:
db-data:
使用Docker Compose:
# 1. 启动所有服务
docker-compose up -d
# 2. 查看服务状态
docker-compose ps
# 3. 查看日志
docker-compose logs -f
# 4. 查看网络
docker network ls | grep app-network
docker network inspect <network-name>
# 5. 测试服务
curl http://localhost
curl http://localhost/api/health
# 6. 停止服务
docker-compose down
# 7. 停止并删除数据卷
docker-compose down -v
网络结构:
┌─────────────────────────────────────────────────────┐
│ app-network (Docker Compose) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ web │──┤ api │──┤ db │ │
│ │ :80 │ │ :3000 │ │ :3306 │ │
│ └─────────┘ └────┬────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────┐ │
│ │ redis │ │
│ │ :6379 │ │
│ └─────────┘ │
└─────────────────────────────────────────────────────┘
高级配置示例:
version: '3.8'
services:
# 使用外部网络
app:
image: your-app
networks:
- frontend
- backend
# 使用自定义IP
app2:
image: your-app2
networks:
backend:
ipv4_address: 192.168.200.100
# 定义多个网络
networks:
frontend:
driver: bridge
backend:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.200.0/24
🎯 案例5:网络故障排查¶
场景: 容器无法互相通信,进行故障排查
排查步骤:
# 1. 检查容器是否在同一网络
docker inspect web-app | grep Network
docker inspect api-service | grep Network
# 2. 检查网络是否存在
docker network ls
docker network inspect app-network
# 3. 检查容器IP地址
docker inspect web-app --format '{{.NetworkSettings.Networks.app-network.IPAddress}}'
docker inspect api-service --format '{{.NetworkSettings.Networks.app-network.IPAddress}}'
# 4. 测试网络连通性
docker exec web-app ping -c 3 api-service
docker exec web-app nc -zv api-service 3000
# 5. 检查防火墙规则
iptables -L -n | grep DOCKER
# 6. 检查容器日志
docker logs web-app
docker logs api-service
# 7. 进入容器检查
docker exec -it web-app bash
# 在容器内执行:
ip addr show
route -n
curl http://api-service:3000
# 8. 重启网络
docker network disconnect app-network web-app
docker network connect app-network web-app
# 9. 重建网络(最后手段)
docker-compose down
docker network prune
docker-compose up -d
常见问题及解决方案:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 容器无法互相访问 | 不在同一网络 | 将容器连接到同一网络 |
| 无法访问外网 | DNS配置问题 | 检查/etc/resolv.conf |
| 端口映射不工作 | 端口冲突 | 更换端口或停止占用进程 |
| 网络性能差 | 网络模式不当 | 考虑使用Host网络 |
8. 常见问题¶
❓ 问题1:容器无法访问外网¶
现象:
可能原因及解决方案:
- DNS配置问题
# 检查容器DNS配置
docker exec mycontainer cat /etc/resolv.conf
# 解决方法1:使用宿主机DNS
docker run -d --dns 8.8.8.8 --dns 8.8.4.4 myimage
# 解决方法2:修改Docker守护进程配置
# 编辑 /etc/docker/daemon.json
{
"dns": ["8.8.8.8", "8.8.4.4"]
}
# 重启Docker服务
sudo systemctl restart docker
- 防火墙规则问题
# 检查iptables规则
sudo iptables -L -n -v | grep DOCKER
# 检查NAT规则
sudo iptables -t nat -L -n -v | grep POSTROUTING
# 如果规则丢失,重启Docker
sudo systemctl restart docker
- 网络模式问题
# 检查容器网络模式
docker inspect mycontainer | grep NetworkMode
# 如果使用none模式,改为bridge
docker run --network=bridge myimage
- 宿主机网络问题
❓ 问题2:容器间无法通信¶
现象:
可能原因及解决方案:
- 不在同一网络
# 检查容器网络
docker inspect container1 | grep Network
docker inspect container2 | grep Network
# 解决方法:连接到同一网络
docker network connect shared-network container1
docker network connect shared-network container2
- 容器名称解析问题
# 使用IP地址测试
CONTAINER2_IP=$(docker inspect -f '{{.NetworkSettings.Networks.shared-network.IPAddress}}' container2) # $()命令替换:执行命令并获取输出
docker exec container1 ping $CONTAINER2_IP
# 如果IP可以但名称不行,检查DNS
docker exec container1 cat /etc/resolv.conf
- 防火墙阻止
# 检查容器防火墙规则
docker exec container1 iptables -L -n
# 检查宿主机防火墙
sudo iptables -L -n | grep DOCKER-ISOLATION
- 容器服务未启动
# 检查容器状态
docker ps -a
# 检查容器日志
docker logs container2
# 进入容器检查服务
docker exec -it container2 bash
# 检查服务是否运行
netstat -tulnp
❓ 问题3:端口冲突怎么办¶
现象:
解决方案:
- 查找占用端口的进程
# 方法1:使用netstat
sudo netstat -tulnp | grep 8080 # grep文本搜索:按模式匹配行
# 方法2:使用lsof
sudo lsof -i :8080
# 方法3:使用ss
sudo ss -tulnp | grep 8080
# 输出示例:
# tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 12345/nginx
- 停止占用端口的进程
- 使用其他端口
- 绑定到特定IP
- 使用随机端口
❓ 问题4:如何查看容器的网络配置¶
方法1:使用docker inspect
# 查看完整的网络配置
docker inspect <container-name>
# 只查看网络部分
docker inspect <container-name> --format '{{json .NetworkSettings}}' | jq
# 查看IP地址
docker inspect <container-name> --format '{{.NetworkSettings.IPAddress}}'
# 查看所有网络连接
docker inspect <container-name> --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
# 查看端口映射
docker inspect <container-name> --format '{{json .NetworkSettings.Ports}}' | jq
方法2:在容器内查看
# 进入容器
docker exec -it <container-name> bash
# 查看网络接口
ip addr show
# 查看路由表
ip route show
# 查看DNS配置
cat /etc/resolv.conf
# 查看主机名
hostname
# 查看网络连接
netstat -tulnp
# 或
ss -tulnp
方法3:使用docker network inspect
# 查看网络中的所有容器
docker network inspect <network-name> --format '{{json .Containers}}' | jq # |管道:将前一命令的输出作为后一命令的输入
# 查看特定容器的网络信息
docker network inspect <network-name> --format '{{range .Containers}}{{if eq .Name "container-name"}}{{.}}{{end}}{{end}}'
方法4:使用第三方工具
❓ 问题5:Docker网络性能优化¶
优化建议:
- 选择合适的网络模式
# 高性能场景使用Host网络
docker run --network=host high-performance-app
# 开发环境使用Bridge网络
docker run --network=bridge dev-app
# 生产环境考虑Overlay网络
docker network create --driver overlay prod-network
- 减少网络跳数
# 将相关服务放在同一网络
docker network create app-network
docker run --network=app-network service-a
docker run --network=app-network service-b
# 避免不必要的网络连接
docker network connect --alias service service-network container
- 使用DNS缓存
# 配置DNS缓存
docker run -d --name dns-cache \
--network=host \
andyshinn/dnsmasq:2.78 \
--server=8.8.8.8 \
--server=8.8.4.4
# 使用DNS缓存
docker run --dns 127.0.0.1 myapp
- 调整MTU大小
# 创建网络时指定MTU
docker network create \
--driver bridge \
--opt com.docker.network.driver.mtu=1450 \
custom-network
❓ 问题6:容器重启后IP地址变化¶
问题: 容器重启后IP地址会改变,导致其他容器无法连接
解决方案:
- 使用容器名称而非IP
# ✅ 推荐:使用容器名称
docker exec container1 curl http://container2:8080
# ❌ 不推荐:使用IP地址
docker exec container1 curl http://172.17.0.3:8080
- 使用网络别名
# 连接容器时指定别名
docker network connect \
--alias web \
--alias api \
app-network container
# 使用别名访问
docker exec other-container curl http://web:8080
- 使用固定IP(不推荐)
# 创建支持固定IP的网络
docker network create \
--subnet=192.168.100.0/24 \
--ip-range=192.168.100.128/25 \
app-network
# 启动容器时指定IP
docker run -d \
--network app-network \
--ip 192.168.100.10 \
myapp
- 使用Docker Compose服务名
# docker-compose.yml
services: # services定义各个服务容器
web:
image: nginx
api:
image: node-app
environment:
WEB_URL: http://web:80
❓ 问题7:跨主机容器通信¶
场景: 容器分布在不同的主机上,需要互相通信
解决方案:
- 使用Overlay网络(推荐)
# 初始化Swarm集群
docker swarm init --advertise-addr <主机IP>
# 创建Overlay网络
docker network create \
--driver overlay \
--attachable \
multi-host-network
# 在不同主机上启动容器
docker run -d --network multi-host-network app1
docker run -d --network multi-host-network app2
- 使用Macvlan网络
# 在每台主机上创建相同的Macvlan网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
macvlan-net
# 容器可以直接通信
docker run -d --network macvlan-net app1
- 使用第三方网络插件
# 安装Weave Net
curl -L git.io/weave -o /usr/local/bin/weave
chmod a+x /usr/local/bin/weave
weave launch
# 使用Weave网络
docker run --net=weave app1
📚 总结¶
Docker网络核心要点:
- 理解网络模式:Bridge、Host、None、Overlay、Macvlan各有适用场景
- 合理规划网络:为不同应用创建独立的网络
- 使用容器名称:避免依赖IP地址
- 善用Docker Compose:简化多容器网络管理
- 掌握故障排查:能够快速定位和解决网络问题
最佳实践:
✅ 为每个应用创建独立的网络 ✅ 使用容器名称而非IP地址进行通信 ✅ 合理配置端口映射,注意安全性 ✅ 使用Docker Compose管理复杂应用 ✅ 定期清理未使用的网络 ✅ 监控网络性能,及时优化
学习建议:
- 从简单的Bridge网络开始学习
- 动手实践每个网络模式
- 遇到问题时,使用
docker inspect和docker logs排查 - 阅读Docker官方文档,了解最新特性
- 关注社区动态,学习最佳实践
🎉 恭喜!¶
你已经掌握了Docker网络的核心知识!现在你可以:
- ✅ 理解Docker网络的工作原理
- ✅ 创建和管理自定义网络
- ✅ 配置容器间的通信
- ✅ 使用Docker Compose管理网络
- ✅ 排查常见的网络问题
下一步建议:
- 在实际项目中应用这些知识
- 尝试不同的网络模式
- 学习Kubernetes网络(更高级的话题)
- 关注Docker网络的最新发展
祝你学习愉快!🚀