Docker 网络配置

核心知识点

1. Docker 网络基础

1.1 网络驱动类型

Docker 提供多种网络驱动,适用于不同的使用场景:

┌─────────────────────────────────────────────────────────────┐
│                   Docker 网络驱动                          │
├─────────────────────────────────────────────────────────────┤
│                                                      │
│  Bridge (桥接) ──> 默认模式,容器间通信              │
│  Host (主机)   ──> 共享主机网络栈                    │
│  None (无)     ──> 独立网络,无网络访问              │
│  Overlay      ──> 跨主机容器通信(集群)             │
│  Macvlan      ──> 直接连接物理网络                   │
│  IPvlan       ──> 共享物理接口                       │
│                                                      │
└─────────────────────────────────────────────────────────────┘

1.2 网络架构

Docker 网络采用虚拟网桥架构:

┌─────────────────────────────────────────────────────────────┐
│                    宿主机                                │
├─────────────────────────────────────────────────────────────┤
│                                                      │
│  ┌──────────────┐         ┌──────────────┐            │
│  │  容器 A      │         │  容器 B      │            │
│  │  172.17.0.2  │         │  172.17.0.3  │            │
│  └──────┬───────┘         └──────┬───────┘            │
│         │                        │                       │
│         └────────┬───────────────┘                       │
│                  │                                      │
│         ┌────────▼────────┐                           │
│         │  docker0 网桥   │  172.17.0.1              │
│         └────────┬────────┘                           │
│                  │                                      │
│         ┌────────▼────────┐                           │
│         │  物理网卡 eth0  │                           │
│         └─────────────────┘                           │
│                                                      │
└─────────────────────────────────────────────────────────────┘

2. 网络模式详解

2.1 Bridge 模式(默认)

Bridge 模式是 Docker 的默认网络模式,容器通过虚拟网桥连接。

# 使用默认 bridge 网络运行容器
docker run -d --name web1 nginx:latest
docker run -d --name web2 nginx:latest

# 查看容器网络
docker inspect web1 | grep -A 10 NetworkSettings

# 查看网桥信息
docker network inspect bridge

# 容器间通信
docker exec web1 ping web2

2.2 Host 模式

Host 模式使容器共享宿主机的网络命名空间。

# 使用 host 网络模式
docker run -d --network host --name web-host nginx:latest

# 查看容器网络
docker inspect web-host | grep -A 5 NetworkMode

# 注意:端口映射在 host 模式下无效
docker run -d --network host -p 8080:80 nginx:latest
# 容器将直接监听宿主机的 80 端口

2.3 None 模式

None 模式为容器创建独立的网络环境,无网络访问。

# 使用 none 网络模式
docker run -d --network none --name web-none nginx:latest

# 查看容器网络
docker inspect web-none | grep -A 5 NetworkMode

# 容器无法访问外部网络
docker exec web-none ping google.com
# ping: bad address 'google.com'

3. 自定义网络

3.1 创建 Bridge 网络

# 创建自定义 bridge 网络
docker network create my-bridge

# 指定子网和网关
docker network create \
    --driver bridge \
    --subnet 192.168.100.0/24 \
    --gateway 192.168.100.1 \
    my-custom-bridge

# 创建网络时指定 IP 范围
docker network create \
    --driver bridge \
    --subnet 172.20.0.0/16 \
    --ip-range 172.20.10.0/24 \
    my-limited-bridge

# 查看网络列表
docker network ls

# 查看网络详细信息
docker network inspect my-bridge

3.2 连接容器到网络

# 创建容器时指定网络
docker run -d --network my-bridge --name app1 nginx:latest
docker run -d --network my-bridge --name app2 nginx:latest

# 将现有容器连接到网络
docker run -d --name app3 nginx:latest
docker network connect my-bridge app3

# 断开容器与网络的连接
docker network disconnect my-bridge app3

# 连接时指定 IP 地址
docker network connect \
    --ip 192.168.100.100 \
    my-bridge \
    app1

3.3 创建 Overlay 网络

Overlay 网络用于跨主机的容器通信(需要 Docker Swarm)。

# 初始化 Swarm
docker swarm init

# 创建 overlay 网络
docker network create \
    --driver overlay \
    --attachable \
    my-overlay

# 在 overlay 网络上运行服务
docker service create \
    --name my-service \
    --network my-overlay \
    nginx:latest

# 查看网络
docker network ls
docker network inspect my-overlay

4. 容器间通信

4.1 通过容器名称通信

# 创建自定义网络
docker network create app-network

# 启动 Web 服务器
docker run -d \
    --network app-network \
    --name web-server \
    nginx:latest

# 启动应用容器
docker run -d \
    --network app-network \
    --name app-client \
    alpine:latest \
    sh -c "while true; do wget -qO- http://web-server; sleep 5; done"

# 查看客户端日志
docker logs app-client

# 测试通信
docker exec app-client ping web-server

4.2 通过 IP 地址通信

# 查看容器 IP 地址
docker inspect web-server | grep IPAddress

# 使用 IP 地址通信
docker exec app-client wget -qO- http://172.18.0.2

# 查看网络中的所有容器
docker network inspect app-network | grep -A 10 Containers

4.3 多网络连接

# 创建两个网络
docker network create frontend
docker network create backend

# 启动数据库容器(连接到 backend 网络)
docker run -d \
    --name database \
    --network backend \
    -e POSTGRES_PASSWORD=password \
    postgres:13

# 启动应用容器(连接到两个网络)
docker run -d \
    --name app \
    --network frontend \
    nginx:latest

docker network connect backend app

# 验证网络连接
docker inspect app | grep -A 20 Networks

# 从不同网络访问
docker exec app ping database

5. 端口映射

5.1 基本端口映射

# 映射单个端口
docker run -d -p 8080:80 --name web1 nginx:latest

# 映射多个端口
docker run -d \
    -p 80:80 \
    -p 443:443 \
    --name web2 \
    nginx:latest

# 映射到随机端口
docker run -d -p 80 --name web3 nginx:latest

# 查看端口映射
docker port web1
docker ps

5.2 高级端口映射

# 绑定到特定接口
docker run -d -p 127.0.0.1:8080:80 --name web-local nginx:latest
docker run -d -p 0.0.0.0:8080:80 --name web-all nginx:latest

# 映射 UDP 端口
docker run -d -p 53:53/udp --name dns-server bind9

# 映射端口范围
docker run -d -p 8000-8010:8000-8010 --name web-range nginx:latest

6. DNS 配置

6.1 容器 DNS 设置

# 使用宿主机 DNS
docker run -d --dns 8.8.8.8 --name dns-custom nginx:latest

# 使用多个 DNS 服务器
docker run -d \
    --dns 8.8.8.8 \
    --dns 8.8.4.4 \
    --name dns-multi \
    nginx:latest

# 添加 DNS 搜索域
docker run -d \
    --dns-search example.com \
    --name dns-search \
    nginx:latest

# 查看容器 DNS 配置
docker exec dns-custom cat /etc/resolv.conf

6.2 自定义 DNS 服务器

# 运行 DNS 服务器
docker run -d \
    --name dns-server \
    -p 53:53/udp \
    -p 53:53 \
    andyshinn/dnsmasq

# 配置容器使用自定义 DNS
docker run -d \
    --dns $(docker inspect dns-server | grep IPAddress | head -1 | awk '{print $2}' | tr -d '"') \
    --name dns-client \
    alpine:latest \
    nslookup google.com

7. 网络安全

7.1 网络隔离

# 创建隔离的网络
docker network create isolated-network

# 启动隔离的容器
docker run -d --network isolated-network --name isolated-app nginx:latest

# 尝试从其他容器访问(失败)
docker run --rm alpine:latest ping isolated-app
# ping: bad address 'isolated-app'

7.2 网络访问控制

# 创建内部网络
docker network create --internal internal-network

# 启动容器
docker run -d --network internal-network --name internal-app nginx:latest

# 容器无法访问外部网络
docker exec internal-app ping google.com
# ping: bad address 'google.com'

实用案例分析

案例 1:Web 应用与数据库通信

场景描述

部署一个包含 Nginx 和 PostgreSQL 的 Web 应用,实现容器间通信。

操作步骤

# 1. 创建应用网络
docker network create app-network

# 2. 启动 PostgreSQL 数据库
docker run -d \
    --name postgres \
    --network app-network \
    -e POSTGRES_DB=myapp \
    -e POSTGRES_USER=myapp \
    -e POSTGRES_PASSWORD=password \
    -v postgres-data:/var/lib/postgresql/data \
    postgres:13

# 3. 等待数据库启动
sleep 10

# 4. 启动 Nginx Web 服务器
docker run -d \
    --name nginx \
    --network app-network \
    -p 80:80 \
    nginx:latest

# 5. 测试容器间通信
docker exec nginx ping postgres

# 6. 从 Nginx 容器测试数据库连接
docker exec nginx sh -c "apt-get update && apt-get install -y postgresql-client"
docker exec nginx psql -h postgres -U myapp -d myapp -c "SELECT version();"

# 7. 查看网络配置
docker network inspect app-network

# 8. 清理
docker stop nginx postgres
docker rm nginx postgres
docker network rm app-network

案例 2:多网络架构

场景描述

创建前端、后端和数据库三层架构,使用不同的网络进行隔离。

操作步骤

# 1. 创建网络
docker network create frontend
docker network create backend
docker network create database

# 2. 启动数据库(仅连接到 database 网络)
docker run -d \
    --name mysql \
    --network database \
    -e MYSQL_ROOT_PASSWORD=rootpassword \
    -e MYSQL_DATABASE=myapp \
    -v mysql-data:/var/lib/mysql \
    mysql:5.7

# 3. 启动后端应用(连接到 backend 和 database 网络)
docker run -d \
    --name backend \
    --network backend \
    -e DB_HOST=mysql \
    -e DB_PASSWORD=rootpassword \
    node:16-alpine \
    node server.js

docker network connect database backend

# 4. 启动前端应用(连接到 frontend 和 backend 网络)
docker run -d \
    --name frontend \
    --network frontend \
    -p 80:80 \
    nginx:latest

docker network connect backend frontend

# 5. 验证网络连接
docker inspect backend | grep -A 30 Networks

# 6. 测试通信
docker exec frontend ping backend
docker exec backend ping mysql

# 7. 查看网络拓扑
docker network ls
docker network inspect frontend
docker network inspect backend
docker network inspect database

# 8. 清理
docker stop frontend backend mysql
docker rm frontend backend mysql
docker network rm frontend backend database

案例 3:端口映射与负载均衡

场景描述

运行多个 Web 容器,通过端口映射实现负载均衡。

操作步骤

# 1. 启动多个 Web 容器
docker run -d --name web1 -p 8081:80 nginx:latest
docker run -d --name web2 -p 8082:80 nginx:latest
docker run -d --name web3 -p 8083:80 nginx:latest

# 2. 查看端口映射
docker port web1
docker port web2
docker port web3

# 3. 测试访问
curl http://localhost:8081
curl http://localhost:8082
curl http://localhost:8083

# 4. 创建负载均衡器
docker run -d \
    --name lb \
    -p 80:80 \
    nginx:latest

# 5. 配置负载均衡
docker exec lb sh -c "cat > /etc/nginx/conf.d/lb.conf << 'EOF'
upstream backend {
    server web1:80;
    server web2:80;
    server web3:80;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
    }
}
EOF"

# 6. 连接网络
docker network connect app-network lb
docker network connect app-network web1
docker network connect app-network web2
docker network connect app-network web3

# 7. 重启负载均衡器
docker restart lb

# 8. 测试负载均衡
for i in {1..10}; do
    curl -s http://localhost | grep -o "Welcome to nginx"
done

# 9. 清理
docker stop lb web1 web2 web3
docker rm lb web1 web2 web3
docker network rm app-network

最佳实践

  1. 使用自定义网络:避免使用默认的 bridge 网络,提高网络隔离性。

  2. 合理规划网络架构:根据应用需求选择合适的网络模式。

  3. 使用有意义的网络名称:便于识别和管理网络。

  4. 定期清理未使用的网络:释放系统资源。

# 清理未使用的网络
docker network prune

# 查看所有网络
docker network ls

# 查看网络详细信息
docker network inspect network-name
  1. 监控网络流量:及时发现网络问题。
# 查看容器网络统计
docker stats --no-stream

# 使用 tcpdump 抓包
docker exec container-name tcpdump -i eth0
  1. 使用 DNS 服务发现:避免硬编码 IP 地址。
# 使用容器名称而非 IP 地址
docker exec app1 ping app2

总结

本教程详细介绍了 Docker 网络的配置方法,包括网络模式、自定义网络、容器间通信、端口映射等。通过实际案例,我们学习了如何构建多网络架构、实现负载均衡以及配置 DNS。掌握这些技能后,可以设计和管理复杂的 Docker 网络架构。

« 上一篇 Docker 容器管理 下一篇 » Docker 存储管理