4. 自定义Bridge网络:创建与管理自定义网络、容器互联、DNS解析
Docker 默认的 bridge 网络虽然开箱即用,但在生产环境或复杂微服务场景下,其局限性非常明显:容器只能通过 IP 地址通信,且无法实现服务发现。自定义 Bridge 网络正是为了解决这些问题而设计的,它提供了内置的 DNS 解析能力,允许容器通过容器名直接互联,是构建容器化应用网络的基础设施。
4.1 自定义Bridge网络 vs 默认Bridge网络
在深入操作之前,先明确自定义 Bridge 网络相比默认网络的核心优势:
| 对比维度 | 默认 Bridge 网络 | 自定义 Bridge 网络 |
|---|---|---|
| DNS 解析 | 不支持容器名解析,只能通过 --link 单向连接 |
内置 DNS,自动解析所有容器名到对应 IP |
| 网络隔离 | 所有未指定网络的容器默认加入,隔离性差 | 独立网络空间,只有加入该网络的容器才能通信 |
| 动态加入/离开 | 容器重启后 IP 可能变化,需手动维护 | 支持动态连接和断开,DNS 自动更新 |
| 配置灵活性 | 仅支持默认子网,无法自定义网段 | 可指定子网、网关、IP 范围 |
| 适用场景 | 单机简单测试,容器间无强依赖 | 微服务架构、多容器协作、需要服务发现的场景 |
最佳实践: 在生产环境中,始终优先使用自定义 Bridge 网络而非默认网络。即使只有一个应用需要多个容器协作,自定义网络带来的 DNS 解析能力也能大幅简化配置管理。
4.2 创建与管理自定义Bridge网络
Docker 提供了 docker network 命令族来管理网络资源。以下是创建和管理自定义 Bridge 网络的完整流程。
4.2.1 创建网络
使用 docker network create 命令创建自定义 Bridge 网络。最简形式只需指定网络名称:
# 创建默认配置的自定义网络
docker network create my-net
# 创建时指定子网和网关
docker network create --subnet=172.20.0.0/16 --gateway=172.20.0.1 my-net-prod
# 创建时指定 IP 范围(限制自动分配的 IP 池)
docker network create --subnet=172.20.0.0/16 --ip-range=172.20.5.0/24 my-net-limited
常用参数说明:
| 参数 | 说明 | 示例 |
|---|---|---|
--driver |
指定网络驱动,默认 bridge | --driver bridge |
--subnet |
CIDR 格式的子网地址 | --subnet=10.10.0.0/16 |
--gateway |
指定网关 IP | --gateway=10.10.0.1 |
--ip-range |
限制自动分配的 IP 范围 | --ip-range=10.10.1.0/24 |
--label |
为网络添加元数据标签 | --label env=prod |
4.2.2 管理网络
网络创建后,可以通过以下命令进行管理:
# 列出所有网络
docker network ls
# 查看网络详细信息(包括连接的容器和 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 rm 会报错。可以使用 docker network disconnect --force 强制断开。
4.3 容器互联与DNS解析
自定义 Bridge 网络最强大的特性是内置的 DNS 解析。当容器加入同一个自定义网络时,Docker 内置的 DNS 服务器会自动将容器名解析为容器的 IP 地址。
4.3.1 通过容器名互联
以下示例演示两个容器在自定义网络中通过容器名通信:
# 1. 创建自定义网络
docker network create app-net
# 2. 启动第一个容器(Web 服务)
docker run -d --name web --network app-net nginx:alpine
# 3. 启动第二个容器(客户端),通过容器名访问 web
docker run --rm --network app-net alpine:latest \
sh -c "ping -c 3 web"
在客户端容器中,ping web 会自动解析为 web 容器的 IP 地址,无需手动配置 /etc/hosts 或使用 --link。
4.3.2 多网络与别名
一个容器可以同时加入多个网络,实现网络隔离与互联的灵活组合。同时,可以为容器设置网络别名,实现更灵活的服务发现:
# 创建两个网络
docker network create front-net
docker network create back-net
# 启动数据库容器,只加入 back-net
docker run -d --name db --network back-net mysql:8.0
# 启动应用容器,同时加入两个网络,并在 front-net 中设置别名
docker run -d --name app \
--network front-net \
--network-alias api-service \
alpine:latest sleep 3600
# 将 app 容器也连接到 back-net
docker network connect back-net app
# 验证:在 front-net 中可以通过 api-service 访问 app
docker run --rm --network front-net alpine:latest \
sh -c "ping -c 2 api-service"
4.4 自定义Bridge网络架构图
下图展示了自定义 Bridge 网络的核心架构,包括网络创建、容器加入、DNS 解析和跨网络通信的完整流程:
4.5 实战:构建微服务网络
以下是一个完整的微服务网络搭建示例,展示如何利用自定义 Bridge 网络实现服务发现和网络隔离:
# 1. 创建业务网络
docker network create --subnet=10.10.0.0/16 --gateway=10.10.0.1 micro-net
# 2. 启动数据库(只对内网暴露)
docker run -d --name mysql-db \
--network micro-net \
--network-alias db \
-e MYSQL_ROOT_PASSWORD=root123 \
mysql:8.0
# 3. 启动 Redis 缓存
docker run -d --name redis-cache \
--network micro-net \
--network-alias redis \
redis:7-alpine
# 4. 启动后端 API 服务
docker run -d --name api-service \
--network micro-net \
--network-alias api \
-p 8080:8080 \
my-api:latest
# 5. 启动前端 Nginx(反向代理到 api)
docker run -d --name frontend \
--network micro-net \
-p 80:80 \
nginx:alpine
# 6. 验证 DNS 解析
docker run --rm --network micro-net alpine:latest \
sh -c "nslookup api && nslookup db && nslookup redis"
关键点: 在这个架构中,
api-service 可以通过容器名 db 和 redis 直接访问数据库和缓存,无需硬编码 IP 地址。即使容器重启导致 IP 变化,DNS 会自动更新,应用无需任何配置变更。
4.6 常见故障与排查
在使用自定义 Bridge 网络时,可能会遇到以下问题:
| 故障现象 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
| 容器名无法解析 | 容器不在同一自定义网络 | docker inspect <容器名> | grep Networks |
使用 docker network connect 将容器加入同一网络 |
| 网络删除失败 | 仍有容器连接 | docker network inspect <网络名> |
先断开所有容器,或使用 --force 强制删除 |
| IP 地址冲突 | 手动指定了已分配的 IP | docker network inspect <网络名> | grep IPv4Address |
使用 --ip-range 限制自动分配范围,避免手动指定 |
| 跨网络通信失败 | 容器未加入目标网络 | docker exec <容器名> ip addr |
将容器同时加入多个网络,或使用网络别名 |
重要提醒: 自定义 Bridge 网络的 DNS 解析仅在同一网络内生效。如果容器 A 和容器 B 不在同一个自定义网络中,即使它们在同一台宿主机上,也无法通过容器名互相访问。这是 Docker 网络隔离的设计原则。