外观
项目 5:Docker 网络隔离与微服务互联
约 2375 字大约 8 分钟
DockerNetworkDNS微服务互联
2026-05-29
项目目标
微服务架构中,前端容器需要访问后端数据库容器。如果你在代码里写死 IP 地址(如 172.17.0.3),容器删除重建、重新调度或接入网络变化后,整个应用就可能崩掉。
本课带你深入 Linux Network Namespace 底层,理解容器网络的隔离机制和打通原理,最终通过 Docker 自定义网络实现基于容器名称(DNS)的稳定服务互联。
一、容器网络为什么是"孤岛"?
Docker 利用 Linux 的 Network Namespace 为每个容器创建独立的网络空间——独立的网卡、路由表、iptables 规则、IP 地址。
默认情况下容器从 172.17.0.0/16 网段获取私有 IP(如 172.17.0.2)。这个地址属于 Docker 管理的私有网络,外部客户端和浏览器不能把它当成稳定入口——这就是"孤岛"。
veth pair 与 docker0 网桥
为了让容器联网,Docker 启动时在宿主机上创建了一个叫 docker0 的虚拟网桥(想象成虚拟交换机),然后用 veth pair(虚拟以太网对)——一根"穿墙网线"——一头插容器 eth0,一头插 docker0。容器通过这根网线能访问外网,但外部网络要访问容器服务,通常仍需要端口发布。
🌐 容器网络:Namespace 与 veth pair
图解 Docker 如何将“网络孤岛”接入宿主机网络
步骤 1 / 6
【初始状态】宿主机拥有物理网卡 eth0(连接互联网),Docker 引擎已创建了 docker0 虚拟网桥。
☁️ 互联网
🖥️ 宿主机 (Host OS)
eth0 物理网卡
docker0 虚拟网桥
课堂速记图
这张图把本课的容器网络隔离、三种默认网络模式、自定义 bridge + DNS 服务发现和 Redis 互联实践串成一条线。建议先浏览一遍,后面做实验时再对照检查。

二、Docker 的三种默认网络模式
docker network ls| 模式 | 说明 | 适用场景 |
|---|---|---|
bridge | 默认网桥 docker0,容器接入后可上网、互相通信 | 一般用途 |
host | 容器直接使用宿主机网卡,无隔离 | 极少数高性能场景,有安全风险 |
none | 不插网线,容器完全无网络 | 安全隔离计算 |
注意
默认 bridge 模式下没有自定义网络的内置 DNS 服务发现,容器之间通常只能用 IP 地址互相通信。但容器 IP 不是稳定接口——你的代码不能写死 IP。
三、自定义 bridge 网络与 DNS 服务发现
解决方案:创建自定义 bridge 网络。Docker 在自定义网络中内置了 DNS 服务器,容器可以直接用对方容器名称通信,Docker 自动把名称解析为最新 IP。
docker network create my-micro-net问题:创建一个新的 Docker 自定义网络,使用什么子命令?(全小写,6个字母)
关键结论
- 默认
docker0网络:不提供自定义网络那样的容器名 DNS 服务发现 - 自定义 bridge 网络:支持
ping 容器名,Docker 自动解析为当前 IP
🔍 微服务互联:Docker 内置 DNS 解析
为什么在容器间通信时,必须使用容器名称而不能写死 IP?
【初始状态】Web 容器代码中写死了 Redis 的 IP 地址 (172.18.0.2)。
🌐 Web 容器
# 数据库连接配置
REDIS_HOST="172.18.0.2"
REDIS_HOST="172.18.0.2"
🗄️ Redis 容器
容器名: redis-dbIP: 172.18.0.2
四、实战:Redis + 前端容器互联
4.1 启动后端 Redis
# Redis 是一个高性能键值数据库,常用来做缓存
docker run -d --name redis-db --network my-micro-net redis:alpine4.2 启动前端探测容器
问题:docker run 中指定容器加入哪个网络的参数叫什么?(全小写,7个字母,两个单词用连字符连接)
4.3 验证 DNS 服务发现
# 在前端容器内 ping 后端容器——使用名称而不是 IP!
docker exec web-client ping -c 3 redis-db你应该看到 redis-db 被解析为 172.x.x.x 并成功 ping 通。这就是 Docker 内置 DNS 在工作——你不用知道 Redis 的具体 IP,只要记住它的容器名。
五、多网络连接
实际场景中,一个容器可能需要同时连接两个网络——前端网络和后台管理网络。
# 创建两个独立网络
docker network create frontend-net
docker network create backend-net
# 启动容器接入 frontend-net
docker run -d --name container-a --network frontend-net alpine sleep 3600
# 热插拔:把运行中的容器接到第二个网络
docker network connect backend-net container-a问题:docker network 中用于把运行中容器接入另一个网络的子命令叫什么?(全小写,7个字母)
验证双网卡:
docker exec container-a ip addr
# 你会看到 eth0(frontend-net)和 eth1(backend-net)两张网卡六、提交物清单
| 文件 | 说明 |
|---|---|
docker network ls 截图 | 显示自定义网络 my-micro-net |
ping redis-db 成功截图 | 证明 DNS 服务发现生效 |
docker network connect 截图 | 显示容器接入第二个网络后的双网卡 |
| bridge/host/none 对比说明 | 用表格或简图说明三种默认网络模式的区别和适用场景 |
当堂检测
- 默认
bridge网络和自定义 bridge 网络有什么区别?为什么企业要求用自定义网络? docker network connect的作用是什么?一个容器最多可以连接几个网络?- 容器删除重建或 IP 变化后,为什么用容器名称还能 ping 通?
七、故障排查
| 现象 | 排查方法 |
|---|---|
ping 不通 | 检查两个容器是否在同一自定义网络中 |
| 能 ping IP 不能 ping 名 | 确认在自定义网络而非默认 bridge |
| 端口冲突 | 不同容器可用同一端口,宿主机端口才需要区分 |
八、深度探索任务
以下任务不强制提交,是拔高性质的进阶练习。每个探索任务都包含完整的操作流程和确认问题。
探索任务 1:验证默认 bridge 不支持 DNS
目标:亲身对比默认 bridge 网络和自定义网络在 DNS 解析上的差异。
操作步骤:
1. 在默认 bridge 网络中启动两个容器
# 注意:这里故意不用 --network 参数,容器自动接入默认 docker0 网桥
docker run -d --name container-a alpine sleep 3600
docker run -d --name container-b alpine sleep 36002. 尝试用名称 ping
# 进入 container-a,用容器名 ping container-b
docker exec container-a ping -c 3 container-b你应该看到类似 ping: bad address 'container-b' 的错误——默认 bridge 网络无法把容器名解析为 IP。
3. 试试用 IP ping(作为对照)
# 先查 container-b 的 IP
docker inspect -f '{{(index .NetworkSettings.Networks "bridge").IPAddress}}' container-b
# 用 IP 直接 ping(这会成功,因为两个容器都在同一网桥上)
docker exec container-a ping -c 3 <container-b-IP>4. 创建自定义网络,重新测试
# 创建自定义网络
docker network create test-dns-net
# 把两个容器接入新网络
docker network connect test-dns-net container-a
docker network connect test-dns-net container-b
# 再次用名称 ping
docker exec container-a ping -c 3 container-b这次应该成功!Docker 内置 DNS 把 container-b 自动解析为当前 IP。
5. 清理
docker rm -f container-a container-b
docker network rm test-dns-net确认问题
默认 bridge 网络和自定义 bridge 网络在 DNS 解析能力上有什么区别?这个区别对微服务架构有什么实际影响?docker network connect 在这里发挥了什么作用?
探索任务 2:容器删除重建后的名称解析验证
目标:理解容器 IP 不是稳定配置项;即使容器删除重建后 IP 发生变化,自定义网络中的 DNS 名称仍然是稳定访问入口。
操作步骤:
1. 搭建测试环境
# 确保 my-micro-net 存在(如不存在则创建)
docker network inspect my-micro-net >/dev/null 2>&1 || docker network create my-micro-net
# 避免旧容器影响实验
docker rm -f redis-db ip-holder 2>/dev/null || true
# 启动 Redis 后端
docker run -d --name redis-db --network my-micro-net redis:alpine
# 查看 Redis 当前的 IP
docker inspect -f '{{(index .NetworkSettings.Networks "my-micro-net").IPAddress}}' redis-db记录下 IP 地址,例如 172.18.0.2。
2. 删除并重建容器,检查 IP
# 删除 Redis 容器
docker rm -f redis-db
# 启动一个临时占位容器,占用网络中的下一个地址,方便观察 IP 变化
docker run -d --name ip-holder --network my-micro-net alpine sleep 3600
# 重新创建同名 Redis 容器
docker run -d --name redis-db --network my-micro-net redis:alpine
# 再次查看 IP
docker inspect -f '{{(index .NetworkSettings.Networks "my-micro-net").IPAddress}}' redis-db你通常会发现 IP 变了,可能是 172.18.0.3 或别的地址。即使某次实验中 Docker 恰好复用了同一个 IP,也不能把它当成稳定配置。
3. 验证 DNS 自动更新
# 启动一个测试容器
docker run --rm --name test-client --network my-micro-net alpine \
ping -c 3 redis-db尽管 Redis 容器已经删除重建,ping redis-db 仍然成功——Docker 内置 DNS 会把名称解析到当前同名容器的 IP。
4. 再删除重建一次加深印象
# 再删除并重建一次
docker rm -f redis-db
docker run -d --name redis-db --network my-micro-net redis:alpine
docker inspect -f '{{(index .NetworkSettings.Networks "my-micro-net").IPAddress}}' redis-db
# 再 ping
docker run --rm --name test-client --network my-micro-net alpine \
ping -c 3 redis-db容器 IP 不适合作为长期配置,但名称在自定义网络中会持续指向当前容器。
5. 清理
docker rm -f redis-db ip-holder确认问题
容器删除重建后,为什么用 redis-db 这个名称还能 ping 通?如果没有 Docker 内置 DNS,你在代码里应该怎么写数据库连接地址?为什么写死 IP 是坏习惯?
