滴普技术荟 - 云原生基座 OpenKube 开放容器实践(二):理解 linux 虚拟网络设备 veth
前言
前面介绍了 linux network namespace,接着介绍一下如何让一个独立的网络命名空间和主机的网络互通,这里我们需要用到 linux 虚拟网络设备 veth。
veth 设备
veth 是 linux 的一种虚拟网络设备,它有点类似于两张网卡中间用一条网线连着,veth 设备总是成对出现,通常用来连接不同网络命名空间(下面开始简称 NS),一端连着 NS1 的内核协议栈,另一端连着 NS2 的内核协议栈,一端发送的数据会立刻被另一端接收。
接下来我们通过一些示例来理解 veth 设备,我们创建一个新的 NS,然后跟主机的 NS 连接起来通过下面的命令可以创建一对 veth 设备:
然后创建一个名为 ns1 的 network namespace:
然后把刚创建的 veth1 网卡的其中一端转到 ns1,这就好像一端插到 ns1 上,另一端插在主机的 ns 上:
给 veth 的两端都配置个 IP,设置 veth0 时,要用 ip netns exec ns1,因为 veth0 此时在 ns1 中:
此时的状态如下:
这时候主机和 ns1 已经可以相互 ping 通了:
如果我们进到 ns1 中发现 ping localhost 不通的话,有可能只是因为 lo 网卡没有启动起来
如果我们进到 ns1 中发现 ping localhost 不通的话,有可能只是因为 lo 网卡没有启动起来
这条路由指示以后凡是往 192.168.10.0/24 这个网段的地址都给 veth1,这显然不是我们想要的结果,因为其它的 ns 并没有连在 veth1 上。在 k8s 的节点上,相同主机的 pod 通常会在同一个子网段里,前面那条路由就相当于把这个主机的全部 pod 的通信都引到了 veth1 上,这就有问题了。其实,我们是可以不在 veth1 上配置 IP 的,上面的示例只是为了让大家可以对 veth 连接的效果有个认识,因为 veth1 连的是主机的内核协议栈,主机上已经有很多个 IP 了,只是因为当前 ns1 中没有默认路由,去主机的 IP 的话是不通的(当然如果你的主机的网段本来就是 192.168.10.0/24 网段,那又是能通的),所以如果不配置 veth1 端的 IP 的话,只要加上默认路由就可以了,下面我们演示一个更实用的场景。
另一种方法
直接上命令,跟上面的差不多,也是建一对 veth 网卡,一端转到新的 ns 上,在这就不一句句解释了:
打开主机这一端 veth3 的 arp 代答:
给 ns2 加上默认路由:
在主机上添加去往 ns2 路由:
为什么 ns2 的默认路由是个这么奇怪的 IP?后面会解释。
此时整个状态如下图:
这时候 ping 一下 ns2,发现通了:
那 ns1 和 ns2 能不能相互 ping 通呢?行的,不过要先打开 veth1 的 arp 代答,并给 ns1 配个默认网关
如无意外,在 ns1 上 ping ns2 应该是通了,记得要打开主机的路由转发功能:
简单解释一下为什么给 ns2 设置的默认网关是 169.2.2.2,其实默认网关的 IP 在整个通信的过程中都不会用到,想一下数据包发送流程,当 ns2 的要发一个包去主机时,封完 IP 头后,到了链路层,协议栈的路由判决已经决定了下一跳为默认网关,这时候邻居子系统会从 ns1 的邻居表(也就是 ARP 表)查找下一跳 IP 的 MAC 地址,找不到就会发送 ARP 请求,这时候 ARP 请求到了对端 veth3,因为 veth3 开启了 arp 代答,所以会直接把自己的 MAC 地址返回去,这样 ns2 的邻居子系统会以为自己得到了网关的 MAC 地址,于是完成 MAC 头的封装,把数据包发送到 veth1,所以其实在这里的默认网关的 IP 可以随便写一个非当前网段的地址。
总结
上面介绍了在主机与容器相互连接的两种方法,还有第三种方法就是用 linux bridge,下一章介绍 linux bridge。
欢迎关注滴普科技官网http://datasink-sensors.deepexi.top/t/ta
作者:刘海峰,IT 行业资深码农,
从事.net/java/go 语言开发十余年,
长期关注 springcloud/k8s/linux 网络相关的技术,
现为滴普科技容器产品首席架构师。
版权声明: 本文为 InfoQ 作者【滴普科技2048实验室】的原创文章。
原文链接:【http://xie.infoq.cn/article/a9fb2b2f0cd41faae4885e34e】。文章转载请联系作者。
评论