Kubernetes 网络基础知识

看球不费电
发布于 2023-7-13 13:50
浏览
0收藏

本文主要介绍一些Linux网络基础和概念:namespace、veth pair、bridge、overlay、隧道等技术,便于深入理解Kubernetes网络。

作者:王一之,中国移动云能力中心软件开发工程师,专注于云原生领域。

01Network namespace

在Linux系统中,namespace是一种用于隔离系统资源的机制。通过namespace,可以为每个进程创建一个隔离的环境,使得每个进程看到的系统资源都是独立的,不会受到其他进程的干扰。

Linux系统中有多种类型的namespace,它们分别用于隔离不同的系统资源。例如,pid namespace用于隔离进程树,使得每个namespace中的进程看到的PID都是从1开始的。mount namespace用于隔离文件系统挂载点,使得每个namespace中的进程看到的文件系统都是独立的。


分类


系统调用参数


内核版本


隔离内容


Mount namespaces


CLONE_NEWNS


Linux 2.4.19


文件系统(挂载点)


UTS namespaces


CLONE_NEWUTS


Linux 2.6.19


主机名和域名


IPC namespaces


CLONE_NEWIPC


Linux 2.6.19


信号量、消息队列和共享内存


PID namespaces


CLONE_NEWPID


Linux 2.6.24


进程编号


Network namespaces


CLONE_NEWNET


Linux 2.6.29


网络设备、网络栈、端口等


User namespaces


CLONE_NEWUSER


Linux 3.8


用户、用户组

Network namespace,顾名思义,是用于隔离网络资源的一种namespace,它可以为每个进程或者线程创建一个隔离的网络环境,使得每个进程看到的网络设备和网络配置都是独立的。Docker正是利用了network namespace空间特性,实现了不同容器之间的网络隔离。

Network namespace的常用功能已经集成到Linux的Ip工具的netns子命令中,我们可以通过几个简单的命令感受下network namespace的作用:

ip netns help
Usage: ip netns list
       ip netns add NAME
       ip netns set NAME NETNSID
       ip [-all] netns delete [NAME]
       ip netns identify [PID]
       ip netns pids NAME
       ip [-all] netns exec [NAME] cmd ...
       ip netns monitor
       ip netns list-id

创建一个名为ns1的network namespace:

ip netns add ns1

以下命令表示进入ns1 命名空间执行ip a命令:

ip netns exec ns1 ip a
# 输出:
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

可以对比一下直接执行ip a命令 ,我们发现在新创建的ns中只有环回接口,且状态为DOWN。

顺带一提,创建进程时如何设置namespace?我们经常听到的clone()、unshare()系统调用是什么意思?请看代码:

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};

int container_main(void* arg)
{
    printf("Container - inside the container!\n");
    /* 直接执行一个shell,以便我们观察这个进程空间里的资源是否被隔离了 */
    execv(container_args[0], container_args); 
    printf("Something's wrong!\n");
    return 1;
}

int main()
{
    printf("Parent - start a container!\n");
    /* 启用CLONE_NEWNET Namespace隔离 */
    int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNET | SIGCHLD, NULL);
    waitpid(container_pid, NULL, 0);
    printf("Parent - container stopped!\n");
    return 0;
}

以上代码通过clone()系统调用创建了一个进程,并且通过传递CLONE_NEWNET开启network namespace隔离。按照预期,新进程只能看到lo设备,验证如下:

Kubernetes 网络基础知识-鸿蒙开发者社区

除了clone(),常见的系统调用还有以下2个:

  • unshare():使某进程脱离某个namespace
  • setns():把某进程加入到某个namespace

02Veth pair

新创建的namespace默认不能和其它namespace通信,需要通过一对虚拟网卡,即veth pair(Virtual Ethernet Device)。构造veth pair的过程有点类似于“插网线”,一头插在ns1,另一头插在ns2上,两个ns之间就可以通信了,如下图:

Kubernetes 网络基础知识-鸿蒙开发者社区

接下来我们一起体验下打通ns1和ns2网络的过程:

# 创建两个 network namespace
[root@k8s01 ~]# ip netns add ns1
[root@k8s01 ~]# ip netns add ns2
[root@k8s01 ~]# ip netns list
ns2
ns1

创建一个veth pair,其一端名为veth1,对端为veth2:

[root@k8s01 ~]# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:1c:42:d0:c4:38 brd ff:ff:ff:ff:ff:ff
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:1f:ac:76 brd ff:ff:ff:ff:ff:ff
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:1f:ac:76 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 02:42:5f:2d:6b:22 brd ff:ff:ff:ff:ff:ff
[root@k8s01 ~]# ip link add veth1 type veth peer name veth2
[root@k8s01 ~]# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:1c:42:d0:c4:38 brd ff:ff:ff:ff:ff:ff
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:1f:ac:76 brd ff:ff:ff:ff:ff:ff
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:1f:ac:76 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 02:42:5f:2d:6b:22 brd ff:ff:ff:ff:ff:ff
8: veth2@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:39:60:2d:fd:09 brd ff:ff:ff:ff:ff:ff
9: veth1@veth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fe:a1:45:64:c6:b6 brd ff:ff:ff:ff:ff:ff

可以看到,通过ip link list查询时多了两个网络接口。接下来把veth1绑定到ns1中,转移之后,就只能到ns1里面才能看到了:

[root@k8s01 ~]# ip netns exec ns1 ip link list1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00[root@k8s01 ~]# ip link set veth1 netns ns1[root@k8s01 ~]# ip netns exec ns1 ip link list1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:009: veth1@if8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000    link/ether fe:a1:45:64:c6:b6 brd ff:ff:ff:ff:ff:ff link-netnsid 0

同理,把veth2移到ns2中:

[root@k8s01 ~]# ip link set veth2 netns ns2
[root@k8s01 ~]# ip netns exec ns2 ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
8: veth2@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:39:60:2d:fd:09 brd ff:ff:ff:ff:ff:ff link-netnsid 0

分配ip地址:

[root@k8s01 ~]# ip netns exec ns1 ip a add 10.1.1.1/24 dev veth1
[root@k8s01 ~]# ip netns exec ns1 ip a 
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
9: veth1@if8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether fe:a1:45:64:c6:b6 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 10.1.1.1/24 scope global veth1
       valid_lft forever preferred_lft forever
[root@k8s01 ~]# ip netns exec ns2 ip a add 10.1.1.2/24 dev veth2
[root@k8s01 ~]# ip netns exec ns2 ip a 
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
8: veth2@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 32:39:60:2d:fd:09 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.1.2/24 scope global veth2
       valid_lft forever preferred_lft forever

测试连通性:

[root@k8s01 ~]# ip netns exec ns1 ping 10.1.1.2
connect: Network is unreachable

这里无法ping通是因为veth设备状态为DOWN,表示还未启动。先启动它们:

[root@k8s01 ~]# ip netns exec ns1 ip link set dev veth1 up
[root@k8s01 ~]# ip netns exec ns2 ip link set dev veth2 up

再次测试:

[root@k8s01 ~]# ip netns exec ns1 ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.076 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.070 ms
64 bytes from 10.1.1.2: icmp_seq=3 ttl=64 time=0.065 ms
^C
--- 10.1.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.065/0.070/0.076/0.008 ms
[root@k8s01 ~]# ip netns exec ns2 ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from 10.1.1.1: icmp_seq=2 ttl=64 time=0.076 ms
64 bytes from 10.1.1.1: icmp_seq=3 ttl=64 time=0.071 ms
^C
--- 10.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.063/0.070/0.076/0.005 ms

补充,veth pair对端查找:

# 查找对端所在ns
[root@k8s01 ~]# ip netns exec ns2 ip link show veth2
8: veth2@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 32:39:60:2d:fd:09 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@k8s01 ~]# ip netns exec ns1 ip link show veth1
9: veth1@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether fe:a1:45:64:c6:b6 brd ff:ff:ff:ff:ff:ff link-netnsid 1
[root@k8s01 ~]# ip netns list-id
nsid 0 (iproute2 netns name: ns1)
nsid 1 (iproute2 netns name: ns2)

# 查找对端设备
[root@k8s01 ~]# ip netns exec ns1 ethtool -S veth1
NIC statistics:
     peer_ifindex: 8
[root@k8s01 ~]# ip netns exec ns2 ip link list | grep 8
8: veth2@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000

03Bridge

通过veth pair,我们可以让两个network namespace相互访问。但有个问题,假如存在10个network namespace,仅通过veth pair就会非常麻烦。是否有一种类似交换机的虚拟设备呢?这就是本节的主题:Bridge(网桥)。

Bridge是一种虚拟交换机,有着和物理交换机相同的功能,例如二层交换,MAC地址学习等。我们可以把veth pair、tun/tap等设备连接到网桥上,就像是把设备连接到物理交换机一样,ns之间就可以相互访问了。

我们在启动docker的时候,docker会创建一个docker0网桥。通过veth pair将各个容器(network namespace)接入docker0来打通容器网络。(ps:docker有多种网络模式,这里指默认的bridge模式)

Kubernetes 网络基础知识-鸿蒙开发者社区

接下来,我们通过命令行来实现一下上图的网络结构,首先创建bridge(因为docker0已被占用,用br0替代):

[root@k8s01 ~]# brctl addbr br0
[root@k8s01 ~]# brctl show
bridge name  bridge id    STP enabled  interfaces
br0    8000.000000000000  no    
docker0    8000.02425f2d6b22  no    
virbr0    8000.5254001fac76  yes    virbr0-nic

创建3个ns

[root@k8s01 ~]# ip netns add ns1
[root@k8s01 ~]# ip netns add ns2
[root@k8s01 ~]# ip netns add ns3
[root@k8s01 ~]# ip netns list
ns3
ns2
ns1

创建veth pairs

[root@k8s01 ~]# ip link add veth1 type veth peer name veth-ns1
[root@k8s01 ~]# ip link add veth2 type veth peer name veth-ns2
[root@k8s01 ~]# ip link add veth3 type veth peer name veth-ns3
[root@k8s01 ~]# ip link list
...
10: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 4e:ae:91:1d:14:23 brd ff:ff:ff:ff:ff:ff
11: veth-ns1@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether a6:c7:1b:06:95:15 brd ff:ff:ff:ff:ff:ff
12: veth1@veth-ns1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether de:15:f0:62:e0:f1 brd ff:ff:ff:ff:ff:ff
13: veth-ns2@veth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:72:7c:0e:43:dd brd ff:ff:ff:ff:ff:ff
14: veth2@veth-ns2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 76:a8:93:6e:8e:5c brd ff:ff:ff:ff:ff:ff
15: veth-ns3@veth3: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether c6:3d:78:1b:dd:f2 brd ff:ff:ff:ff:ff:ff
16: veth3@veth-ns3: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 3a:6e:8c:13:47:c6 brd ff:ff:ff:ff:ff:ff

将vethx移到ns中

[root@k8s01 ~]# ip link set veth1 netns ns1
[root@k8s01 ~]# ip link set veth2 netns ns2
[root@k8s01 ~]# ip link set veth3 netns ns3
[root@k8s01 ~]# ip link list
...
10: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 4e:ae:91:1d:14:23 brd ff:ff:ff:ff:ff:ff
11: veth-ns1@if12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether a6:c7:1b:06:95:15 brd ff:ff:ff:ff:ff:ff link-netnsid 0
13: veth-ns2@if14: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:72:7c:0e:43:dd brd ff:ff:ff:ff:ff:ff link-netnsid 1
15: veth-ns3@if16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether c6:3d:78:1b:dd:f2 brd ff:ff:ff:ff:ff:ff link-netnsid 2

启动lo、veth设备,分配ip

[root@k8s01 ~]# ip netns exec ns1 ip link set lo up
[root@k8s01 ~]# ip netns exec ns2 ip link set lo up
[root@k8s01 ~]# ip netns exec ns3 ip link set lo up
[root@k8s01 ~]# ip netns exec ns1 ip link set veth1 up
[root@k8s01 ~]# ip netns exec ns2 ip link set veth2 up
[root@k8s01 ~]# ip netns exec ns3 ip link set veth3 up
[root@k8s01 ~]# ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth1
[root@k8s01 ~]# ip netns exec ns2 ip addr add 10.0.0.2/24 dev veth2
[root@k8s01 ~]# ip netns exec ns3 ip addr add 10.0.0.3/24 dev veth3

将veth的另一端挂载到网桥上,并启动

[root@k8s01 ~]# brctl addif br0 veth-ns1
[root@k8s01 ~]# brctl addif br0 veth-ns2
[root@k8s01 ~]# brctl addif br0 veth-ns3
[root@k8s01 ~]# ip link set veth-ns1 up
[root@k8s01 ~]# ip link set veth-ns2 up
[root@k8s01 ~]# ip link set veth-ns3 up

启动网桥

[root@k8s01 ~]# ip link set br0 up
# 关闭 ip link set br0 down

测试网络连通性

[root@k8s01 ~]# ip netns exec ns1 ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.127 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.134 ms
^C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.127/0.130/0.134/0.011 ms
[root@k8s01 ~]# ^C
[root@k8s01 ~]# ^C
[root@k8s01 ~]# ip netns exec ns2 ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.136 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.115 ms
64 bytes from 10.0.0.3: icmp_seq=3 ttl=64 time=0.118 ms
^C
--- 10.0.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.115/0.123/0.136/0.009 ms

补充:docker会把vethX设备名改成eth0,就像是物理网卡一样

[root@k8s01 ~]# ip netns exec ns1 ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.127 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.134 ms
^C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.127/0.130/0.134/0.011 ms
[root@k8s01 ~]# ^C
[root@k8s01 ~]# ^C
[root@k8s01 ~]# ip netns exec ns2 ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.136 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.115 ms
64 bytes from 10.0.0.3: icmp_seq=3 ttl=64 time=0.118 ms
^C
--- 10.0.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.115/0.123/0.136/0.009 ms

04Overlay

目前为止,我们通过veth pair + bridge的方式,解决了单节点容器网络问题,这也是docker网络的原理。但是,一台主机的docker0与其它主机上的docker0是完全没有关系的。如何解决跨主机通信呢?

我们需要一个能够把所有容器连通起来的网络,这张网络的名字大家应该比较熟悉,就是overlay network。

Kubernetes 网络基础知识-鸿蒙开发者社区

Overlay网络是建立在一个实际的物理网络(Underlay网络)之上的虚拟网络。这句话怎么理解?

比如说,两台主机之间可以通过协议栈走tcp/udp通信(underlay,这是前提)。tcp/udp之上是可以封装其它协议的,如果封装了ip协议,那么可以说这个overlay是虚拟三层网络;如果封装了数据链路协议,那么这个overlay网络就是虚拟二层网络。

参考一张vxlan抓包图:

Kubernetes 网络基础知识-鸿蒙开发者社区

另外,对于ns中的进程来说,它们其实不会感知到自己是走的是overlay还是underlay:

Kubernetes 网络基础知识-鸿蒙开发者社区

pod1直接通过10.0.0.2与pod2访问,并且数据包的转换是在发送之后、接收之前,所以pod是无感知的。

上图中提到的装置是什么?Linux有现成的吗?

有,就是我们经常听到的隧道。接下来对两种主流隧道技术linux tunnel和linux vxlan做简单介绍。

05Tunnel

Linux 原生支持多种三层隧道:ipip | gre | sit | isatap | vti

[root@k8s01 ~]# ip netns exec ns1 ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.127 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.134 ms
^C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.127/0.130/0.134/0.011 ms
[root@k8s01 ~]# ^C
[root@k8s01 ~]# ^C
[root@k8s01 ~]# ip netns exec ns2 ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.136 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.115 ms
64 bytes from 10.0.0.3: icmp_seq=3 ttl=64 time=0.118 ms
^C
--- 10.0.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.115/0.123/0.136/0.009 ms
  • ipip:即IPv4 in IPv4,在IPv4报文的基础上封装一个IPv4报文;
  • GRE:即通用路由封装(Generic Routing Encapsulation),定义了在任意一种网络层协议上封装其他任意一种网络层协议的机制,适用于IPv4和IPv6;
  • sit:和ipip类似,不同的是sit用IPv4报文封装IPv6报文,即IPv6 over IPv4;
  • ISATAP:即站内自动隧道寻址协议(Intra-Site Automatic Tunnel Addressing Protocol),与sit类似,也用于IPv6的隧道封装;
  • VTI:即虚拟隧道接口(Virtual Tunnel Interface),是思科提出的一种IPSec隧道技术。

接下来尝试一下节点之间通过ipip隧道通信:

Kubernetes 网络基础知识-鸿蒙开发者社区

# 查询是否加载了ipip模块,没有的话使用modprobe ipip加载
[root@MiWiFi-R3P-srv ~]# lsmod | grep ipip
ipip                   13465  0 
tunnel4                13252  1 ipip
ip_tunnel              25163  1 ipip

# node1操作
# 创建ipip设备,名为ipip2
# underlay 网卡为eth0,对端地址为 192.168.31.191,本机为 192.168.31.132
ip tunnel add tun0 mode ipip remote 192.168.31.191 local 192.168.31.132 dev eth0
# 启动
ip link set tun0 up
# 设置隧道内层ip
ip addr add 100.0.0.2 peer 100.0.0.3 dev tun0

# node2操作
ip tunnel add tun0 mode ipip remote 192.168.31.132 local 192.168.31.191 dev eth0
ip link set tun0 up
ip addr add 100.0.0.3 peer 100.0.0.2 dev tun0

# 验证,node1
ping 100.0.0.3

ps:使用macox系统通过parallels的两个虚机进行ipip实验时,发现使用”共享网络模式“无法ping通,改为”默认适配器“后可以,原因未知。

ip tuntap和ip tunnel?

关于ip tunnel中的tun是不是ip tuntap中的tun,在多个资料中的解释有些冲突(可能是我理解不对)。仅从使用层面,我个人感觉tuntap和tunnel没有太大关联。

ip tuntap中的tun,我的理解是需要搭配一个用户开发的程序(进程)使用的。当数据包发往tun设备时,程序会接收到数据包,具体数据包怎么处理,由程序决定。即,通过编码决定发往谁、怎么发。flannel的UDP模式是基于tun的,tun的缺点在于多次用户态和内核态之间的数据拷贝,导致性能较差。

06VxLAN

VxLAN(Virtual eXtensible LAN,虚拟可扩展的局域网),是Linux内核自带的一种虚拟化隧道通信技术,它可以通过三层的网络搭建虚拟的二层网络。为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端,这个设备就叫作 VTEP(VXLAN Tunnel End Point,虚拟隧道端点),它的作用是对Ethernet frames进行封包和解包。VxLAN将 L2 的以太网帧(Ethernet frames)封装成 L4 的 UDP 数据包,然后在 L3 的网络中传输,效果就像 L2 的以太网帧在一个广播域中传输一样,实际上是跨越了 L3 网络,但却感知不到 L3 网络的存在。

A framework for overlaying virtualized layer 2 networks over lay 3 networks.

点对点VxLAN实验:

Kubernetes 网络基础知识-鸿蒙开发者社区

# id: VxLan的id标识,需要与对端相同
# dev: bond1.1810 实验主机的underlay网卡
ip link add vxlan1 type vxlan id 100 dstport 4789 remote 100.73.10.36 local 100.73.10.31 dev bond1.1810
ip link set vxlan1 up
ip addr add 10.10.10.2/24 dev vxlan1

ip link add vxlan1 type vxlan id 100 dstport 4789 remote 100.73.10.31 local 100.73.10.36 dev bond1.1810
ip link set vxlan1 up
ip addr add 10.10.10.3/24 dev vxlan1

# 测试
ping 10.10.10.3

VXLAN + Bridge实验:

Kubernetes 网络基础知识-鸿蒙开发者社区

# 100.73.10.31节点
ip link add vxlan0 type vxlan id 88 dstport 4788 remote 100.73.10.36 local 100.73.10.31 dev bond1.1810
ip link add br0 type bridge
ip link set vxlan0 master br0
#避免影响宿主机,通过vrf隔离root network namespace
ip link add vrf0 type vrf table 10 
ip link set br0 master vrf0
ip link set vxlan0 up
ip link set br0 up
ip link set vrf0 up
ip netns add ns0
ip link add veth0 type veth peer name eth0 netns ns0
ip link set veth0 master br0
ip link set veth0 up
ip -n ns0 link set lo up
ip -n ns0 addr add 172.66.1.2/24 dev eth0
ip -n ns0 link set eth0 up

# 100.73.10.36
ip link add vxlan0 type vxlan id 88 dstport 4788 remote 100.73.10.31 local 100.73.10.36 dev bond1.1810
ip link add br0 type bridge
ip link set vxlan0 master br0
ip link add vrf0 type vrf table 10
ip link set br0 master vrf0
ip link set vxlan0 up
ip link set br0 up
ip link set vrf0 up
ip netns add ns0
ip link add veth0 type veth peer name eth0 netns ns0
ip link set veth0 master br0
ip link set veth0 up
ip -n ns0 link set lo up
ip -n ns0 addr add 172.66.1.3/24 dev eth0
ip -n ns0 link set eth0 up

参考资料

- 《Kubernetes权威指南》

- 《深入剖析Kubernetes》

- 《Kubernetes网络权威指南》

- ​https://coolshell.cn/articles/17029.html

- ​https://icloudnative.io/posts/vxlan-linux/

- ​https://zhuanlan.zhihu.com/p/293667316

- ​https://www.cnblogs.com/bakari/p/10564347.html

- ​https://typesafe.cn/categories/

-​https://space.bilibili.com/646178510/channel/collectiondetail?sid=375141

- ​https://lwn.net/Articles/580893/




文章转载自公众号:k8s技术圈

分类
标签
已于2023-7-13 13:50:47修改
收藏
回复
举报
回复
    相关推荐