跳转至

07 - Docker网络

Docker网络

本章核心: 理解Docker网络模型,掌握容器间通信和网络配置


📖 章节导航

前序章节: 05-网络模式详解.md06-云服务与CDN.md 后续章节: 08-实战应用场景.md09-AI网络专题.md 快速参考: 网络工具箱.md 第1章 故障排查: 故障排查手册.md 第3章


📚 目录

  1. 引言
  2. Docker网络基础
  3. Docker网络驱动
  4. Bridge网络详解
  5. Docker网络命令
  6. 端口映射
  7. 实战案例
  8. 常见问题

1. 引言

🎯 为什么需要理解Docker网络?

想象一下,你在开发一个Web应用,它由多个服务组成: - 一个前端服务(React应用) - 一个后端API服务(Node.js) - 一个数据库服务(MySQL) - 一个缓存服务(Redis)

这些服务需要相互通信才能正常工作。Docker网络就是让这些容器能够安全、高效地相互通信的机制。

理解Docker网络的重要性:

容器间通信:让不同的容器能够互相访问和交换数据 ✅ 服务部署:在生产环境中正确配置服务之间的连接 ✅ 网络隔离:保证不同应用或环境的网络安全性 ✅ 性能优化:合理配置网络可以提高应用性能 ✅ 故障排查:当出现网络问题时,能够快速定位和解决

💡 简单类比

把Docker网络想象成一个公司的内部电话系统: - 每个容器就像一个员工 - Docker网络就像公司的电话交换机 - 网络驱动就像不同的电话线路类型(内线、外线、专线等) - 端口映射就像设置分机号码


2. Docker网络基础

🌐 Docker网络的作用和重要性

Docker网络的核心作用是解决容器之间的通信问题。默认情况下,每个容器都有自己的独立网络空间,就像每个员工有自己的办公室一样。

主要功能:

  1. 容器互联:让容器之间可以互相访问
  2. 外部访问:允许外部网络访问容器服务
  3. 网络隔离:将不同的应用隔离开来
  4. 跨主机通信:支持容器在不同主机间通信

🔒 容器与宿主机的网络隔离

Docker使用网络命名空间(Network Namespace)来实现网络隔离。这意味着:

Text Only
┌─────────────────────────────────────────┐
│         宿主机网络空间                    │
│  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由三个核心组件组成:

Text Only
┌─────────────────────────────────────────────────┐
│              CNM 架构                            │
├─────────────────────────────────────────────────┤
│                                                 │
│   ┌─────────┐         ┌─────────┐              │
│   │ Sandbox │         │Network  │              │
│   │ (容器)  │◄────────┤ (网络)  │              │
│   └────┬────┘         └────┬────┘              │
│        │                   │                   │
│        │                   │                   │
│        │         ┌─────────▼──────┐            │
│        └────────►│   Endpoint     │            │
│                  │  (网络端点)     │            │
│                  └────────────────┘            │
│                                                 │
└─────────────────────────────────────────────────┘

CNM三大组件:

  1. Sandbox(沙箱)
  2. 代表一个容器的网络栈
  3. 包含网络接口、路由表、DNS配置等
  4. 每个容器有自己的Sandbox

  5. Endpoint(端点)

  6. 连接Sandbox和Network的桥梁
  7. 类似于网络插头,将容器连接到网络

  8. Network(网络)

  9. 一组可以相互通信的Endpoint
  10. 由Driver(驱动)管理
  11. 可以是Bridge、Overlay、Macvlan等类型

3. Docker网络驱动

Docker支持多种网络驱动,每种驱动适用于不同的场景:

🌉 1. Bridge驱动(默认桥接网络)

特点: - ✅ Docker默认网络模式 - ✅ 适合单主机上的容器通信 - ✅ 通过NAT访问外网 - ❌ 不支持跨主机通信

使用场景: - 开发环境 - 单机部署的微服务 - 需要容器间通信的应用

Text Only
┌──────────────────────────────────────────────┐
│            宿主机                              │
│                                              │
│   ┌──────────────────────────────────────┐  │
│   │          docker0 网桥                │  │
│   │   IP: 172.17.0.1                     │  │
│   │                                      │  │
│   │  ┌──────────┐  ┌──────────┐         │  │
│   │  │ 容器A    │  │ 容器B    │         │  │
│   │  │.2       │  │.3       │         │  │
│   │  └──────────┘  └──────────┘         │  │
│   └──────────────────────────────────────┘  │
│                                              │
│   通过NAT访问外网                             │
└──────────────────────────────────────────────┘

🏠 2. Host驱动(使用宿主机网络)

特点: - ✅ 容器使用宿主机的网络栈 - ✅ 性能最好(无网络开销) - ✅ 端口直接暴露 - ❌ 网络隔离性差 - ❌ 端口冲突风险高

使用场景: - 网络性能要求极高的应用 - 需要直接访问宿主机网络接口的服务 - 监控和日志收集工具

Bash
# 使用host网络启动容器
docker run --network=host -d nginx

网络结构:

Text Only
┌──────────────────────────────────────┐
│         宿主机网络                     │
│                                      │
│   ┌──────────────────────────────┐  │
│   │     容器(共享宿主机网络)     │  │
│   │     使用相同的IP和端口         │  │
│   └──────────────────────────────┘  │
│                                      │
│   直接使用宿主机的网络接口            │
└──────────────────────────────────────┘

🚫 3. None驱动(无网络)

特点: - ✅ 完全隔离的网络环境 - ✅ 安全性最高 - ❌ 无法访问外网 - ❌ 无法与其他容器通信

使用场景: - 高安全性的批处理任务 - 不需要网络的数据处理 - 离线计算任务

Bash
# 使用none网络启动容器
docker run --network=none -d myapp

网络结构:

Text Only
┌──────────────────────────────────────┐
│         宿主机网络                     │
│                                      │
│   ┌──────────────────────────────┐  │
│   │     容器(无网络)             │  │
│   │     只有lo回环接口            │  │
│   └──────────────────────────────┘  │
│                                      │
│   完全隔离,无网络连接                │
└──────────────────────────────────────┘

🌐 4. Overlay驱动(跨主机网络)

特点: - ✅ 支持跨主机容器通信 - ✅ 适合分布式系统 - ✅ 自动加密通信 - ❌ 配置相对复杂 - ❌ 需要额外的键值存储(如etcd、Consul)

使用场景: - Docker Swarm集群 - Kubernetes环境 - 分布式微服务架构

Text Only
┌──────────────────────┐        ┌──────────────────────┐
│      主机A           │        │      主机B           │
│                      │        │                      │
│   ┌──────────────┐  │        │   ┌──────────────┐  │
│   │   容器A1     │  │        │   │   容器B1     │  │
│   │  10.0.0.2    │  │        │   │  10.0.0.3    │  │
│   └──────┬───────┘  │        │   └──────┬───────┘  │
│          │          │        │          │          │
│   ┌──────▼───────┐  │        │   ┌──────▼───────┐  │
│   │  Overlay网络 │◄─┼────────┼──►│  Overlay网络 │  │
│   └──────────────┘  │        │   └──────────────┘  │
│                      │        │                      │
└──────────────────────┘        └──────────────────────┘
         │                                │
         └──────── 物理网络 ──────────────┘

📡 5. Macvlan驱动(物理网络接口)

特点: - ✅ 容器拥有独立的MAC地址 - ✅ 直接连接到物理网络 - ✅ 性能接近原生网络 - ❌ 需要物理网络支持 - ❌ 配置复杂度高

使用场景: - 需要直接接入物理网络的容器 - 传统应用迁移到容器 - 网络监控和管理工具

Bash
# 创建macvlan网络
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 my-macvlan-net

网络结构:

Text Only
┌──────────────────────────────────────────┐
│           物理网络                        │
│                                          │
│   ┌──────────┐  ┌──────────┐           │
│   │ 容器A    │  │ 容器B    │           │
│   │MAC:AA:BB │  │MAC:CC:DD │           │
│   │IP: .100   │  │IP: .101   │           │
│   └────┬─────┘  └────┬─────┘           │
│        │              │                 │
│        └──────┬───────┘                 │
│               │                         │
│        ┌──────▼──────┐                 │
│        │  物理交换机  │                 │
│        └─────────────┘                 │
└──────────────────────────────────────────┘

📊 网络驱动对比表

驱动类型 适用场景 优点 缺点 跨主机
Bridge 单机开发部署 简单易用,默认支持 性能一般
Host 高性能需求 性能最好,无开销 隔离性差
None 离线任务 安全性高 无法联网
Overlay 分布式集群 跨主机通信 配置复杂
Macvlan 物理网络集成 直接接入物理网络 需要网络支持

4. Bridge网络详解

🔍 Bridge网络的工作原理

Bridge网络是Docker最常用的网络模式,它使用Linux网桥技术来实现容器间的通信。

工作原理:

Text Only
┌────────────────────────────────────────────────────┐
│                  宿主机                            │
│                                                    │
│   ┌──────────────────────────────────────────┐   │
│   │            docker0 网桥                  │   │
│   │            (虚拟交换机)                   │   │
│   │            IP: 172.17.0.1/16            │   │
│   │                                          │   │
│   │   ┌──────────┐    ┌──────────┐          │   │
│   │   │veth1     │    │veth2     │          │   │
│   │   │(虚拟网卡) │    │(虚拟网卡) │          │   │
│   │   └────┬─────┘    └────┬─────┘          │   │
│   │        │               │                │   │
│   └────────┼───────────────┼────────────────┘   │
│            │               │                    │
│            │               │                    │
│   ┌────────▼─────┐  ┌─────▼────────┐         │
│   │   容器A       │  │   容器B       │         │
│   │   eth0        │  │   eth0        │         │
│   │ 172.17.0.2    │  │ 172.17.0.3    │         │
│   └───────────────┘  └───────────────┘         │
│                                                    │
│   通过NAT规则访问外网                               │
└────────────────────────────────────────────────────┘

通信流程:

  1. 容器创建时:Docker为每个容器创建一对虚拟网卡(veth pair)
  2. 一端在容器内:命名为eth0,容器使用它进行网络通信
  3. 一端在宿主机:连接到docker0网桥
  4. 容器间通信:通过docker0网桥进行二层转发
  5. 访问外网:通过宿主机的NAT规则进行地址转换

🌉 docker0网桥的作用

docker0是Docker默认创建的网桥,它就像一个虚拟的交换机:

主要功能:

  1. 连接容器:将所有容器连接到同一个虚拟网络
  2. IP分配:为容器分配IP地址
  3. 数据转发:在容器之间转发数据包
  4. NAT网关:作为容器访问外网的网关

查看docker0信息:

Bash
# 查看网桥信息
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地址分配:

分配规则:

Text Only
默认Bridge网络配置:
- 子网:172.17.0.0/16
- 网关:172.17.0.1
- 可用IP范围:172.17.0.2 - 172.17.255.254

查看容器IP:

Bash
# 方法1:使用docker inspect
docker inspect <容器名> | grep IPAddress

# 方法2:在容器内查看
docker exec <容器名> ip addr show eth0

# 方法3:查看网络详情
docker network inspect bridge

IP分配示例:

Bash
# 启动第一个容器
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端口

Text Only
步骤详解:

┌──────────────┐
│  容器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. 返回响应  │
└──────────────┘

实际操作验证:

Bash
# 启动两个容器
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

基本语法:

Bash
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网络:

Bash
# 创建自定义网络
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集群):

Bash
# 初始化Swarm集群
docker swarm init

# 创建Overlay网络
docker network create \
  --driver overlay \
  --subnet 10.0.0.0/24 \
  --attachable \
  my-overlay-network

📋 查看网络:docker network ls

基本用法:

Bash
# 列出所有网络
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

过滤网络:

Bash
# 只查看bridge类型的网络
docker network ls --filter driver=bridge

# 查看特定名称的网络
docker network ls --filter name=my-app-network

🔗 连接容器到网络:docker network connect

基本语法:

Bash
docker network connect [选项] 网络名称 容器名称

常用选项:

选项 说明 示例
--alias 为容器添加网络别名 --alias web
--ip 指定容器的IP地址 --ip 192.168.100.10

使用示例:

Bash
# 启动一个容器(使用默认网络)
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

容器连接多个网络:

Bash
# 创建两个网络
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

基本用法:

Bash
docker network inspect 网络名称

输出信息说明:

Bash
# 查看网络详情
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": {}
}

提取特定信息:

Bash
# 只查看子网信息
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

基本用法:

Bash
docker network disconnect 网络名称 容器名称

使用示例:

Bash
# 断开容器与网络的连接
docker network disconnect my-app-network myapp

# 强制断开(容器正在运行时)
docker network disconnect -f my-app-network myapp

🗑️ 删除网络:docker network rm

基本用法:

Bash
docker network rm 网络名称

使用示例:

Bash
# 删除单个网络
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. 端口映射

🤔 为什么需要端口映射?

问题场景:

Text Only
┌──────────────────────────────────────────────┐
│         宿主机 (192.168.1.100)               │
│                                              │
│   ┌──────────────────────────────────────┐  │
│   │   容器A (nginx)                      │  │
│   │   内部IP: 172.17.0.2                 │  │
│   │   监听端口: 80                       │  │
│   └──────────────────────────────────────┘  │
│                                              │
│   问题:外部用户如何访问容器内的nginx服务?    │
└──────────────────────────────────────────────┘

答案:通过端口映射!

端口映射将宿主机的端口映射到容器的端口,让外部用户可以通过宿主机IP和端口访问容器服务。

🔧 端口映射的原理

工作原理:

Text Only
外部访问流程:

用户浏览器
    │ 访问 http://192.168.1.100:8080
┌──────────────────────────────────────────────┐
│         宿主机 (192.168.1.100)               │
│                                              │
│   iptables规则:                              │
│   宿主机:8080 → 容器:80                      │
│                                              │
│   ┌──────────────────────────────────────┐  │
│   │   容器A (nginx)                      │  │
│   │   内部IP: 172.17.0.2                 │  │
│   │   监听端口: 80                       │  │
│   └──────────────────────────────────────┘  │
│                                              │
└──────────────────────────────────────────────┘

技术实现:

Docker使用iptables的NAT(网络地址转换)规则来实现端口映射:

Bash
# 查看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

📝 常用端口映射命令

基本语法:

Bash
docker run -p [宿主机端口]:[容器端口] 镜像名称

使用示例:

Bash
# 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自动分配宿主机端口

查看端口映射:

Bash
# 查看容器的端口映射
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

🚫 端口映射的局限性

常见问题:

  1. 端口冲突
Bash
# 问题:端口已被占用
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
  1. 性能开销
Text Only
端口映射会带来一定的性能开销:
- 数据包需要经过NAT转换
- 增加了网络延迟
- CPU需要处理额外的iptables规则

对于高性能要求的应用,考虑使用Host网络模式
  1. 只支持TCP/UDP
Bash
# ❌ 不支持其他协议
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
  1. 安全性考虑
Bash
# ⚠️ 谨慎绑定到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应用创建独立的网络环境

步骤:

Bash
# 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

网络结构:

Text Only
┌──────────────────────────────────────────────┐
│         宿主机                                │
│                                              │
│   ┌──────────────────────────────────────┐  │
│   │   web-app-network (192.168.200.0/24) │  │
│   │   网关: 192.168.200.1                │  │
│   │                                      │  │
│   │   ┌──────────┐  ┌──────────┐       │  │
│   │   │web-server│  │app-server│       │  │
│   │   │.2       │  │.3       │       │  │
│   │   └──────────┘  └──────────┘       │  │
│   └──────────────────────────────────────┘  │
└──────────────────────────────────────────────┘

🎯 案例2:部署多容器应用(Web + Database)

场景: 部署一个包含Web服务器和数据库的完整应用

步骤:

Bash
# 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

通信流程:

Text Only
外部用户
    │ http://宿主机:8080
┌──────────────────────────────────────────────┐
│         宿主机                                │
│                                              │
│   ┌──────────────────────────────────────┐  │
│   │       app-network                    │  │
│   │                                      │  │
│   │   ┌──────────┐      ┌──────────┐    │  │
│   │   │ web-app  │      │ mysql-db │    │  │
│   │   │ :8080    │─────►│ :3306    │    │  │
│   │   └──────────┘      └──────────┘    │  │
│   └──────────────────────────────────────┘  │
└──────────────────────────────────────────────┘

测试数据库连接:

Bash
# 进入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)

步骤:

Bash
# 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

服务架构:

Text Only
┌─────────────────────────────────────────────────────┐
│                multi-tier-network                     │
│                                                     │
│   ┌──────────────┐     ┌──────────────┐            │
│   │ web-frontend │────►│ api-service  │            │
│   │   :80        │     │   :3000      │            │
│   └──────────────┘     └──────┬───────┘            │
│                              │                      │
│                              ▼                      │
│                     ┌──────────────┐               │
│                     │ redis-cache  │               │
│                     │   :6379      │               │
│                     └──────────────┘               │
└─────────────────────────────────────────────────────┘

🎯 案例4:使用Docker Compose管理网络

场景: 使用Docker Compose一键部署多容器应用

docker-compose.yml:

YAML
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:

Bash
# 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

网络结构:

Text Only
┌─────────────────────────────────────────────────────┐
│            app-network (Docker Compose)             │
│                                                     │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐           │
│   │   web   │──┤   api   │──┤   db    │           │
│   │  :80    │  │  :3000  │  │  :3306  │           │
│   └─────────┘  └────┬────┘  └─────────┘           │
│                     │                               │
│                     ▼                               │
│                ┌─────────┐                         │
│                │  redis  │                         │
│                │  :6379  │                         │
│                └─────────┘                         │
└─────────────────────────────────────────────────────┘

高级配置示例:

YAML
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:网络故障排查

场景: 容器无法互相通信,进行故障排查

排查步骤:

Bash
# 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:容器无法访问外网

现象:

Bash
docker exec mycontainer ping google.com
# ping: bad address 'google.com'

可能原因及解决方案:

  1. DNS配置问题
Bash
# 检查容器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
  1. 防火墙规则问题
Bash
# 检查iptables规则
sudo iptables -L -n -v | grep DOCKER

# 检查NAT规则
sudo iptables -t nat -L -n -v | grep POSTROUTING

# 如果规则丢失,重启Docker
sudo systemctl restart docker
  1. 网络模式问题
Bash
# 检查容器网络模式
docker inspect mycontainer | grep NetworkMode

# 如果使用none模式,改为bridge
docker run --network=bridge myimage
  1. 宿主机网络问题
Bash
# 检查宿主机网络连接
ping -c 3 google.com

# 检查宿主机DNS
cat /etc/resolv.conf

# 检查宿主机路由
route -n

❓ 问题2:容器间无法通信

现象:

Bash
docker exec container1 ping container2
# ping: container2: Name or service not known

可能原因及解决方案:

  1. 不在同一网络
Bash
# 检查容器网络
docker inspect container1 | grep Network
docker inspect container2 | grep Network

# 解决方法:连接到同一网络
docker network connect shared-network container1
docker network connect shared-network container2
  1. 容器名称解析问题
Bash
# 使用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
  1. 防火墙阻止
Bash
# 检查容器防火墙规则
docker exec container1 iptables -L -n

# 检查宿主机防火墙
sudo iptables -L -n | grep DOCKER-ISOLATION
  1. 容器服务未启动
Bash
# 检查容器状态
docker ps -a

# 检查容器日志
docker logs container2

# 进入容器检查服务
docker exec -it container2 bash
# 检查服务是否运行
netstat -tulnp

❓ 问题3:端口冲突怎么办

现象:

Bash
docker run -d -p 8080:80 nginx
# Error: bind: address already in use

解决方案:

  1. 查找占用端口的进程
Bash
# 方法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
  1. 停止占用端口的进程
Bash
# 停止进程
sudo kill 12345

# 如果无法停止,强制停止
sudo kill -9 12345
  1. 使用其他端口
Bash
# 使用不同的端口
docker run -d -p 8081:80 nginx
docker run -d -p 9090:80 nginx
  1. 绑定到特定IP
Bash
# 如果端口被其他服务占用,绑定到localhost
docker run -d -p 127.0.0.1:8080:80 nginx
  1. 使用随机端口
Bash
# 让Docker自动分配端口
docker run -d -p 80 nginx

# 查看分配的端口
docker port <container-id>

❓ 问题4:如何查看容器的网络配置

方法1:使用docker inspect

Bash
# 查看完整的网络配置
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:在容器内查看

Bash
# 进入容器
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

Bash
# 查看网络中的所有容器
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:使用第三方工具

Bash
# 使用ctop(容器监控工具)
ctop

# 使用lazydocker(TUI界面)
lazydocker

# 使用docker-stats(实时统计)
docker stats

❓ 问题5:Docker网络性能优化

优化建议:

  1. 选择合适的网络模式
Bash
# 高性能场景使用Host网络
docker run --network=host high-performance-app

# 开发环境使用Bridge网络
docker run --network=bridge dev-app

# 生产环境考虑Overlay网络
docker network create --driver overlay prod-network
  1. 减少网络跳数
Bash
# 将相关服务放在同一网络
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
  1. 使用DNS缓存
Bash
# 配置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
  1. 调整MTU大小
Bash
# 创建网络时指定MTU
docker network create \
  --driver bridge \
  --opt com.docker.network.driver.mtu=1450 \
  custom-network

❓ 问题6:容器重启后IP地址变化

问题: 容器重启后IP地址会改变,导致其他容器无法连接

解决方案:

  1. 使用容器名称而非IP
Bash
# ✅ 推荐:使用容器名称
docker exec container1 curl http://container2:8080

# ❌ 不推荐:使用IP地址
docker exec container1 curl http://172.17.0.3:8080
  1. 使用网络别名
Bash
# 连接容器时指定别名
docker network connect \
  --alias web \
  --alias api \
  app-network container

# 使用别名访问
docker exec other-container curl http://web:8080
  1. 使用固定IP(不推荐)
Bash
# 创建支持固定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
  1. 使用Docker Compose服务名
YAML
# docker-compose.yml
services:  # services定义各个服务容器
  web:
    image: nginx
  api:
    image: node-app
    environment:
      WEB_URL: http://web:80

❓ 问题7:跨主机容器通信

场景: 容器分布在不同的主机上,需要互相通信

解决方案:

  1. 使用Overlay网络(推荐)
Bash
# 初始化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
  1. 使用Macvlan网络
Bash
# 在每台主机上创建相同的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
  1. 使用第三方网络插件
Bash
# 安装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网络核心要点:

  1. 理解网络模式:Bridge、Host、None、Overlay、Macvlan各有适用场景
  2. 合理规划网络:为不同应用创建独立的网络
  3. 使用容器名称:避免依赖IP地址
  4. 善用Docker Compose:简化多容器网络管理
  5. 掌握故障排查:能够快速定位和解决网络问题

最佳实践:

✅ 为每个应用创建独立的网络 ✅ 使用容器名称而非IP地址进行通信 ✅ 合理配置端口映射,注意安全性 ✅ 使用Docker Compose管理复杂应用 ✅ 定期清理未使用的网络 ✅ 监控网络性能,及时优化

学习建议:

  1. 从简单的Bridge网络开始学习
  2. 动手实践每个网络模式
  3. 遇到问题时,使用docker inspectdocker logs排查
  4. 阅读Docker官方文档,了解最新特性
  5. 关注社区动态,学习最佳实践

🎉 恭喜!

你已经掌握了Docker网络的核心知识!现在你可以:

  • ✅ 理解Docker网络的工作原理
  • ✅ 创建和管理自定义网络
  • ✅ 配置容器间的通信
  • ✅ 使用Docker Compose管理网络
  • ✅ 排查常见的网络问题

下一步建议:

  1. 在实际项目中应用这些知识
  2. 尝试不同的网络模式
  3. 学习Kubernetes网络(更高级的话题)
  4. 关注Docker网络的最新发展

祝你学习愉快!🚀