Chapter 05

Docker 网络

理解容器网络隔离原理,掌握容器间通信与端口映射

Docker 网络基础

每个容器默认拥有独立的网络命名空间(Network Namespace),意味着它有自己独立的:

Docker 通过网络驱动(Network Driver)管理容器的网络连接,提供多种网络模式。

网络驱动类型

bridge(桥接网络)— 默认

Docker 安装时会创建一个名为 docker0 的虚拟网桥。所有使用默认 bridge 网络的容器都连接到这个网桥,通过 IP 地址互相通信。


# 默认情况下,容器连接到 docker0 网桥
# 宿主机 IP:172.17.0.1
# 容器 A:172.17.0.2
# 容器 B:172.17.0.3

宿主机
├── docker0(172.17.0.1)
│   ├── container-a(172.17.0.2)
│   └── container-b(172.17.0.3)
└── eth0(宿主机外网接口)
⚠️

默认 bridge 网络的限制 — 默认 bridge 网络中的容器只能通过 IP 地址互相访问,无法通过容器名称(hostname)访问。这在容器 IP 可能变化的场景下很不方便。推荐使用用户自定义 bridge 网络。

host(宿主机网络)

容器直接共享宿主机的网络命名空间,没有网络隔离。容器内绑定 80 端口,宿主机的 80 端口就被占用。


# 使用 host 网络(不需要 -p 端口映射)
docker run --network host nginx
💡

Linux 最佳,Mac 不支持 — host 网络只在 Linux 上有意义(直接使用宿主机网络,性能最好)。在 macOS 上,Docker 运行在 Linux VM 中,host 网络实际上是该 VM 的网络,而非 Mac 的网络。

none(无网络)

容器完全没有网络接口(只有 loopback),适合需要完全网络隔离的批处理任务。


docker run --network none alpine sh

overlay(覆盖网络)

跨多台宿主机的容器通信网络,用于 Docker Swarm 模式。容器可以跨机器通过名称互相访问,底层通过 VXLAN 封装实现。


# 在 Swarm 中创建 overlay 网络
docker network create --driver overlay my-overlay

用户自定义 Bridge 网络的优势

强烈推荐为自己的应用创建专属网络,而不使用默认的 bridge。用户自定义 bridge 网络提供:


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

# 两个容器加入同一网络
docker run -d --name db --network my-app-network postgres:16
docker run -d --name web --network my-app-network myapp:1.0

# web 容器内可以直接用容器名访问 db!
# 如:postgresql://db:5432/mydb

端口映射(Port Mapping)

容器的网络是隔离的,外部(宿主机或网络中的其他机器)默认无法访问容器端口。通过端口映射,Docker 在宿主机上配置 iptables 规则,将宿主机端口的流量转发给容器。


# 映射宿主机 8080 到容器 80
docker run -p 8080:80 nginx

# 绑定到特定 IP(只允许 localhost 访问)
docker run -p 127.0.0.1:8080:80 nginx

# 随机分配宿主机端口
docker run -p 80 nginx    # 宿主机随机端口 → 容器80

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

# 查看实际映射的端口
docker port my-nginx
⚠️

安全提示 — 默认 -p 8080:80 会监听所有网络接口(0.0.0.0),意味着网络上的任何机器都可访问。在生产环境中,建议使用 -p 127.0.0.1:8080:80 并通过 Nginx/负载均衡器转发外部流量。

容器间通信示例

一个典型场景:Web 应用通过数据库容器名直接访问数据库:


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

# 2. 启动数据库容器(仅在内网,不对外暴露端口)
docker run -d \
  --name postgres-db \
  --network webapp-net \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  postgres:16-alpine

# 3. 启动 Web 应用,通过容器名 'postgres-db' 连接数据库
docker run -d \
  --name web-app \
  --network webapp-net \
  -p 3000:3000 \
  -e DATABASE_URL="postgresql://postgres:secret@postgres-db:5432/myapp" \
  myapp:1.0

# web-app 容器内部可以用 postgres-db 作为主机名访问数据库

网络命令速查


# 列出所有网络
docker network ls

# 创建网络(默认 bridge 驱动)
docker network create my-net

# 创建并指定网段
docker network create --subnet 192.168.100.0/24 my-net

# 查看网络详情(连接的容器、IP 等)
docker network inspect my-net

# 将运行中的容器连接到网络
docker network connect my-net my-container

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

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

# 清理所有未使用网络
docker network prune

实战:三容器网络架构

搭建前端 + 后端 API + 数据库的三层架构,每层之间网络隔离:


# 创建两个网络:前端-后端 / 后端-数据库
docker network create frontend-net
docker network create backend-net

# 数据库:只在 backend-net(对前端不可见)
docker run -d --name db \
  --network backend-net \
  -e POSTGRES_PASSWORD=secret \
  postgres:16-alpine

# 后端 API:同时加入两个网络
docker run -d --name api \
  --network backend-net \
  -e DB_HOST=db \
  myapi:1.0
docker network connect frontend-net api  # 再加入前端网络

# 前端:只在 frontend-net,通过 'api' 容器名访问后端
docker run -d --name web \
  --network frontend-net \
  -p 80:80 \
  -e API_URL=http://api:8000 \
  myfrontend:1.0

# 结果:web → api → db
# web 无法直接访问 db(不在同一网络)

实际开发中 — 手动管理多容器网络很繁琐。Docker Compose 会自动为每个项目创建独立网络,并支持服务间通过名称互访。第7章将详细介绍。