Docker 网络基础
每个容器默认拥有独立的网络命名空间(Network Namespace),意味着它有自己独立的:
- 网络接口(
eth0,IP 地址如172.17.0.2) - 路由表(如何到达其他网络)
- 端口空间(容器内的 80 端口与宿主机的 80 端口是独立的)
- iptables 规则
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 网络提供:
- 自动 DNS 解析:容器可以通过容器名(而非 IP)互相访问,如
http://db:5432 - 更好的隔离:只有加入同一网络的容器才能互相通信
- 动态连接/断开:运行中的容器可以随时加入或离开网络
- 可配置网段:可以自定义 IP 地址范围
# 创建用户自定义网络
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章将详细介绍。