Skip to content

自定义网络

用户定义网络(User-defined Network)是 Docker 网络的最佳实践,相比默认 bridge 网络提供了更好的隔离性和服务发现能力。

创建自定义网络

bash
# 基本创建(使用默认 bridge 驱动)
docker network create my-network

# 指定驱动
docker network create --driver bridge my-network

# 指定子网和网关
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/16 \
  --gateway 172.20.0.1 \
  my-network

# 指定 IP 范围(从 CIDR 范围中分配 IP)
docker network create \
  --subnet 172.20.0.0/16 \
  --ip-range 172.20.10.0/24 \
  --gateway 172.20.0.1 \
  my-network

# 设置标签
docker network create \
  --label project=myapp \
  --label env=production \
  my-network

# 禁用容器间通信(只能访问外部网络)
docker network create \
  --driver bridge \
  --opt com.docker.network.bridge.enable_icc=false \
  isolated-network

查看网络详情

bash
# 列出所有网络
docker network ls

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

# 格式化输出(查看连接的容器)
docker network inspect my-network \
  --format '{{json .Containers}}' | python3 -m json.tool

# 查看网络子网配置
docker network inspect my-network \
  --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'

容器连接到自定义网络

创建时指定网络

bash
# 创建容器时加入网络
docker run -d --name web --network my-network nginx
docker run -d --name db --network my-network mysql:8.0 \
  -e MYSQL_ROOT_PASSWORD=secret

# 指定静态 IP
docker run -d \
  --name web \
  --network my-network \
  --ip 172.20.0.100 \
  nginx

已有容器加入网络

bash
# 将已运行的容器加入网络
docker network connect my-network existing-container

# 指定 IP 加入
docker network connect --ip 172.20.0.200 my-network existing-container

# 设置别名(同一网络中可通过别名访问)
docker network connect --alias myalias my-network existing-container

断开网络连接

bash
docker network disconnect my-network my-container

容器间通信

在同一用户定义网络中的容器,可以通过容器名直接通信(内置 DNS):

bash
# 创建网络和容器
docker network create app-net

docker run -d --name mysql \
  --network app-net \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=mydb \
  mysql:8.0

docker run -d --name api \
  --network app-net \
  -e DB_HOST=mysql \
  -e DB_PORT=3306 \
  myapi:latest

# api 容器内可以直接通过 "mysql" 名称访问数据库
docker exec api ping mysql         # 可以 ping 通
docker exec api curl http://mysql:80  # 通过名称访问

多网络配置

一个容器可以同时连接多个网络,实现网络分层:

bash
# 前端网络(对外暴露)
docker network create frontend-net

# 后端网络(仅内部通信)
docker network create backend-net

# Nginx 连接两个网络(作为反向代理)
docker run -d --name nginx \
  --network frontend-net \
  -p 80:80 \
  nginx

docker network connect backend-net nginx

# API 只在后端网络
docker run -d --name api \
  --network backend-net \
  myapi

# 数据库只在后端网络
docker run -d --name db \
  --network backend-net \
  mysql:8.0

# 架构:Internet → nginx(frontend-net + backend-net) → api(backend-net) → db(backend-net)

网络别名

同一网络中可以为容器设置别名,实现简单的负载均衡:

bash
docker network create service-net

# 两个容器共享同一个别名(Round-robin DNS)
docker run -d --network service-net --network-alias api myapi:v1
docker run -d --network service-net --network-alias api myapi:v2

# 访问 "api" 会随机路由到其中一个
docker run --rm --network service-net alpine nslookup api
# 会返回两个 IP 地址

实用配置示例

Web 应用的网络架构

bash
#!/bin/bash

# 创建网络
docker network create --driver bridge \
  --subnet 172.20.0.0/24 \
  webapp-net

# 数据库
docker run -d \
  --name postgres \
  --network webapp-net \
  --ip 172.20.0.10 \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16-alpine

# 缓存
docker run -d \
  --name redis \
  --network webapp-net \
  --ip 172.20.0.11 \
  redis:alpine

# 后端 API
docker run -d \
  --name api \
  --network webapp-net \
  --ip 172.20.0.20 \
  -e DATABASE_URL=postgresql://postgres:secret@postgres:5432/mydb \
  -e REDIS_URL=redis://redis:6379 \
  myapi:latest

# 前端(仅 API 通过 nginx 对外暴露)
docker run -d \
  --name nginx \
  --network webapp-net \
  -p 80:80 \
  -p 443:443 \
  nginx:alpine

删除网络

bash
# 删除指定网络(需要先断开所有容器)
docker network rm my-network

# 删除多个网络
docker network rm net1 net2 net3

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

# 强制删除(-f 忽略确认)
docker network prune -f

排查网络问题

bash
# 查看容器 IP 地址
docker inspect container --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'

# 测试容器间连通性
docker exec container1 ping container2
docker exec container1 curl http://container2:8080

# 查看容器 DNS 解析
docker exec container1 nslookup container2
docker exec container1 cat /etc/resolv.conf

# 查看容器路由表
docker exec container1 ip route

# 抓包(需要 tcpdump)
docker exec container1 tcpdump -i eth0 -n

总结

自定义网络的核心优势:

  1. 容器名 DNS 解析:无需记忆 IP,通过名称直接访问
  2. 网络隔离:不同应用使用不同网络,互不干扰
  3. 动态管理:随时连接/断开容器
  4. 网络别名:实现简单的服务发现

最佳实践:为每个应用创建独立的自定义网络,只通过 Nginx/负载均衡器对外暴露必要端口。