Kubernetes_容器网络_01_Docker网络原理(二)

news2024/12/24 9:00:53

文章目录

  • 一、前言
  • 二、被隔离的Docker容器
  • 三、网桥Bridge
  • 四、VethPair网络对
  • 五、统一宿主机上的两个Container容器通信
  • 六、宿主机访问其上的容器
  • 七、宿主机上的容器访问另一个宿主机
  • 八、尾声

一、前言

二、被隔离的Docker容器

Linux 网络,就包括:网卡(Network Interface)、路由表(Routing Table)和 防火墙 (iptables 规则 / firewalld 端口)

作为一个容器,它可以声明直接使用宿主机的网络栈(–net=host),即:不开启 Network Namespace,比如:

$ docker run –d –net=host --name nginx-host nginx

在这种情况下,这个容器启动后,直接监听的就是宿主机的 80 端口。

像这样直接使用宿主机网络栈的方式,虽然可以为容器提供良好的网络性能,但也会不可避免地引入共享网络资源的问题,比如端口冲突。所以,在大多数情况下,我们都希望容器进程能使用自己 Network Namespace 里的网络栈,即:拥有属于自己的 IP 地址和端口。

这时候,一个显而易见的问题就是:这个被隔离的容器进程,该如何跟其他 Network Namespace 里的容器进程进行交互呢?

三、网桥Bridge

为了理解这个问题,你其实可以把每一个容器Container看做一台主机,它们都有一套独立的“网络栈”。如果你想要实现两台主机之间的通信,最直接的办法,就是把它们用一根网线连接起来;而如果你想要实现多台主机之间的通信,那就需要用网线,把它们连接在一台交换机上。

在 Linux 中,能够起到虚拟交换机作用的网络设备,是网桥(Bridge)。网桥Bridge是一个工作在数据链路层(Data Link)的网络设备,主要功能是根据 MAC 地址学习来将数据包转发到网桥的不同端口(Port)上。

当然,至于为什么这些主机之间需要 MAC 地址才能进行通信,这就是网络分层模型的基础知识了。不熟悉这块内容的读者,可以通过这篇文章来学习一下。

四、VethPair网络对

而为了实现上述目的,Docker 项目会默认在宿主机上创建一个名叫 docker0 的网桥,凡是连接在 docker0 网桥上的容器,就可以通过它来进行通信。可是,我们又该如何把这些容器“连接”到 docker0 网桥上呢?这时候,我们就需要使用一种名叫 Veth Pair 的虚拟设备了。

Veth Pair 设备的特点是:它被创建出来后,总是以两张虚拟网卡(Veth Peer)的形式成对出现的。并且,从其中一个“网卡”发出的数据包,可以直接出现在与它对应的另一张“网卡”上,哪怕这两个“网卡”在不同的 Network Namespace 里。

这就使得 Veth Pair 常常被用作连接不同 Network Namespace 的“网线”。比如,现在我们启动了一个叫作 nginx-1 的容器:

$ docker run –d --name nginx-1 nginx



# 在宿主机上
$ docker exec -it nginx-1 /bin/bash
# 在容器里
root@2b3c181aecf1:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 364  bytes 8137175 (7.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 281  bytes 21161 (20.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        
$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

可以看到,这个容器里有一张叫作 eth0 的网卡,它正是一个 Veth Pair 设备在容器里的这一端。通过 route 命令查看 nginx-1 容器的路由表:
(1) 第一条 default 路由规则:这个 eth0 网卡是这个容器里的默认路由设备,Linux机器默认路由是 172.17.0.1
(2) 第二条 172.17.0.0 路由规则:所有对 172.17.0.0/16 网段的请求,也会被交给 eth0 来处理。

而这个 Veth Pair 设备的另一端,则在宿主机上。你可以通过查看宿主机的网络设备看到它,如下所示:

# 查看宿主机上的网卡
$ ifconfig
...
docker0   Link encap:Ethernet  HWaddr 02:42:d8:e4:df:c1  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:d8ff:fee4:dfc1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:309 errors:0 dropped:0 overruns:0 frame:0
          TX packets:372 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:0 
          RX bytes:18944 (18.9 KB)  TX bytes:8137789 (8.1 MB)
veth9c02e56 Link encap:Ethernet  HWaddr 52:81:0b:24:3d:da  
          inet6 addr: fe80::5081:bff:fe24:3dda/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:288 errors:0 dropped:0 overruns:0 frame:0
          TX packets:371 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:0 
          RX bytes:21608 (21.6 KB)  TX bytes:8137719 (8.1 MB)
# 第一次查看宿主机上的网桥          
$ brctl show
bridge name bridge id  STP enabled interfaces
docker0  8000.0242d8e4dfc1 no  veth9c02e56

通过 ifconfig 命令的输出,你可以看到,nginx-1 容器对应的 Veth Pair 设备,在宿主机上是一张虚拟网卡。它的名字叫作 veth9c02e56。并且,通过 brctl show 的输出,你可以看到这张网卡被“插”在了 docker0 上。

五、统一宿主机上的两个Container容器通信

这时候,如果我们再在这台宿主机上启动另一个 Docker 容器,比如 nginx-2:

# 启动并运行第二个容器container
$ docker run –d --name nginx-2 nginx
# 再次查看宿主机上的网桥
$ brctl show
bridge name bridge id  STP enabled interfaces
docker0  8000.0242d8e4dfc1 no  veth9c02e56
       vethb4963f3

你就会发现一个新的、名叫 vethb4963f3 的虚拟网卡,也被“插”在了 docker0 网桥上。这时候,如果你在 nginx-1 容器里 ping 一下 nginx-2 容器的 IP 地址(172.17.0.3),就会发现同一宿主机上的两个容器默认就是相互连通的。

当你在 nginx-1 容器里访问 nginx-2 容器的 IP 地址(比如 ping 172.17.0.3)的时候,这个目的 IP 地址会匹配到 nginx-1 容器里的第二条路由规则。可以看到,这条路由规则的网关(Gateway)是 0.0.0.0,这就意味着这是一条直连规则,即:凡是匹配到这条规则的 IP 包,应该经过本机的 eth0 网卡,通过二层网络直接发往目的主机。【这里的两层网络就是指 数据链路层,就是 TCP/IP 五层网络模型中的第二层】

而要通过二层网络到达 nginx-2 容器,就需要有 172.17.0.3 这个 IP 地址对应的 MAC 地址。所以 nginx-1 容器的网络协议栈,就需要通过 eth0 网卡发送一个 ARP 广播,来通过 IP 地址查找对应的 MAC 地址。

备注:ARP(Address Resolution Protocol),是通过三层的 IP 地址找到对应的二层 MAC 地址的协议。

我们前面提到过,这个 eth0 网卡,是一个 Veth Pair,它的一端在这个 nginx-1 容器的 Network Namespace 里,而另一端则位于宿主机上(Host Namespace),并且被“插”在了宿主机的 docker0 网桥上。

一旦一张虚拟网卡被“插”在网桥上,它就会变成该网桥的“从设备”。从设备会被“剥夺”调用网络协议栈处理数据包的资格,从而“降级”成为网桥上的一个端口。而这个端口唯一的作用,就是接收流入的数据包,然后把这些数据包的“生杀大权”(比如转发或者丢弃),全部交给对应的网桥。

所以,在收到这些 ARP 请求之后,docker0 网桥就会扮演二层交换机的角色,把 ARP 广播转发到其他被“插”在 docker0 上的虚拟网卡上。这样,同样连接在 docker0 上的 nginx-2 容器的网络协议栈就会收到这个 ARP 请求,从而将 172.17.0.3 所对应的 MAC 地址回复给 nginx-1 容器。

有了这个目的 MAC 地址,nginx-1 容器的 eth0 网卡就可以将数据包发出去。而根据 Veth Pair 设备的原理,这个数据包会立刻出现在宿主机上的 veth9c02e56 虚拟网卡上。不过,此时这个 veth9c02e56 网卡的网络协议栈的资格已经被“剥夺”,所以这个数据包就直接流入到了 docker0 网桥里。

docker0 处理转发的过程,则继续扮演二层交换机的角色。此时,docker0 网桥根据数据包的目的 MAC 地址(也就是 nginx-2 容器的 MAC 地址),在它的 CAM 表(即交换机通过 MAC 地址学习维护的端口和 MAC 地址的对应表)里查到对应的端口(Port)为:vethb4963f3,然后把数据包发往这个端口。

而这个端口,正是 nginx-2 容器“插”在 docker0 网桥上的另一块虚拟网卡,当然,它也是一个 Veth Pair 设备。这样,数据包就进入到了 nginx-2 容器的 Network Namespace 里。

所以,nginx-2 容器看到的情况是,它自己的 eth0 网卡上出现了流入的数据包。这样,nginx-2 的网络协议栈就会对请求进行处理,最后将响应(Pong)返回到 nginx-1。以上,就是同一个宿主机上的不同容器通过 docker0 网桥进行通信的流程了。我把这个流程总结成了一幅示意图,如下所示:

在这里插入图片描述

需要注意的是,在实际的数据传递时,上述数据的传递过程在网络协议栈的不同层次,都有 Linux 内核 Netfilter 参与其中。所以,如果感兴趣的话,你可以通过打开 iptables 的 TRACE 功能查看到数据包的传输过程,具体方法如下所示:

# 在宿主机上执行
$ iptables -t raw -A OUTPUT -p icmp -j TRACE
$ iptables -t raw -A PREROUTING -p icmp -j TRACE

通过上述设置,你就可以在 /var/log/syslog 里看到数据包传输的日志了。

熟悉了 docker0 网桥的工作方式,你就可以理解,在默认情况下,被限制在 Network Namespace 里的容器进程,实际上是通过 Veth Pair 设备 + 宿主机网桥的方式,实现了跟同其他容器的数据交换。

六、宿主机访问其上的容器

与之类似地,当你在一台宿主机上,访问该宿主机上的容器的 IP 地址时,这个请求的数据包,也是先根据路由规则到达 docker0 网桥,然后被转发到对应的 Veth Pair 设备,最后出现在容器里。这个过程的示意图,如下所示:

在这里插入图片描述

七、宿主机上的容器访问另一个宿主机

同样地,当一个容器试图连接到另外一个宿主机时,比如:ping 10.168.0.3,它发出的请求数据包,首先经过 docker0 网桥出现在宿主机上。然后根据宿主机的路由表里的直连路由规则(10.168.0.0/24 via eth0)),对 10.168.0.3 的访问请求就会交给宿主机的 eth0 处理。

所以接下来,这个数据包就会经宿主机的 eth0 网卡转发到宿主机网络上,最终到达 10.168.0.3 对应的宿主机上。当然,这个过程的实现要求这两台宿主机本身是连通的。这个过程的示意图,如下所示:

在这里插入图片描述

所以说,当你遇到容器连不通“外网”的时候,你都应该先试试 docker0 网桥能不能 ping 通,然后查看一下跟 docker0 和 Veth Pair 设备相关的 iptables 规则是不是有异常,往往就能够找到问题的答案了。

不过,在最后一个“Docker 容器连接其他宿主机”的例子里,你可能已经联想到了这样一个问题:如果在另外一台宿主机(比如:10.168.0.3)上,也有一个 Docker 容器。那么,我们的 nginx-1 容器又该如何访问它呢?这个问题,其实就是容器的“跨主通信”问题。

在 Docker 的默认配置下,一台宿主机上的 docker0 网桥,和其他宿主机上的 docker0 网桥,没有任何关联,它们互相之间也没办法连通。所以,连接在这些网桥上的容器,自然也没办法进行通信了。不过,万变不离其宗。如果我们通过软件的方式,创建一个整个集群“公用”的网桥,然后把集群里的所有容器都连接到这个网桥上,不就可以相互通信了吗?说得没错。这样一来,我们整个集群里的容器网络就会类似于下图所示的样子:

在这里插入图片描述

可以看到,构建这种容器网络的核心在于:我们需要在已有的宿主机网络上,再通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络。所以,这种技术就被称为:Overlay Network(覆盖网络)。

甚至,每台宿主机上,都不需要有一个这种特殊的网桥,而仅仅通过某种方式配置宿主机的路由表,就能够把数据包转发到正确的宿主机上。这些内容,我在后面的文章中会为你一一讲述。

八、尾声

Linux上,Namespace用来资源隔离,cgroup用来资源限制

每一个docker container 都有六个独立的命名空间,和网络通信相关的是 network ns。因为每个docker container都有一个独立network ns,不同的 network ns 默认网络是不通的,所以 docker container 之间网络是不通的,通过一种底层技术 veth pair 让 container 之间可以通信,宿主机与其上运行的 container 可以通信。

但是,不同宿主机之间的情况,比如宿主机上的容器访问另一个宿主机,或者 宿主机上的容器访问另一个宿主机上的容器, 还是网络不通,怎么解决这个问题呢?需要用到 overlay network 技术,这种技术 docker 本身是没有的,通过专门的 cni 插件时间,cni 全名为 container network interface ,即容器网络接口,具体实现如常见的 flannel 插件,calico 插件 。

这就是 K8S 的内容了。

参考资料:https://ghostwritten.blog.csdn.net/article/details/119485267

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/508629.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

技术选型对比- RPC(Feign VS Dubbo)

协议 Dubbo 支持多传输协议: Dubbo、Rmi、http,可灵活配置。默认的Dubbo协议&#xff1a;利用Netty&#xff0c;TCP传输&#xff0c;单一、异步、长连接&#xff0c;适合数据量小(传送数据小&#xff0c;不然影响带宽&#xff0c;响应速度)、高并发和服务提供者远远少于消费者…

UnityWebGL+阿里云服务器+Apache完成项目搭建展示

一、服务器相关 Step1:租借一台阿里云服务器 我自己租借了一台北京的ECS服务器&#xff0c;有免费一年的活动&#xff0c;1 vCPU 2 GiB&#xff0c;我自己选择的Ubuntu系统&#xff0c;也可以选择Windows系统 Step2:进入远程连接 进入自己的服务器实例后&#xff0c;点击远程…

vue+elementui+nodejs机票航空飞机航班查询与推荐

语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode )本系统主要是为旅客提供更为便利的机票预定方式&#xff0c;同时提高民航的预定机票的工作效率。通过网络平台实现信息化和网络化&am…

关于Android的性能优化,主要是针对哪些方面的问题进行优化

前言 我们在开发Android的时候&#xff0c;经常会遇到一些性能问题&#xff1b;例如&#xff1a;卡顿、无响应&#xff0c;崩溃等&#xff0c;当然&#xff0c;这些问题为我们可以从日志来进行追踪&#xff0c;尽可能避免此类问题的发生&#xff0c;要解决这些问题&#xff0c…

mysql从零开始(05)----锁

全局锁 使用 # 启用全局锁 flush tables with read lock # 释放全局锁 unlock tables开启全局锁后&#xff0c;整个数据库就处于只读状态了&#xff0c;这种状态下&#xff0c;对数据的增删改操作、对表结构的更改操作都会被阻塞。 另外&#xff0c;当会话断开&#xff0c;全…

【1015. 可被 K 整除的最小整数】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给定正整数 k &#xff0c;你需要找出可以被 k 整除的、仅包含数字 1 的最 小 正整数 n 的长度。 返回 n 的长度。如果不存在这样的 n &#xff0c;就返回 -1。 注意&#xff1a; n 不符合 64 位带…

手把手教你在winform中将文本或文件路径拖到控件中

文章目录 前言博主履历介绍&#xff1a;一、将txt文件的所有内容复制到 RichTextBox中二、将txt文件的一行内容移动到RichTextBox中三、将多个文件的全路径复制到 RichTextBox中四 、源码1、[Winform从入门到精通&#xff08;1&#xff09;——&#xff08;如何年入30万&#x…

「MIAOYUN」:降本增效,赋能传统企业数字化云原生转型 | 36kr 项目精选

作为新经济综合服务平台第一品牌&#xff0c;36氪自2019年落地四川站以来&#xff0c;不断通过新锐、深度的商业报道&#xff0c;陪跑、支持四川的新经济产业。通过挖掘本土优质项目&#xff0c;36氪四川帮助企业链接更多资源&#xff0c;助力企业成长&#xff0c;促进行业发展…

分布式系统概念和设计——命名服务设计和落地经验

分布式系统概念和设计 通过命名服务&#xff0c;客户进程可以根据名字获取资源或对象的地址等属性。 被命名的实体可以是多种类型&#xff0c;并且可由不同的服务管理。 命名服务 命名是一个分布式系统中的非常基础的问题&#xff0c;名字在分布式系统中代表了广泛的资源&#…

C语言:指针求解鸡兔同笼问题

题目&#xff1a;鸡兔同笼问题 要求&#xff1a;使用自定义函数void calc(int h, int f,int *c,int *r) 求解鸡兔同笼问题。 h 表示总的头数&#xff0c;f 表示总的脚数。 例子&#xff1a; 输入&#xff1a; 5 16 输出&#xff1a; 2 3 分析&#xff1a; 在该代码中&a…

05-Docker安装Mysql、Redis、Tomcat

Docker 安装 Mysql 以安装 Mysql 5.7为例&#xff1a; docker pull mysql:5.7Mysql 单机 Mysql 5.7安装 启动 Mysql 容器&#xff0c;并配置容器卷映射&#xff1a; docker run -d -p 3306:3306 \--privilegedtrue \-v /app/mysql/log:/var/log/mysql \-v /app/mysql/data:…

ASP.NET Core MVC 从入门到精通之文件上传

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…

VMware NSX-T Data Center 3.2.2.1 - 数据中心网络全栈虚拟化

请访问原文链接&#xff1a;https://sysin.org/blog/vmware-nsx-t-3/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org VMware NSX-T Data Center 3.2.2.1 | 30 MAR 2023 | Build 21487560 VMware NSX-T Data Center 3.2.2 | 08 …

NOA上车「清一色」自主品牌,哪些供应商正在突围前线

随着入门级L2进入普及周期&#xff0c;以NOA&#xff08;高速、城区&#xff09;为代表的L2/L2赛道&#xff0c;正在成为主机厂、硬件供应商、算法及软件方案商的下一波市场制高点的争夺阵地。 高工智能汽车研究院监测数据显示&#xff0c;2023年1-3月中国市场&#xff08;不含…

MySQL基础(十六)变量、流程控制与游标

1. 变量 在MySQL数据库的存储过程和函数中&#xff0c;可以使用变量来存储查询或计算的中间结果数据&#xff0c;或者输出最终的结果数据。 在 MySQL 数据库中&#xff0c;变量分为系统变量以及用户自定义变量。 1.1 系统变量 1.1.1 系统变量分类 变量由系统定义&#xff…

【Nacos在derby模式下密码忘记】使用derby的ij工具重置密码/修改密码

【问题描述】 nacos部署未用mysql,直接运行&#xff0c;使用了默认的derby数据库&#xff0c;这时候不一小心修改的密码给忘记了&#xff0c;无法登录 当时是部署在centos上的一个演示环境&#xff0c;没有采用mysql数据库&#xff0c;如果生产上&#xff0c;建议使用mysql。 …

php用户分享信息技术交流大学生论坛系统vue

系统应实现的目标 1. 提供安全、友好的操作环境&#xff1a;避免一些网上的不良言论&#xff0c;创造一个和谐的网络环境。 2. 提供发表帖子功能&#xff1a;注册的用户可以自由发帖&#xff0c;发表符合法律法规的言论。 3. 提供回复帖子功能&#xff1a;户可以自由回复&am…

camunda执行监听器如何使用

在Camunda工作流引擎中&#xff0c;执行监听器是一种机制&#xff0c;用于在业务流程执行期间捕获特定事件并执行相应的操作。它们可以帮助您实现一些重要的任务&#xff0c;例如&#xff1a; 1、记录或更新业务数据&#xff1a;当流程中的任务或事件发生时&#xff0c;您可以…

工程监测无线中继采集发送仪 指示灯功能说明及接口定义

工程监测NLM5无线中继采集发送仪 指示灯功能说明及接口定义 指示灯功能说明 标识 名称 状态 描述说明 备注说明 CHG 正在充电 常亮 正在充电 DON 充电完成 常亮 已充满 POW 电源指示 常亮 外部电源已连接 仅用于指示是否连接了外部电源 熄灭 无外部电源 SIG 空 RUN 运行状态 闪…

“数字社区”诞生 “智慧大脑”助力提升社区综合治理效能

近日&#xff0c;民政局等9部门印发的《关于深入推进智慧社区建设的意见》提出&#xff0c;到2025年&#xff0c;基本构建起网格化管理、精细化服务、信息化支撑、开放共享的智慧社区服务平台&#xff0c;初步打造成智慧共享、和睦共治的新型数字社区。 数字社区建设是智慧城市…