Docker 与 K8s 网络模型全解析

一、Docker 网络模型

Docker网络的核心是docker0网桥,当我们安装好docker之后,宿主机上会自动创建一个docker0的网桥来充当交换机的角色,所有容器连接到这个网桥上,使得容器之间的通信就像在同一个局域网中一样,docker网桥如下图;docker容器每个veth都包含两个虚拟网络接口,其中veth负责连接到dicker0网桥,而另外一个接口被配置到容器的网络栈中,命名为eth0,veth像一根虚拟的网线,连接了容器与宿主机的网络命名空间,允许容器发出的数据包直接到达宿主机的网桥,当容器1与容器2间通时,通过docker0实现容器间的通信。

1. 核心组件与通信原理

组件 作用
docker0 网桥 宿主机自动创建的虚拟网桥(类似物理交换机),所有容器默认连接至此网桥
veth 设备 虚拟网线,成对存在:一端连 docker0 网桥,另一端作为容器内的 eth0 网卡
网络命名空间 隔离容器网络栈,使容器拥有独立的 IP、路由、端口等网络资源

容器间通信流程(同一宿主机)

  1. 容器1发出数据包,通过自身eth0(veth一端)传递到docker0网桥;
  2. docker0网桥根据目标IP(容器2的IP)转发数据包到容器2的veth端;
  3. 容器2通过eth0接收数据包,完成通信

2. 容器与外部网络交互

Docker依赖iptables规则实现内外网转发,核心分为两种场景:

(1)容器访问外部网络(出网)
  • 核心iptables规则(POSTROUTING):

    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

  • 规则解析:

  • -s 172.17.0.0/16:匹配来自 Docker 容器网段(默认 172.17.0.0/16)的数据包;

  • ! -o docker0:排除容器间通信(不通过 docker0 网桥的流量);

  • MASQUERADE:动态 SNAT(源地址转换),将容器 IP 替换为宿主机 IP,实现出网。

(2)外部网络访问容器(入网)

容器 IP 仅在宿主机内可见,外网需通过 端口映射 访问,核心是 -p 参数与 iptables 转发规则:

  1. 启动容器时配置端口映射:

    docker run -d --name web -p 8080:80 nginx

2.自动生成的 iptables 规则(以容器 IP 172.17.0.2 为例):

复制代码
# 1. PREROUTING 链:将宿主机 8080 端口的流量转发到容器 IP:端口
-A PREROUTING -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
# 2. POSTROUTING 链:确保容器回包能正确返回外网
-A POSTROUTING -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j SNAT --to-source 宿主机IP

二、Docker网络模式

安装Docker时会自动创建3个网络,可以使用docker network ls命令列出这些网络。

复制代码
[root@docker ~]# docker network ls
NETWORK ID         NAME             DRIVER              SCOPE
2379cach4e83        bridge              bridge              local
52e2de623b35        host                host                local
4651f24b3341        none                null                local

我们在使用docker run创建容器时,可以用--net选项指定容器的网络模式,Docker有以下4种网络模式:

  1. Host模式,使用--net=host指定。
  2. Container模式,使用--net=container:NAME_or_ID指定。
  3. None模式,使用--net=none指定。
  4. Bridge模式,使用--net=bridge指定,默认设置。

1.Host 模式核心原理:完全共享宿主机网络栈

Docker 默认会为每个容器创建独立的 Network Namespace (包含独立网卡、IP、路由、iptables 规则),如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等,但 Host 模式会「跳过」这个隔离,让容器直接使用宿主机的 Root Network Namespace,具体表现为:

  1. 无独立网卡 / IP :容器内没有 eth0 虚拟网卡,而是直接使用宿主机的物理网卡(如 ens33);
  2. 端口直接占用 :容器启动的服务会直接使用宿主机的端口(如容器内启动 Nginx 80 端口,外部可通过「宿主机 IP:80」直接访问,无需 -p 映射);
  3. 共享网络配置:容器内的路由表、DNS 配置、iptables 规则与宿主机完全一致(修改容器内的路由会直接影响宿主机)。

1.1、Host 模式的安全风险(为什么不推荐?)

你提到的「安全风险」可细化为 3 个核心问题,这些问题在生产环境中可能导致严重故障:

1. 端口冲突风险:容器直接占用宿主机端口
  • 问题:若宿主机已运行其他服务(如宿主机本身有 Nginx 占用 80 端口),Host 模式容器会启动失败(端口被占用);
  • 隐患:若容器服务异常占用关键端口(如 22 SSH 端口、6443 K8s API 端口),会直接导致宿主机核心服务不可用。
2. 网络配置篡改风险:容器可修改宿主机网络
  • 问题:容器内执行 ip route add/iptables -A 等命令,会直接修改宿主机的路由表 /iptables 规则;
  • 隐患:恶意容器或误操作可能删除宿主机默认路由,导致整个宿主机断网;或添加错误 iptables 规则,阻断核心服务流量。
3. 进程身份混淆风险:容器进程与宿主机进程难区分
  • 问题:宿主机 ps -ef 查看进程时,容器内的 nginx 进程显示为「nginx: master process」,无法直观区分是宿主机进程还是容器进程;
  • 隐患:排查端口占用、进程异常时,容易误杀宿主机进程(如误将宿主机 Nginx 当作容器进程杀死)。

1.2、Host 模式的「少数合理场景」

虽然不推荐,但在以下特殊场景中,Host 模式可能是最优选择(权衡便利性与风险):

  1. 对网络性能要求极高的场景:如高频网络通信的服务(如分布式缓存、实时数据传输),Host 模式跳过虚拟网络转发(veth、bridge),减少网络延迟(性能比 Bridge 模式高 10%-20%)。
  2. 需要访问宿主机网络栈的工具类容器:如网络监控容器(需抓取宿主机所有网卡流量)、DNS 服务容器(需修改宿主机 DNS 配置),Host 模式可直接获取宿主机网络数据。

2.Container 模式核心原理:共享指定容器的网络栈

Container 模式的核心是「新容器不创建独立 Network Namespace,而是 "寄生" 到已存在的目标容器的 Network Namespace 中」,具体特性如下:

  1. 网络资源完全共享 :新容器与目标容器共享 IP、端口、网卡、路由表、DNS 配置(两者在网络层面完全 "融为一体",外部看是同一个 IP);
  2. 其他资源完全隔离:文件系统、进程列表、PID Namespace、Mount Namespace 等仍与目标容器隔离(比如新容器里看不到目标容器的进程);
  3. 通信极高效 :两个容器可通过 lo 回环网卡 直接通信(如 ping 127.0.0.1 或访问 localhost:端口),无需经过网桥转发,延迟极低。

2.1、Container 模式的适用场景

这种模式不常用,但在以下特定场景中能解决关键问题:

  1. "工具容器" 辅助主容器 :主容器(如 Nginx/Java 服务)未安装调试工具(如 curl/ping/tcpdump),可启动一个工具容器共享其网络,直接调试主容器的服务(无需进入主容器或暴露额外端口);

  2. 多服务共享端口(特殊需求):某些老旧服务依赖固定端口(如必须用 80 端口),但又不能部署在同一个容器中(需隔离文件系统 / 进程),可通过 Container 模式让多服务共享同一个 IP 和端口(需确保服务监听不同路径,如 Nginx 代理不同 URI 到不同容器)。

  3. 降低网络延迟:对通信延迟敏感的场景(如主容器是数据库,新容器是缓存服务),通过 lo 网卡直接通信,延迟比跨容器网桥转发低 1-2 个数量级。

2.2、注意事项与风险

  1. 端口冲突风险:新容器与目标容器不能监听同一个端口(如目标容器已用 80 端口,新容器再启动 80 端口服务会失败);
  2. 目标容器依赖:若目标容器停止或删除,新容器会失去网络栈(无法联网,需重新启动并指定新的目标容器);
  3. 安全隔离弱化:新容器与目标容器共享网络,若新容器被入侵,攻击者可通过网络直接访问目标容器的服务(需确保新容器的安全性)。

3.None 模式核心原理:仅保留网络隔离,无任何默认配置

Docker 对 None 模式的处理逻辑非常简单:

  1. 创建独立 Network Namespace:容器拥有专属的网络隔离环境(与宿主机、其他容器的网络完全隔开);
  2. 不做任何网络配置 :容器内只有 lo 回环网卡(用于容器内进程间通信),没有物理 / 虚拟网卡(如 eth0),无 IP、无路由、无 DNS 配置;
  3. 需手动配置网络 :若要让容器联网,必须通过 ip/route 等命令手动添加网卡、分配 IP、配置路由(相当于 "从零搭建网络")。

3.1、None 模式的典型使用场景

None 模式因 "完全手动配置" 的特性,仅适用于对网络有 高度定制化需求 的场景,常见场景包括:

  1. 安全隔离场景:需严格限制容器网络(如仅允许容器内进程通信,不允许联网),例如运行敏感数据处理的容器(无需对外通信,减少攻击面);

    • 例:容器内仅运行一个计算脚本,无需联网,用 None 模式可避免网络层面的安全风险。
  2. 自定义网络协议 / 拓扑:需搭建特殊网络环境(如自定义路由、使用非 TCP/IP 协议、配置 VLAN 等),例如测试网络设备驱动、验证自定义路由算法;

    • 例:为容器配置 SR-IOV 直通网卡(绕过操作系统网络栈,直接使用物理网卡),需先通过 None 模式清空默认配置,再手动绑定硬件网卡。
  3. 网络调试 / 学习场景:用于学习 Linux 网络原理(如手动配置 veth、网桥、路由),None 模式提供了 "干净的网络画布",无默认配置干扰;

    • 例:新手学习 ip 命令、Network Namespace 隔离原理时,用 None 模式容器实操更易理解。

4、Bridge 模式核心技术细节

Bridge 模式的本质是通过 虚拟网桥(docker0)+ 虚拟网卡对(veth pair)+ iptables 规则 构建的 NAT 网络,各组件协作如下:

组件 作用
docker0 网桥 宿主机启动 Docker 时自动创建的虚拟二层交换机(默认 IP:172.17.0.1/16),所有 Bridge 模式容器都连接至此
veth pair(虚拟网卡对) 成对存在的虚拟网络接口,形似 "网线":一端(vethxxx)连 docker0 网桥,另一端(eth0)在容器内作为网卡
容器 Network Namespace 容器独立的网络空间,包含 eth0 网卡(veth 一端)、IP(从 docker0 网段分配,如 172.17.0.2)、路由表
iptables 规则 控制容器与外网、容器间的通信(如 SNAT/DNAT 转发、端口映射、网络隔离),主要作用于 nat 表和 filter 表

4.1、Bridge 模式通信全流程解析

1. 容器与容器通信(同一宿主机)

以容器 A(172.17.0.2)访问容器 B(172.17.0.3)为例:

  1. 容器 A 内进程发送数据包,目标 IP 为 172.17.0.3,通过自身 eth0 网卡(veth 一端)传出;
  2. 数据包经 veth 对传输到 docker0 网桥(veth 另一端连接网桥);
  3. docker0 网桥作为二层交换机,根据目标 MAC 地址(通过 ARP 协议获取)直接转发数据包到容器 B 的 veth 端;
  4. 容器 B 通过 eth0 网卡接收数据包,完成通信。
    • 关键:无需经过宿主机物理网卡,直接通过 docker0 网桥转发,效率较高。
2. 容器访问外部网络(出网流程)

以容器 A(172.17.0.2)访问百度(220.181.38.148)为例:

  1. 容器 A 数据包目标 IP 为 220.181.38.148,经 eth0 → veth 传到 docker0 网桥;

  2. docker0 网桥发现目标 IP 不在自身网段(172.17.0.0/16),根据容器内默认路由(网关指向 172.17.0.1,即 docker0 IP),将数据包转发到宿主机物理网卡;

  3. 宿主机 iptables 的 POSTROUTING 链触发 SNAT 规则(MASQUERADE):

    bash

    复制代码
    # 查看规则:将容器网段的数据包源 IP 替换为宿主机物理网卡 IP
    iptables -t nat -vnL POSTROUTING | grep 'MASQUERADE'
  4. 数据包以宿主机 IP 作为源地址发送到外网,外网响应包回到宿主机后,反向通过 iptables 规则转发到容器 A。

3. 外部网络访问容器(入网流程,端口映射)

以外部主机访问宿主机 8080 端口(映射到容器 A 的 80 端口)为例:

  1. 外部主机发送数据包到宿主机 IP:8080,宿主机物理网卡接收;

  2. 宿主机 iptables 的 PREROUTING 链触发 DNAT 规则(端口映射):

    bash

    复制代码
    # 查看规则:将宿主机 8080 端口流量转发到容器 A 的 172.17.0.2:80
    iptables -t nat -vnL PREROUTING | grep '8080'
  3. 数据包经 docker0 网桥转发到容器 A 的 veth 端,容器 A 通过 eth0 接收并处理;

  4. 容器 A 的响应包经原路径返回,iptables 自动替换源地址为宿主机 IP,确保外部主机能识别响应。

4.2、Bridge 模式的 iptables 规则详解

Docker 会自动在宿主机的 nat 表和 filter 表中创建规则,控制 Bridge 模式的网络流量,核心规则如下:

表(Table) 链(Chain) 典型规则示例 作用
nat PREROUTING -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80 外部访问宿主机端口 → 转发到容器端口
nat POSTROUTING -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE 容器出网流量 → 替换源 IP 为宿主机 IP
nat DOCKER -A DOCKER ! -i docker0 -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80 关联 PREROUTING 链,细化端口映射规则
filter DOCKER-USER (默认空,用户可自定义) 优先控制所有 Docker 流量(如黑名单)
filter DOCKER -A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp --dport 80 -j ACCEPT

Docker网络综合图形

五、k8s网络模型

5.1、BGP Pod通信过程

5.1.2、在 Calico 网络流量传输流程里,calico/node 中的三个组件各自承担关键作用:

Felix:作为 Calico 的核心代理,负责在宿主机上配置网络接口(如创建 cali 开头的虚拟网卡)、管理路由规则(确保 Pod 流量能正确转发到目标节点或 Pod),还会维护网络策略(控制 Pod 间的访问权限),是实现网络连通和安全策略的基础执行者。

Bird:作为 BGP(边界网关协议)客户端,负责与其他节点的 Bird 组件或外部 BGP 设备建立对等连接,交换路由信息,让集群中各节点能知晓不同 Pod 网段对应的目标节点,从而为跨节点的 Pod 流量提供准确的路由指引,保障数据包能跨节点传递。

Confd:主要负责监听 Calico 资源的配置变化(比如 IP 池、网络策略等配置的更新),并将这些配置转化为 Felix 和 Bird 可识别的格式,确保两者能基于最新配置工作,维持网络配置的一致性与动态更新能力。

正是这三个组件协同工作,才使得 Calico 能实现高效、灵活且可控的容器网络通信。

5.1.3、跨节点通讯过程:

宿主机calico网卡与Pod的是成对的网卡(veth网卡);在网卡上使用proxy arp协议

calico会开启响应,A Pod将数据包交给calico网卡。

A Pod 的 eth0(IP 为 10.121.74.181)先通过 ARP 找到网关,接着经 A 宿主机的 cali3e7996a24a7 网卡,依据路由表确定 B Pod 所在网段,然后从 A 节点的 eth0发送出去;数据包到达 B Node 的 eth0(IP 为 10.120.128.7)后,通过路由表找到目标 IP(10.121.46.65)对应的 B 宿主机 cali558def1712b 网卡,交给calico网卡后自然的到 B Pod 的 eth0(IP 为 10.121.46.65)。

5.2、IPIP Pod通信流程

5.2.1、跨节点通讯过程:

前面这个是一样的A Pod 的 eth0(IP 为 10.7.75.132)先将流量发往自身网关,随后流量经 A 宿主机的 cali76174826315 网卡;进入 A 宿主机的 tunl0(IP 为 10.7.75.128)进行 IP-in-IP 封装;(新增的封装报文(外层报文)的目标 IP 确实是 B Node 的地址)封装后的数据包从 A 节点的 eth0(IP 为 10.120.181.20)发出,通过网关 10.120.181.254(路由器;如果是交换机,那就不加IP头了用标准BGP协议来通信) 转发到下一跳 B Node 的 eth0(IP 为 10.120.179.8);在 B Node 上对数据包进行解封装,之后经 B 宿主机的 tunl0(IP 为 10.5.34.192),再通过 B 宿主机的 calie83684f4735 网卡,最终将流量转发到 B Pod 的 eth0(IP 为 10.5.34.192)。

5.3、VXLAN Pod通信流程

5.3.1、跨节点通讯过程:

Pod1(IP:10.244.103.68)的流量先经自身 eth0 网卡,传递到 Node1 上的 calice0906292e2 虚拟网卡;随后进入 Node1 的 vxlan.calico 设备,在此处,原始数据包被封装到 UDP(端口 4789)报文里,外层头部的源 IP/MAC 设为 Node1 物理网卡 ens33 的 IP(192.168.0.81)与 MAC;封装后的报文通过物理网络传输至 Node2 的 ens33 网卡(IP:192.168.0.82),接着进入 Node2 的 vxlan.calico 设备进行解封装,取出原始数据包;最后,数据包经 Node2 上的 cali49778cadcf1 虚拟网卡,转发到 Pod2 的 eth0 网卡(IP:10.244.42.71),完成通信。

Calico的VXLAN模式不需要BGP生成路由表,而使用VXLAN隧道自身来维护的路由表实现

5.3.2、VXLAN with BGP 模式下,当网络设备为交换机时,通信过程可这样解析:

假设 Node1 和 Node2 处于同一物理子网(如都在 192.168.1.0/24),Pod1(IP:10.244.1.10,在 Node1)要访问 Pod2(IP:10.244.1.20,在 Node2),中间设备是交换机:

Pod1 发送数据包,经自身 eth0 → Node1 上的 cali 虚拟网卡 → Node1 的路由表(由 BGP 同步而来,记录 "10.244.1.20/32 对应 Node2 的物理 IP 192.168.1.2")。

Node1 将数据包通过 ** 物理网卡(如 ens33)** 发往交换机;交换机基于 "目的 IP(Node2 物理 IP 192.168.1.2)" 和 MAC 表,转发到 Node2。

Node2 接收数据包后,经自身路由表(BGP 同步),将数据包转发到 Pod2 的 cali 虚拟网卡 → Pod2 的 eth0,完成通信。

(此过程无 VXLAN 封装,依赖 BGP 传递 "Pod IP → 节点物理 IP" 的路由规则,交换机仅做二层转发。)

如果同一网段,就使用BGP

如果不同网段,就用VXLAN机制

6、Calico 路由反射器(Route Reflector)

6.1、路由反射器的核心作用:解决全互联模式的痛点

Calico 默认的 Node-to-Node Mesh(节点全互联) 模式,虽能实现路由信息同步,但存在明显局限性:

  • 连接数爆炸 :若集群有 N 个节点,每个节点需与其他 N-1 个节点建立 BGP 连接,总连接数为 N×(N-1)/2(如 100 个节点需 4950 个连接);
  • 资源开销大:大量 BGP 连接会占用节点 CPU、内存及网络带宽,且路由同步效率随节点数增加而下降。

路由反射器(RR)的核心是 "集中转发路由信息"

  • 选择少数节点作为 RR,其他节点(客户端节点)仅与 RR 建立 BGP 连接;
  • 路由同步流程简化为 "客户端→RR→其他客户端",总连接数降至 N(仅客户端到 RR 的连接),彻底解决连接数爆炸问题,适用于 100 节点以上的大规模集群。

点赞+关注+收藏,下期再见。博主忙着学习shell脚本,更新有点慢,有兴趣可以一起交流shell脚本的。

相关推荐
skyeeeeee26 分钟前
kubeadm安装k8s集群
后端·kubernetes
高旭博2 小时前
7. kubernetes资源——service服务
云原生·容器·kubernetes
斯普信专业组3 小时前
Docker 常用命令与时区配置指南
docker·容器·eureka
天一生水water14 小时前
ubuntu使用毫秒镜像方式安装docker mysql
ubuntu·阿里云·docker
Qayrup17 小时前
docker 搭建私有仓库,推送并拉取
运维·docker·容器
郭庆汝17 小时前
docker拉取英伟达官方cuda11.8镜像
docker·cuda11.8
天下不喵19 小时前
Ubuntu24.04安装Docker过程记录
docker
黑黍19 小时前
如何在k8s中配置并使用nvidia显卡
云原生·容器·kubernetes
冷血~多好20 小时前
使用docker部署elk,实现日志追踪
elk·docker·容器