Docker 学习:多容器网络互通——从 host 模式到自定义 bridge 网络

Docker 学习:多容器网络互通------从 host 模式到自定义 bridge 网络

前几天我成功用 docker-compose 启动了导航服务和任务管理两个容器,但它们用的是 network_mode: host,容器直接"裸奔"在宿主机网络上。今天的目标是搞清楚正规的跨容器网络通信到底是怎么工作的。


一、为什么不能用 host 模式?

network_mode: host 的意思是容器和宿主机共享同一个网络栈,相当于容器没有自己的网络"身份证",直接用的宿主机的。

这种模式在本地做测试确实方便,ROS 2 的 DDS 多播也能直接互相发现。但问题也很明显:

  • 端口冲突:两个容器不能同时监听同一个端口(比如都想用 8080,就会打架)。
  • 安全问题:容器可以直接访问宿主机的所有网络接口,隔离性几乎为零。
  • 不可迁移:到了生产环境或者要上 Kubernetes,host 模式就完全不适用了。

所以,正经的工程化项目必须用自定义网络


二、核心机制:虚拟网络 + 内置 DNS

Docker Compose 在启动一组服务时,会在背后悄悄做两件关键事情:

1. 创建虚拟网络,给每个容器分配独立 IP

当你在 compose 文件里声明了 networks

yaml 复制代码
networks:
  robot_net:
    driver: bridge

Compose 会创建一个叫 robot_net 的虚拟网络,并划定一个 IP 地址池(比如 172.20.0.0/16)。每个加入这个网络的容器,都会被自动分配一个私有的 IP 地址

复制代码
robot_net (自定义 bridge 网络)
├── nav_service   → 172.20.0.2
└── task_service  → 172.20.0.3

这个分配是全自动的,不需要你手动指定。你可以随时查看:

bash 复制代码
docker-compose exec nav_service hostname -I
# 输出:172.20.0.2

2. 启动内置 DNS 服务,把服务名翻译成 IP

光有 IP 还不够,你得知道对方的具体 IP 才能通信。Docker 为此提供了一个内置的 DNS 服务器 (地址是 127.0.0.11)。

容器启动时,DNS 服务器会自动注册一条记录:"服务名 → 容器的 IP 地址" 。所以,同一个网络里的容器,不需要知道对方的 IP,直接用服务名就能找到对方。


三、ping task_service 的完整流程

我进入 nav_service 容器,执行 ping task_service,整个过程是这样的:

  1. ping 命令需要解析 task_service 的 IP。
  2. 它去问系统配置的 DNS 服务器(/etc/resolv.conf 里指向的 127.0.0.11)。
  3. 内置 DNS 查了一下自己的注册表,发现 task_service 此刻对应的 IP 是 172.20.0.3,然后返回这个地址。
  4. ping 拿着 172.20.0.3,通过虚拟网桥把数据包直接发给了目标容器。

整个过程不需要知道对方的 IP,只需要记住服务名。IP 的分配和翻译全由 Docker 自动完成。


四、动手实操:改造 compose 文件

我把之前的 docker-compose.yml 升级为自定义网络版本。核心改动就三处:

  • 删除 network_mode: host
  • 添加 顶层的 networks 声明
  • 给每个 service 添加 networks: - robot_net
yaml 复制代码
version: '3.8'

networks:
  robot_net:
    driver: bridge

services:
  nav_service:
    image: my-ros-dev:1.0
    container_name: nav_container
    hostname: nav_host
    networks:
      - robot_net
    # ... 其他配置不变 ...

  task_service:
    image: my-ros-dev:1.0
    container_name: task_container
    hostname: task_host
    networks:
      - robot_net
    depends_on:
      - nav_service
    # ... 其他配置不变 ...

启动后,进入 nav_service 容器验证网络互通:

bash 复制代码
docker-compose exec nav_service bash
ping task_service -c 3

输出:

复制代码
PING task_service (172.20.0.3) 56(84) bytes of data.
64 bytes from task_container.robot_net (172.20.0.3): icmp_seq=1 ttl=64 time=0.123 ms

不写 IP,不写 hostname,直接用服务名,ping 通了。


五、延伸:服务与容器的关系

这里很容易混淆一个概念:服务(Service)容器(Container) 到底是什么关系?

场景 服务数 容器数 关系
默认启动 1 个 nav_service 1 个容器 一对一
水平扩展 1 个 nav_service N 个容器 一对多
  • 默认情况:每个 service 只创建一个容器,是一对一关系。
  • 水平扩展docker-compose up -d --scale nav_service=3 可以让一个服务同时跑 3 个容器实例。Docker DNS 会自动做轮询负载均衡。
  • docker-compose exec 服务名 bash:进入的是该服务对应的容器。如果服务有多个实例,默认进入第一个。

服务是"逻辑分组",容器是"物理实例"。


六、跨主机能用这种方式吗?

不能。 Docker Compose 的网络和 DNS 只作用于单台宿主机。如果你需要跨主机通信,需要更高级的编排工具:

工具 适用场景 复杂度
Docker Swarm 小型集群,原生支持 Compose 文件
Kubernetes(K8s) 大规模生产集群

对于 ROS 2 的跨主机通信,还可以通过配置 DDS 的发现协议来手动指定对方 IP,但这个不在今天的学习范围内。


七、核心收获

  1. host 模式 = 容器裸奔在宿主机网络上,不安全,不推荐生产使用。
  2. 自定义 bridge 网络 = 每个容器有独立私有 IP,安全可控。
  3. Compose 内置 DNS = 同一网络的容器直接用服务名通信,不需要记 IP。
  4. 服务 vs 容器 = 服务是逻辑分组,容器是物理实例,默认一对一,可以水平扩展一对多。
  5. 跨主机通信 = Compose 不支持,需要 Swarm 或 K8s。

用一句话总结今天的核心:

Docker 给每个容器自动配 IP,再用 DNS 把服务名翻译成 IP。你只需要记服务名,完全不用管 IP 是多少。

这个机制就是微服务架构中服务发现的最简实现,理解了它,后面学 Kubernetes 的 Service 概念会非常顺畅。

相关推荐
Zzj_tju1 小时前
Instruction Tuning 论文精读路线:从 Supervised Fine-Tuning 到 Instruction Following
人工智能·笔记·学习·语言模型·自然语言处理
大模型搬砖师2 小时前
在Kubernetes上部署企业AI网关:一份云原生参考
网络·人工智能·安全
j7~2 小时前
【Linux】二十八.线程篇五《Linux多线程编程:线程同步之条件变量》---详解
linux·运维·c++·学习·条件变量·线程同步
celiahul2 小时前
当搜索引擎变成“问答机器人”,你的网站该如何适配?
网络·人工智能·搜索引擎·内容运营·外贸推广
min(a,b)2 小时前
学习第10天:日志、测试、配置与容器化部署
学习
xqqxqxxq2 小时前
AI Agent学习:用户记忆系统(李博杰《深入理解 AI Agent》3.1观后总结)
人工智能·学习
进击切图仔3 小时前
Ubuntu 挂载 XFS 磁盘并免密读写
linux·网络·ubuntu
wangyue_msn_863 小时前
Agent知识学习笔记——01 Prompt/Function call/记忆/上下文
笔记·学习·prompt
呱呱巨基3 小时前
CMake基础
linux·c++·笔记·学习