容器之间怎么通信?

问题:默认情况下,容器之间是隔离的,无法直接访问。

场景

  • Web应用容器需要访问数据库容器
  • 多个微服务容器需要互相调用
  • 外部需要访问容器内的服务

解决:使用Docker网络实现容器间通信。

Docker网络基础

网络类型

1. bridge(桥接网络,默认)

特点

  • 默认网络类型
  • 每个容器分配独立IP
  • 容器通过bridge互相通信
  • 通过端口映射对外暴露服务

原理:

宿主机
    │
    ├── docker0(虚拟网桥)
    │       │
    │       ├── 容器A (172.17.0.2)
    │       ├── 容器B (172.17.0.3)
    │       └── 容器C (172.17.0.4)

2. host(主机网络)

特点

  • 容器使用宿主机网络栈
  • 没有网络隔离
  • 性能最好
  • 不需要端口映射

使用场景

  • 高性能应用
  • 需要直接访问宿主机网络
docker run --network=host nginx

3. none(无网络)

特点

  • 容器没有网络
  • 完全隔离
  • 适合不需要网络的应用
docker run --network=none alpine sleep 3600

4. overlay(覆盖网络)

特点

  • 跨主机容器通信
  • 需要Swarm或Kubernetes
  • 生产环境常用

使用场景

  • 分布式应用
  • 微服务架构

网络基本操作

1. 查看网络

# 列出所有网络
docker network ls

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

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

输出示例:

NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
abc123def456   host      host      local
123abc456def   none      null      local

2. 创建网络

# 创建bridge网络
docker network create my-network

# 创建自定义bridge网络(指定子网)
docker network create \
  --driver=bridge \
  --subnet=172.20.0.0/16 \
  --ip-range=172.20.10.0/24 \
  --gateway=172.20.10.1 \
  my-custom-network

# 创建overlay网络(Swarm集群)
docker network create --driver=overlay my-overlay-network

3. 删除网络

# 删除网络
docker network rm my-network

# 删除未使用的网络
docker network prune

4. 连接容器到网络

# 运行容器时指定网络
docker run -d --network=bridge --name myapp nginx

# 将已有容器连接到网络
docker network connect my-network myapp

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

# 连接时指定别名
docker network connect --alias web my-network myapp

容器间通信

场景1:同一网络中的容器通信

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

# 2. 运行Web应用容器
docker run -d \
  --network=app-network \
  --name webapp \
  nginx

# 3. 运行数据库容器
docker run -d \
  --network=app-network \
  --name db \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql:8.0

# 4. Web应用可以直接通过名称访问数据库
docker exec webapp ping db
docker exec webapp nc -zv db 3306

关键点

  • 同一网络中的容器可以通过容器名称互相访问
  • Docker内置DNS自动解析容器名称

场景2:跨网络容器通信

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

# 2. 前端容器连接到前端网络
docker run -d \
  --network=frontend-network \
  --name frontend \
  nginx

# 3. 后端容器同时连接到前后端网络
docker run -d \
  --name backend \
  --network=backend-network \
  nginx

# 4. 将后端也连接到前端网络
docker network connect frontend-network backend

# 5. 前端可以访问后端
docker exec frontend ping backend

场景3:固定IP地址

# 创建自定义子网
docker network create \
  --subnet=172.20.0.0/16 \
  --ip-range=172.20.10.0/24 \
  --gateway=172.20.10.1 \
  my-network

# 运行容器时指定IP
docker run -d \
  --network=my-network \
  --ip=172.20.10.100 \
  --name myapp \
  nginx

# 验证IP
docker inspect myapp | grep IPAddress

端口映射

基本端口映射

# 映射容器端口到宿主机
docker run -d -p 80:80 --name web nginx

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

# 映射到随机端口
docker run -d -P --name web nginx

# 查看随机分配的端口
docker port web

绑定到特定地址

# 只绑定到localhost(只允许本地访问)
docker run -d -p 127.0.0.1:80:80 --name web nginx

# 绑定到所有接口(默认)
docker run -d -p 0.0.0.0:80:80 --name web nginx

# 绑定到特定IP
docker run -d -p 192.168.1.100:80:80 --name web nginx

端口范围映射

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

实战:完整的多容器应用

架构

┌─────────────────────────────────────────────────────┐
│                      宿主机                          │
│  ┌───────────────────────────────────────────────┐  │
│  │              app-network(自定义网络)         │  │
│  │                                               │  │
│  │  ┌────────────┐      ┌────────────┐         │  │
│  │  │  Web容器   │─────>│  DB容器    │         │  │
│  │  │  (nginx)   │      │  (mysql)   │         │  │
│  │  └────────────┘      └────────────┘         │  │
│  │                                               │  │
│  └───────────────────────────────────────────────┘  │
│                                                     │
│  端口映射:8080 -> Web容器80                         │
└─────────────────────────────────────────────────────┘

完整步骤

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

# 2. 运行MySQL容器
docker run -d \
  --name db \
  --network=app-network \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -e MYSQL_DATABASE=mydb \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

# 3. 等待MySQL启动
sleep 20

# 4. 创建测试数据
docker exec db mysql -uroot -p123456 -e \
  "USE mydb; CREATE TABLE users (id INT, name VARCHAR(100)); INSERT INTO users VALUES (1, 'Alice');"

# 5. 运行Web容器
docker run -d \
  --name web \
  --network=app-network \
  -p 8080:80 \
  nginx

# 6. 验证网络连通性
docker exec web ping db
docker exec web nc -zv db 3306

# 7. 访问Web应用
curl http://localhost:8080

网络排错

1. 检查网络连接

# 检查容器是否在同一网络
docker inspect web | grep -A 10 Networks
docker inspect db | grep -A 10 Networks

2. 测试网络连通性

# ping测试
docker exec web ping db

# 端口测试
docker exec web nc -zv db 3306

# DNS解析
docker exec web nslookup db

3. 查看网络日志

# 查看容器网络接口
docker exec web ip addr

# 查看路由表
docker exec web ip route

# 查看网络统计
docker exec web netstat -tuln

4. 抓包分析

# 安装tcpdump(需要基础镜像支持)
docker exec web apt-get update && apt-get install -y tcpdump

# 抓包
docker exec web tcpdump -i eth0

网络性能优化

1. 使用host网络(无NAT开销)

# 高性能场景
docker run --network=host nginx

2. 减少网络跳数

# 直接连接,避免多层NAT
docker network create --driver=bridge my-network

3. 使用DNS缓存

# 使用--dns选项
docker run --dns=8.8.8.8 --dns=114.114.114.114 nginx

安全考虑

1. 隔离不同环境的网络

# 开发环境
docker network create dev-network

# 测试环境
docker network create test-network

# 生产环境
docker network create prod-network

2. 限制网络访问

# 只允许特定网络访问
docker run --network=none app
# 然后只连接到必要的网络
docker network connect app-network app

3. 使用加密通信

# 使用TLS加密的overlay网络(Swarm)
docker network create --driver=overlay --opt encrypted my-encrypted-network

本章小结

  • 网络类型:bridge(桥接)、host(主机)、none(无网络)、overlay(覆盖)
  • 网络操作:创建、查看、删除网络
  • 容器通信:同一网络通过容器名称访问,跨网络需要连接
  • 端口映射:映射容器端口到宿主机
  • 网络排错:检查连通性、DNS解析、抓包分析

现在已经掌握了网络管理,下一章我们来学习Docker Compose!

继续学下去,马上就能一键启动复杂项目了!