Appearance
Linux 网络基础和容器网络
容器网络,本质是“Linux 网络命名空间 + 虚拟网卡 + 桥接 + NAT + 路由 + iptables”的组合拳。
Docker 桥接网络的「裸奔版」,用最纯净的 Linux 内核机制,理解 namespace + veth + bridge + NAT 的全链路,揭开 Docker 背后的神秘面纱
等处理的概念
- MetalLB 就像是你本地/裸机 Kubernetes 的“LoadBalancer 发号器”,让你在没有云的情况下,依然拥有云的访问体验
- ip addr
- ip link
- ip route 路由表
- 网卡 多 IP
- 虚拟网卡
- 网桥 虚拟交换机
- 网关
- 防火墙
- 默认路由/缺省路由
- 通常情况下,默认路由 = 网关 IP
- default via X dev Y
- 第一跳 = 数据包离开你主机后,抵达的第一台网关设备 IP
- 第一跳的设备
- traceroute 命令
- 它的输出就是:从你电脑出发到目标地址,中间经过的每一跳网关(路由器)
- telnet 命令
- nc 命令
- ping 命令
- ping -c 3 www.baidu.com
-
ip route是导航系统,决定“去哪” NAT - iptables 是关卡系统,决定“能不能去、要不要伪装”。
- tcpdump -i docker0 icmp
- 网络命名空间(即 namespace,Linux 内核的概念)
- 理解
192.168.1.0/24和192.168.1.0/22的区别
网络基础核心概念
| 概念 | 解释 |
|---|---|
| IP 地址 | 网络设备的唯一地址(如 192.168.1.1) |
| 子网掩码 | 决定同一个网段的设备(如 /24 即 255.255.255.0) |
| 网关 | 你出网的门(通常是路由器) |
| DNS | 把网址翻译成 IP 地址 |
| MAC 地址 | 网卡烧录的物理地址 |
| 端口 | 一个 IP 下多个服务的编号(如 80 是 HTTP) |
| TCP vs UDP | TCP 是可靠连接(有握手),UDP 是快递(不保证收) |
| 三次握手 | TCP 建立连接的过程(SYN-SYN/ACK-ACK) |
| 四次挥手 | TCP 断开连接的过程 |
| NAT | 多个内网 IP 公用一个公网 IP 出网(家用 Wi-Fi 就是) |
| 路由 | 多跳设备决定你怎么到达目标 IP(trace route) |
理解 docker0
docker0 是 Docker 默认创建的一个虚拟网桥(Bridge),即默认 bridge 网络,它用于容器与宿主机、其他容器之间的网络通信。
默认桥接网络 bridge 的通信原理
- 启动容器,默认挂到
docker0网桥上(172.17.0.1/16) - 会自动创建一对 veth pair:
- 一端在容器里(命名为 eth0)
- 一端在宿主机里(随机名,比如 vethf58a1c@)
docker0作为桥,把多个 veth 接口连起来,像个二层交换机- 容器间通信靠
docker0转发 - 容器访问外网,靠宿主机做 NAT 转换(iptables MASQUERADE)

服务发现
- 默认 bridge(docker0),不支持 DNS 服务发现
- 自定义 bridge 支持 DNS 服务发现
- Compose 默认网络,支持 DNS 服务发现,本质上是自定义 bridge 网络
容器访问外网的路径(默认 bridge 网络)
sh
# 视角1
容器 eth0 -> veth pair -> docker0 网桥 -> NAT 转换(iptables MASQUERADE) -> 宿主机 eth0 -> 外网
# 视角2
容器 eth0(172.17.0.x)
↓
veth pair(虚拟网卡)
↓
docker0(桥接网络,172.17.0.1)
↓
宿主机 iptables NAT(源地址转换为宿主机 IP)
↓
宿主机物理网卡 eth0(如 10.0.4.2)
↓
路由到外网自定义 Docker 网桥网络
docker0 网络虽然开箱即用,但不支持容器名互通,只能用 IP,自定义 bridge 是支持 DNS 的
自定义 bridge 网络访问外网
sh
容器 eth0 -> veth pair -> 自定义网桥 -> NAT -> 宿主机 eth0 -> 外网创建一个自定义桥接网络
sh
docker network create \
--driver bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.1 \
my-custom-net这时执行 ip addr 能在宿主机上能看到对应的网桥网卡
br-xxxxxxxxxxxx这个 br- 开头的网卡就对应你刚创建的 my-custom-net 网络,可执行下面的命令来验证
sh
docker network inspect my-custom-net你会看到类似:
json
"Options": {
"com.docker.network.bridge.name": "br-3b3a3bfa5c3f"
}这个 bridge.name 就是你宿主机上的真实网卡名
验证自定义 Docker 网桥网络的服务发现
创建网络
sh
docker network create \
--driver bridge \
--subnet 192.168.100.0/24 \
--gateway 192.168.100.1 \
my-custom-net启动两个 alpine 容器
sh
docker run -it --rm --name test1 --network my-custom-net alpine sh
docker run -it --rm --name test2 --network my-custom-net alpine sh在 test1 容器内执行:
sh
ping test2它能解析成 IP 并正常 ping 通,说明服务发现 OK
疑问:Docker Compose 中,容器之间能通过服务名通信,是因为用了自定义网桥吗?
答案:没错!你跑 docker-compose up 的时候,它会自动为该项目创建一个自定义网络 network(名字类似于 项目名\_default)。所以 Compose 里的容器可以直接用服务名(如 db, web)相互访问,就是因为这些容器都被绑定到了一个 同一个自定义 bridge 网络上,并启用了 DNS。
验证 Docker Compose 的服务发现
yaml
version: "3"
services:
app1:
image: alpine
command: ["sh", "-c", "apk add --no-cache iputils && sleep infinity"]
app2:
image: alpine
command: ["sh", "-c", "apk add --no-cache iputils && sleep infinity"]启动服务
sh
docker-compose up -d验证自定义网络是否创建
sh
docker network ls | grep _default进入容器 ping 服务名验证 DNS
sh
docker exec -it <app1容器ID或名字> sh
# 容器内执行
ping app2它能解析成 IP 并正常 ping 通,说明服务发现 OK
docker network 操作命令清单
bash
# 查看所有网络
docker network ls
# 查看网络详情(如 bridge):
docker network inspect bridge
# 创建自定义网络:
docker network create my-net
# 启动容器加入网络:
docker run -d --network=my-net nginxDocker 网络类型全览(docker network ls)
| 类型 | 说明 | 特点 |
|---|---|---|
bridge | 默认网络 | 基于 docker0,支持端口映射/NAT |
host | 与宿主机共用网络命名空间 | 无隔离,性能好,适合高性能通信 |
none | 没有网络连接 | 容器完全裸奔(需手动配置) |
overlay | 跨主机网络(Swarm) | 多宿主机通信,依赖 KV 存储 |
macvlan | 容器作为局域网一员 | 容器像物理机一样拥有独立 IP |
ipvlan | 类似 macvlan,更灵活 | 新手不常用 |
常见的网络配置方式
| 网络模式 | 描述 | 适用场景 |
|---|---|---|
| 桥接(Bridge) | 容器与宿主机在同一网络段,容器可以与宿主机和其他容器通信。 | 容器间需要直接通信,且与宿主机同一局域网内。 |
| NAT | 容器通过宿主机的公网 IP 访问外网,容器 IP 被隐藏。 | 容器访问外网但不需要暴露容器 IP,外部访问不直接访问容器。 |
| 主机(Host) | 容器直接使用宿主机的网络接口,容器和宿主机共享 IP 地址。 | 高效的容器与宿主机通信,减少网络开销。 |
| Overlay | 在物理网络之上构建虚拟网络,支持跨主机通信。 | 容器集群中跨主机的容器通信,跨网络的通信。 |
| Macvlan | 容器有独立的 MAC 地址,直接接入物理网络。 | 容器需要独立的 IP 和 MAC 地址,直接接入物理网络。 |
| None | 容器不连接任何网络,不具备网络访问。 | 需要完全隔离的容器,无需访问外部网络。 |
容器间通信的 3 个常见场景
| 场景 | 条件 | 是否能通信 | 原因 |
|---|---|---|---|
| 同一个 bridge 网络 | 默认 | ✅ | 通过 docker0 桥直接转发 |
| 不同 bridge 网络 | 默认隔离 | ❌ | 除非手动连接 |
| host 网络 | 共用网络栈 | ✅ | 和宿主机一样 |
容器访问宿主机内网 IP(如 10.0.4.2)的流程
sh
容器 (172.10.0.2)
↓
查路由表 (目标 10.0.4.2 不在本地网段)
↓
转发到网关 (172.10.0.1 - docker0)
↓
veth
↓
docker0
↓
宿主机内核 (10.0.4.2)
↓
处理数据包
↓
直接交给宿主机处理
↓
宿主机处理后响应
↓
容器- 容器访问宿主机的内网 IP:
- 容器的
eth0网卡上有一个 IP 地址,比如172.10.0.2,这个 IP 地址属于容器所连接的自定义网络(比如172.10.0.0/24)。 - 容器发送数据包,目标是宿主机内网 IP(比如
10.0.4.2)。
- 容器的
- 容器的路由查找:
- 容器会查看自己的路由表,检查目标地址
10.0.4.2是否在容器的 IP 子网(即172.10.0.0/24)内。 - 因为
10.0.4.2不在容器的子网内,所以容器会把这个数据包交给默认网关,也就是172.10.0.1(这是 Docker 的docker0网桥的 IP)。
- 容器会查看自己的路由表,检查目标地址
- 数据包从容器发送到 Docker 网桥:
- 数据包会通过容器的
eth0网卡发送到docker0网桥(172.10.0.1),即通过veth(虚拟以太网接口)对进行转发。
- 数据包会通过容器的
- Docker 网桥处理数据包:
docker0网桥接收到数据包后,会根据其网桥规则,将数据包转发到宿主机的对应网络接口。
- 宿主机内核处理:
- 宿主机收到数据包后,内核会检查目标 IP
10.0.4.2。由于10.0.4.2是宿主机的一个 IP(假设宿主机eth0的 IP 地址是10.0.4.2),宿主机内核会认为该数据包是自己发出的,直接将数据包交给宿主机进行处理。
- 宿主机收到数据包后,内核会检查目标 IP
总结:容器通过 docker0 网桥向宿主机发起请求时,会先走容器的 eth0 -> docker0 -> 宿主机内核,然后由宿主机处理返回数据。这一过程的关键是,宿主机内核通过路由表和 IP 配置,知道 10.0.4.2 是自己内网的 IP,所以直接处理数据包。
host.docker.internal
在 macOS 和 Windows 上,使用 host.docker.internal 可以轻松地访问宿主机
以下是容器通过 host.docker.internal 访问宿主机的流程图:
容器 -> 查找 DNS -> host.docker.internal -> 宿主机 IP
容器 eth0 -> 查找路由表 -> 找到目标是宿主机(host.docker.internal)
容器 eth0 -> 发送数据包 -> docker0 (veth pair) -> 宿主机
宿主机处理请求 -> 响应数据包返回 -> 容器解释:
- 容器查找 DNS:容器通过 DNS 查询 host.docker.internal,该域名在 Docker 的 DNS 配置中会解析为宿主机的 IP 地址。
- 路由查找:容器查找自己的路由表,发现目标 IP 是宿主机地址,然后决定通过网关(通常是 Docker 网桥 docker0)转发数据包。
- 数据包转发:数据包从容器的 eth0 网卡发送,经过容器的 veth pair,最终通过 Docker 网桥(docker0)发送到宿主机。
- 宿主机处理:宿主机收到数据包后,处理请求并将响应返回给容器。
- 数据包返回:宿主机将响应数据包通过 docker0 网桥,再经过 veth pair 返回给容器的 eth0,完成通信。