前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >浅谈容器网络

浅谈容器网络

原创
作者头像
rxg456
发布于 2025-03-31 16:46:35
发布于 2025-03-31 16:46:35
8301
代码可运行
举报
运行总次数:1
代码可运行

容器技术通过轻量化的资源隔离机制,极大地简化了应用部署的复杂性。而容器网络作为容器生态的核心组件,直接影响着容器间通信、服务发现及跨主机协同的能力。本文将从容器网络的基础组件出发,逐步剖析其工作原理及关键实现。

一、容器网络栈:隔离的基石

所谓网络栈,就包括了:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。对于一个进程来说,这些要素,其实就构成了它发起和响应网络请求的基本环境。

使用宿主机的网络栈(–net=host),即:不开启 Network Namespace,比如:

代码语言:bash
AI代码解释
复制
docker run -d --net=host --name nginx-host nginx:demo

二、容器的网络隔离:命名空间的魔法

每个容器启动时都会创建独立的网络命名空间(Network Namespace),形成完全隔离的网络栈,包含以下核心组件:

  1. 虚拟网卡(veth pair) 容器通过一对虚拟网卡(veth)与宿主机通信。例如,容器内的eth0 网卡通过 veth 对连接到宿主机的虚拟网桥(如 docker0)。这种设计使得容器流量能够通过宿主机网络栈转发。
  2. 回环设备(lo) 容器内部的 lo 设备用于本机进程间通信(如访问 localhost 服务),与宿主机回环设备完全隔离。
  3. 路由表 容器的路由表决定了流量的转发路径。例如,默认路由指向 eth0,将出站流量导向宿主机的网桥;特定服务的路由规则可实现精细的流量控制。
  4. iptables 规则 iptables 负责网络地址转换(NAT)和流量过滤。例如,Docker 默认通过 MASQUERADE 规则将容器出站流量伪装为宿主机 IP,实现外网访问;FORWARD 链规则控制容器间的通信权限。

网络命名空间机制实现不同容器的隔离

  • 独立网络设备:每个容器拥有自己的 eth0lo 等设备,与其他容器不可见。
  • 隔离的路由与防火墙:容器内修改路由表或 iptables 规则不会影响宿主机或其他容器。
  • 端口冲突规避:不同容器可绑定相同端口(如 80),通过宿主机端口映射(如 -p 8080:80)暴露服务。

三、容器间的网络通信

容器间的网络通信本质上是通过虚拟化技术模拟多机通信场景实现的。我们可以将容器视为独立主机,通过虚拟交换机(网桥)和虚拟网线(Veth Pair)构建通信链路。以下通过一个具体场景解析其完整流程:

3.1 架构示例

宿主机上运行两个容器 ContainerAContainerB,二者通过 docker0 网桥互联

代码语言:bash
AI代码解释
复制
+-------------------------------------------------+
|                   宿主机                         |
|  +------------+              +------------+     |
|  | ContainerA |              | ContainerB |     |
|  | eth0@vethA |              | eth0@vethB |     |
|  +-----↑------+              +-----↑------+     |
|        ↓                           ↓            |
|  +-----↓---------------------------↓------+     |
|  |           docker0网桥 (172.17.0.1)      |     |
|  +----------------------------------------+     |
+-------------------------------------------------+

3.2 核心组件协同工作原理

(1)Veth Pair:跨命名空间的"网线"
  1. 创建过程

当容器启动时,Docker 会创建一对 Veth Pair(如 vethAvethA-peer

代码语言:bash
AI代码解释
复制
# 宿主机查看Veth Pair(vethA-peer在容器内被重命名为eth0)
# ip link show | grep -n2 veth
12: veth6f43f82@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether 3e:30:83:c4:92:54 brd ff:ff:ff:ff:ff:ff link-netnsid 0
13: veth2cb4daf@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether 36:e5:74:e0:27:80 brd ff:ff:ff:ff:ff:ff link-netnsid 1
  • vethA-peer 被放入容器的 Network Namespace,重命名为 eth0
  • vethA 保留在宿主机,连接到 docker0 网桥
  1. 数据流

ContainerAContainerB 发送数据包:

  • 容器内 eth0(即 vethA-peer)发出数据包
  • 通过 Veth Pair 直接传递到宿主机的 vethA
  • docker0 网桥接收并转发数据包到 vethB
(2)网桥:基于 MAC 地址的二层转发
  • MAC 学习机制 网桥维护 MAC 地址表(可通过 brctl showmacs docker0 查看),记录端口与 MAC 的映射关系:

MAC地址

端口

3e:30:83:c4:92:54

vethA

36:e5:74:e0:27:80

vethB

代码语言:bash
AI代码解释
复制
  # brctl showmacs docker0
  port no mac addr                is local?       ageing timer
    2     26:12:cf:e4:da:80       no               297.59
    2     36:e5:74:e0:27:80       yes                0.00
    2     36:e5:74:e0:27:80       yes                0.00
    1     3e:30:83:c4:92:54       yes                0.00
    1     3e:30:83:c4:92:54       yes                0.00
    
  字段说明
  port no:  网桥端口编号,对应连接到网桥的接口
  mac addr: 学习到的 MAC 地址
  is local?:
  	yes:  表示该 MAC 地址属于宿主机本地接口(如网桥自身或直接连接的 Veth 宿主机端)
  	no:   表示该 MAC 地址是外部学习到的(如容器内部的 Veth 设备)
  ageing timer: 条目剩余存活时间(秒),归零后删除。0.00 表示该条目被标记为永久或刚被更新

转发决策

  • 若目标 MAC 存在于表中,数据包直接转发到对应端口
  • 若未知 MAC,进行泛洪(Flood)广播到所有端口(除来源端口)
(3)IP 通信的完整流程

ContainerA(172.17.0.2) 访问 ContainerB(172.17.0.3) 为例:

  1. ARP 请求(二层发现) ContainerA 通过广播查询 172.17.0.3 的 MAC 地址。
  2. 网桥泛洪广播 网桥将 ARP 请求广播到所有连接的容器,ContainerB 响应其 MAC。
  3. 建立 TCP 连接(四层通信) MAC 地址已知后,通过 IP 和端口进行应用层通信。

3.3 实验验证

手动模拟容器通信:
代码语言:bash
AI代码解释
复制
# 创建两个Network Namespace
ip netns add ns1
ip netns add ns2

# 创建Veth Pair并分配到Namespace
ip link add veth1 type veth peer name veth1-peer
ip link set veth1-peer netns ns1
ip netns exec ns1 ip link set veth1-peer name eth0

ip link add veth2 type veth peer name veth2-peer
ip link set veth2-peer netns ns2
ip netns exec ns2 ip link set veth2-peer name eth0

# 创建网桥并连接Veth
brctl addbr mybridge
brctl addif mybridge veth1
brctl addif mybridge veth2

# 启动设备
ip link set mybridge up
ip link set veth1 up
ip link set veth2 up

# 配置容器IP
ip netns exec ns1 ip addr add 10.0.0.1/24 dev eth0
ip netns exec ns1 ip link set eth0 up
ip netns exec ns2 ip addr add 10.0.0.2/24 dev eth0
ip netns exec ns2 ip link set eth0 up

# 测试连通性
ip netns exec ns1 ping 10.0.0.2
观察Docker实际环境:
代码语言:bash
AI代码解释
复制
# 查看docker0网桥信息
# brctl show docker0
bridge name     bridge id               STP enabled     interfaces
docker0         8000.7a2a35e08d9f       no              veth2cb4daf
                                                        veth6f43f82
                                                       

定位Veth Pair对应的容器:

代码语言:bash
AI代码解释
复制
1.获取Veth接口索引号
# ip link show veth2cb4daf
13: veth2cb4daf@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether 36:e5:74:e0:27:80 brd ff:ff:ff:ff:ff:ff link-netnsid 1
说明:
13::宿主机上 veth2cb4daf 接口的索引号为 13
@if2 表示其对端接口在另一个网络命名空间的索引为2
link-netnsid 1 表示该Veth对端所在的网络命名空间ID(需结合其他命令解析)


2.列出所有容器的网络命名空间
# ls -l /var/run/docker/netns/
total 0
-r--r--r-- 1 root root 0 Mar 31 23:32 426133a3ab9c
-r--r--r-- 1 root root 0 Mar 31 22:45 default
-r--r--r-- 1 root root 0 Mar 31 23:32 e1f62106d430

3.进入容器网络命名空间验证
# nsenter --net=/var/run/docker/netns/426133a3ab9c ip link show eth0
2: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 26:12:cf:e4:da:80 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    
@if13 对应宿主机的 veth2cb4daf 接口索引号13,确认Veth Pair关系。

四、容器无法互通的排查指南

基础环境确认

代码语言:bash
AI代码解释
复制
# 确认两个容器在同一子网
docker inspect <容器ID> | grep IPAddress

# 确认docker0网桥的子网
ip addr show docker0

检查容器路由表

代码语言:bash
AI代码解释
复制
# 进入容器Network Namespace检查路由
nsenter --net=/var/run/docker/netns/<容器netns> ip route
  • 异常处理
    • 若缺少默认路由:重建容器或检查Docker守护进程配置
    • 若目标IP路由错误:检查容器启动时的 --network 参数

验证ARP表

代码语言:bash
AI代码解释
复制
# 容器A中查询容器B的ARP记录
nsenter --net=/var/run/docker/netns/<容器A-netns> arp -n | grep 172.17.x.x

# 容器B中查询容器A的ARP记录
nsenter --net=/var/run/docker/netns/<容器B-netns> arp -n | grep 172.17.x.x
  • 正常现象:应显示对方IP对应的MAC地址
  • ARP未学习
    • 检查网桥是否禁用学习功能(brctl setageing docker0 0 会关闭学习)

检查网桥MAC学习表

代码语言:bash
AI代码解释
复制
brctl showmacs docker0 | grep -E '3e:30:83:c4:92:54|26:12:cf:e4:da:80' # 示例MAC
  • 正常现象:两个容器的MAC地址应出现在不同端口的 is local?=no 条目。
  • 异常处理
    • 若MAC未学习:重启网桥 ip link set docker0 down && ip link set docker0 up
    • 若MAC冲突:重启冲突容器

跨命名空间抓包分析

代码语言:bash
AI代码解释
复制
# 宿主机抓取veth接口流量(容器A的宿主机端Veth)
tcpdump -i veth123456 -nn -e icmp

# 容器内抓包(进入容器Network Namespace)
nsenter --net=/var/run/docker/netns/<容器B-netns> tcpdump -i eth0 -nn -e icmp
  • 正常现象
    • 容器A发出的ICMP请求应出现在宿主机veth接口和容器B的eth0
    • 容器B的响应应出现在反向路径
  • 常见异常
    • 单向流量:检查iptables规则是否丢弃数据包
    • 无任何流量:检查veth接口状态(ip link show veth123456

其他排障

  • 检查Veth Pair连接状态 ethtool -S vethXXX 查看数据包计数,确认是否有丢包
  • 跟踪iptables规则 Docker会自动添加NAT规则,检查是否有冲突:
代码语言:bash
AI代码解释
复制
  iptables -t nat -L -n -v

五、总结

在这篇文章中,主要为你介绍了在本地环境下,单机容器网络的实现原理和 docker0 网桥的作用。

这里的关键在于,容器要想跟外界进行通信,它发出的 IP 包就必须从它的 Network Namespace 里出来,来到宿主机上。

而解决这个问题的方法就是:为容器创建一个一端在容器里充当默认网卡、另一端在宿主机上的 Veth Pair 设备。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
理解Docker跨多主机容器网络
在Docker 1.9 出世前,跨多主机的容器通信方案大致有如下三种: 1、端口映射 将宿主机A的端口P映射到容器C的网络空间监听的端口P’上,仅提供四层及以上应用和服务使用。这样其他主机上的容器通过访问宿主机A的端口P实 现与容器C的通信。显然这个方案的应用场景很有局限。 2、将物理网卡桥接到虚拟网桥,使得容器与宿主机配置在同一网段下 在各个宿主机上都建立一个新虚拟网桥设备br0,将各自物理网卡eth0桥接br0上,eth0的IP地址赋给br0;同时修改Docker daemon的DOCKER_OPTS
Rainbond开源
2018/05/31
1.6K0
Docker 网络
Docker 服务启动时会首先在主机上自动创建一个 docker0 的虚拟网桥,网桥可以理解为一个软件交换机,负责挂载其上的接口之间进行包转发。
张哥编程
2024/12/07
750
容器网络基础(一)
我们一定听过容器的基础原理,namespace做隔离,Cgroups做限制,rootfs做文件系统,容器本质上是linux的一个进程,那么为什么大多数场景下,容器不直接使用宿主机上的网络,而要是通过network namespace隔离出一组专属的网络空间呢?(容器的基础原理,可参考:https://coolshell.cn/articles/17010.html)
智零办法就是多
2022/04/13
1.5K0
解密Docker容器网络
一个Linux容器能看见的“网络栈”,被隔离在它自己的Network Namespace中。
JavaEdge
2023/07/09
3600
解密Docker容器网络
容器网络实践
本文通过docker的网络介绍容器网络的原理以及一些实践,通过实践一遍相信大家会对网络底层的原理有个更深的理解,最后给出对接ovs的教程,这对下一篇k8s对接ovn的原理理解打下一个基础。
sealyun
2019/07/25
7400
18 Sep 2019 容器网络(一)
所以,当容器不能上网时,首先ping docker0网桥,看是否能正常连接docker0网桥,然后查看docker0及相应的veth pair设备的iptables规则是否有异常,一般就能解决容器不能上网的问题了。
俊采
2023/10/17
2220
Docker 网络模式详解及容器间网络通信
Docker本身在它创建之初,它就有自己的网络驱动器,叫Container Network Manager,简称CNM。本身这个CNM会支持多种模式,本节来看一看这些模式的区别,然后去了解一下,要让一个容器网络真正地配置好,让容器真正地模拟成一个虚拟机,我们最终要做哪些配置。
贾维斯Echo
2024/03/20
2.7K0
Docker 网络模式详解及容器间网络通信
Docker容器网络-基础篇
Docker的技术依赖于Linux内核的虚拟化技术的发展,Docker使用到的网络技术有Network Namespace、Veth设备对、Iptables/Netfilter、网桥、路由等。接下来,我将以Docker容器网络实现的基础技术来分别阐述,在到真正的容器篇章节之前,能形成一个稳固的基础知识网。
民工哥
2020/09/17
2.1K0
Docker容器网络-基础篇
K8s面试系列: Flannel VS Calico 基于 L2 与 L3 的 CNI 之战(一)
在童年期,我们更多是处于认知,而不是意欲的状态。—— 《作为意欲和表象的世界》第二卷第三十一章
山河已无恙
2025/02/25
1220
K8s面试系列: Flannel VS Calico 基于 L2 与 L3 的 CNI 之战(一)
一文读懂 Kubernetes 容器网络
在Kubernetes中要保证容器之间网络互通,网络至关重要。而Kubernetes本身并没有自己实现容器网络,而是通过插件化的方式自由接入进来。在容器网络接入进来需要满足如下基本原则:
iMike
2021/02/07
6600
干货 | 手把手带你搞定4大容器网络问题
一直以来,网络都是容器中令人头疼的问题。本文的主要目的是带你解决容器网络问题,让你不再对它恐惧。
CloudBest
2021/03/29
1K0
干货 | 手把手带你搞定4大容器网络问题
036.集群网络-K8S网络模型及Linux基础网络
  Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,并假定所有Pod都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否运行在同一个Node(宿主机)中,都要求它们可以直接通过对方的IP进行访问。设计这个原则的原因是,用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑如何将容器端口映射到主机端口等问题。
不会飞的小鸟
2020/03/22
7430
Docker单机网络模型动手实验
容器的本质就是一个进程,只不过对它进行了Linux Namesapce隔离,让它看不到外面的世界,用Cgroups限制了它能使用的资源,同时利用系统调用pivot_root或chroot切换了进程的根目录,把容器镜像挂载为根文件系统rootfs。rootfs中不仅有要运行的应用程序,还包含了应用的所有依赖库,以及操作系统的目录和文件。rootfs打包了应用运行的完整环境,这样就保证了在开发、测试、线上等多个场景的一致性。
mazhen
2023/11/24
2960
Docker单机网络模型动手实验
说说linux容器的隔离
说到docker,大家都懂。但是LXC可能就比较陌生。Docker的起源于LXC。LXC的英文全称是Linux Container,相比较其他虚拟机而言,是一种轻量级虚拟化技术,它介于Chroot(linux的一个改变根目录挂载点的机制)和完整开发的虚拟机之间。LXC不使用单独的内核资源,但是可以创建一个类似的Linux操作系统环境。
mariolu
2020/02/13
3.2K0
Docker容器学习梳理--容器间网络通信设置(Pipework和Open vSwitch)
自从Docker容器出现以来,容器的网络通信就一直是被关注的焦点,也是生产环境的迫切需求。容器的网络通信又可以分为两大方面:单主机容器上的相互通信,和跨主机的容器相互通信。下面将分别针对这两方面,对容器的通信原理进行简单的分析,帮助大家更好地使用docker。前面已经在Docker容器学习梳理--基础知识(2)这一篇中详细介绍了Docker的网络配置以及pipework工具。 docker单主机容器通信 基于对net namespace的控制,docker可以为在容器创建隔离的网络环境,在隔离的网络环境下,
洗尽了浮华
2018/01/23
3.5K0
Docker容器学习梳理--容器间网络通信设置(Pipework和Open vSwitch)
云原生时代必须具备的核心技能之Docker高级篇(Docker网络详解)
  前面给大家项目的介绍了Docker的基础内容 Docker基础篇 接下来给大家系统的介绍下Docker高级篇的内容:网络核心、Docker实战、DockerCompose、Harbor以及Swarm。欢迎关注收藏哦
用户4919348
2022/01/06
6860
云原生时代必须具备的核心技能之Docker高级篇(Docker网络详解)
面试官:Docker 有几种网络模式?5 年工作经验都表示答不上来。。
Docker在安装后自动提供3种网络,可以使用docker network ls命令查看
Java技术栈
2023/02/27
8050
面试官:Docker 有几种网络模式?5 年工作经验都表示答不上来。。
Kubernetes网络模型
在Kubernetes中设计了一种网络模型,要求无论容器运行在集群中的哪个节点,所有容器都能通过一个扁平的网络平面进行通信,即在同一IP网络中。需要注意的是:在K8S集群中,IP地址分配是以Pod对象为单位,而非容器,同一Pod内的所有容器共享同一网络名称空间。
mikelLam
2022/10/31
1.2K0
Kubernetes网络模型
【重识云原生】第六章容器6.1.12节——Docker网络模型设计
        先来简要回顾一下前面的内容,namespace和cgroup是Linux 内核的两大特性,namespace的诞生据说就是为了支持容器技术,那么这俩特性到底干了啥呢?
江中散人_Jun
2022/09/28
4660
【重识云原生】第六章容器6.1.12节——Docker网络模型设计
使用 Linux 网络虚拟化技术探究容器网络原理
在 使用 Go 和 Linux Kernel 技术探究容器化原理 一文中,我们揭秘了容器的本质就是一个特殊的进程,特殊在为其创建了 NameSpace 隔离运行环境,并用 Cgroups 为其控制资源开销。
gopher云原生
2022/11/22
1.7K0
使用 Linux 网络虚拟化技术探究容器网络原理
推荐阅读
相关推荐
理解Docker跨多主机容器网络
更多 >
LV.3
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验