网站首页 > 技术文章 正文
原理
k8s的知识体系中,网络是一个难点。我将用一系列文章,对k8s的网络方案做一个深入浅出的分享。
虽然容器可以通过–net=host来指定使用宿主机的网络,但是这样就会引入共享网络资源的问题,比如端口冲突。所以一般情况下,我们希望容器进程能使用自己 Network Namespace 里的网络栈,即:拥有属于自己的 IP 地址和端口
那么这就出现了一个根本的问题
这个被隔离的容器进程,该如何跟其他 Network Namespace 里的容器进程进行交互呢
可以类比物理机进行思考,要让两台物理机互通,最简单的方法就是用一根网线把他们连起来。如果是多台物理机,我们就把他们都接到一台交换机上。
那么对于容器,也是同样的道理。
在 Linux 中,能够起到虚拟交换机作用的网络设备,是网桥(Bridge)。网桥是一个二层设备,工作在数据链路层。根据MAC地址将数据包转发到不同的端口。
Docker 会默认在宿主机上创建一个名叫 docker0 的网桥,
凡是连接在 docker0 网桥上的容器,就都可以通过它来进行通信
那么,下一个问题,docker容器怎么连接到docker0网桥上?
答案就是叫做Veth Pair的虚拟设备
根据名字就可以知道,Veth Pair设备的特点就是,虚拟的,并且是成对的。
可以将veth pair想象成一根管子的两端。从这个口放进去的数据包,可以直接出现在对应的另一个口上。即使这两个虚拟网卡在不同的network namespace里。
做个实验
docker run -d -it --name busy-yys busybox
启动一个busybox容器,然后进入容器查看网卡
docker exec -it busy-yys /bin/sh
看一下容器里的路由
# 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 * 255.255.0.0 U 0 0 0 eth0
这个容器里有一张叫作 eth0 的网卡,它正是一个 Veth Pair 设备在容器里的这一端
根据第二条路由,所有对 172.17.0.0/16 网段的请求,也会被交给 eth0 来处理
再看宿主机上
# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:1eff:fe0d:1279 prefixlen 64 scopeid 0x20<link>
ether 02:42:1e:0d:12:79 txqueuelen 0 (Ethernet)
RX packets 3 bytes 125 (125.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 11 bytes 858 (858.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.250.151.208 netmask 255.255.255.0 broadcast 10.250.151.255
inet6 fe80::f816:3eff:fe35:5192 prefixlen 64 scopeid 0x20<link>
ether fa:16:3e:35:51:92 txqueuelen 1000 (Ethernet)
RX packets 1789919595 bytes 294856793516 (274.6 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1774732821 bytes 281152040711 (261.8 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth066ee4f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::7829:83ff:fe0e:c99 prefixlen 64 scopeid 0x20<link>
ether 7a:29:83:0e:0c:99 txqueuelen 0 (Ethernet)
RX packets 3 bytes 167 (167.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 11 bytes 858 (858.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
虚拟设备veth066ee4f就是veth pair在宿主机上的另一端
然后查看一下网桥的情况
# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02421e0d1279 no veth066ee4f
可以看到,虚拟网卡veth066ee4f已经被注册到网桥docker0上了。
(brctl通过yum -y install bridge-utils安装)
我们再启动一个容器
docker run -d -it --name busy-2 busybox
# docker exec -it busy-2 /bin/sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
看到busy-2的ip是172.17.0.2
veth3950859: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::8ce9:31ff:fecf:6df0 prefixlen 64 scopeid 0x20<link>
ether 8e:e9:31:cf:6d:f0 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth066ee4f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::7829:83ff:fe0e:c99 prefixlen 64 scopeid 0x20<link>
ether 7a:29:83:0e:0c:99 txqueuelen 0 (Ethernet)
RX packets 3 bytes 167 (167.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 11 bytes 858 (858.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
宿主机上增加了对应的veth
# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02421e0d1279 no veth066ee4f
veth3950859
新增的veth:veth3950859,也增加到了网桥docker0上
容器ping容器
在容器里互相ping,发现可以ping通。
原理也很简单,从容器的route信息看到
172.17.0.0 * 255.255.0.0 U 0 0 0 eth0
gateway是*,表示这个网段172.17.0.0 /16是本地直连路由,不需要经过网关,应该经过本机的 eth0 网卡,通过二层网络直接发往目的主机 。
然后,对容器来说,本机的eth0,是veth pair的一端。根据前面的介绍,数据包会直接到宿主机上的另一端。
而另一端的虚拟网卡是插在网桥docker0上的。一旦插到网桥上,这个虚拟网卡的功能就只剩下接收数据包,对数据包的处理全部有网桥docker0掌握。
网桥docker0是一个二层设备,通过mac地址转发数据包。所以会通过arp广播,根据ip得到所有对应虚拟网卡的mac。
有了mac地址,网桥docker0就会将数据包发给对应的veth端口。
这样,数据包就会到达容器内对应的eth0口。
宿主机ping容器
同理,可以分析。在宿主机上直接ping 容器的ip,也是通的。
查看宿主机的route
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
可以看到这一条规则。0.0.0.0和*一样,同表示这是一条直连规则。
也是到网桥docker0。后面就一样了。
容器ping宿主机
容器的数据包,直接出现在docker0上,本身就是通的。
容器ping其他主机
只要目标主机和容器的宿主机是通的
那么容器的数据包经过 docker0 网桥出现在宿主机上,之后根据宿主机的路由表里的路由规则,就可以到达目标主机。
其他主机ping容器
很明显,不会通的。因为其他主机上并没有这个网桥docker0。
网桥docker0只能处理本机的网络。
一台宿主机上的 docker0 网桥,和其他宿主机上的 docker0 网桥,没有任何关联,它们互相之间也没办法连通
进而根据这种网桥的思路,如果我们要做到跨主机的容器互通,一个办法就是打造一个集群公用的超级网桥,将所有的容器都注册上来。
那么就可以做到跨节点的容器互通了。
这也就是下面要说的k8s的overlay网络。
- 上一篇: Docker容器网络bridge
- 下一篇: docker 容器能访问宿主机上的 mysql 服务
猜你喜欢
- 2024-12-02 Docker容器网络实操教程
- 2024-12-02 Docker笔记:Docker网络知识介绍
- 2024-12-02 容器网络二-docker网桥原理
- 2024-12-02 Docker + Wasm 入门讲解
- 2024-12-02 新手学Docker:关于网络
- 2024-12-02 Docker 容器安全风险和防御综述
- 2024-12-02 网络包是如何在主机以及网络上进行流转的
- 2024-12-02 在Docker中安装ipsec-vpn过程记录
- 2024-12-02 linux网络虚拟化:network namespace之间的通信
- 2024-12-02 docker 容器能访问宿主机上的 mysql 服务
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)