Kubernetes 网络 (1) Linux network namespace

Submitted by Lizhe on Mon, 07/20/2020 - 07:15

如果你熟悉docker的namespace隔离机制,你应该知道docker的network也是通过 namespace隔离的

要了解kubernetes的网络原理,不得不提到 linux 的network namespace

Linux的 namespace 的作用是 隔离内核资源,命名空间会给其中的进程造成两个错觉

1. 它是系统内唯一的进程

2. 它独享系统的所有资源

network namespace是从 2.6 开始引入的,作用是隔离 Linux 系统的设备,ip 地址、端口、路由表 和 防火墙规则等网络资源

 

创建一个名为 netns1 的 新命名空间

 

sudo ip netns add netns1

当 ip 命令 创建了一个 新命名空间 之后,系统会在 /var/run/netns 目录下生成一个新的挂载点

挂载点的作用在于一方面是为了方便 命名空间管理,另一个方面是使 命名空间  可以在没有进程运行时也能继续存在

20200720034132

sudo ip netns delete netns1

删除命令并不会直接删除这个命名空间,它只是移除了挂载点,这样只要命名空间中仍然有进程运行,它就会一直存在

 

当 namespace 中的进程 涉及到网络通信时,它就需要一个虚拟网络设备 ,一个全新的 namespace 会附带创建一个 本地回环地址,上面的截屏中我们已经看到了。

不过需要注意的是,默认创建的网卡并没有默认启动

 

sudo ip netns exec netns1 ip link set dev lo up

20200720035758

仅有一个回环网卡是无法与外部通信的,之前在旧版本的 docker 上我使用过 veth pair,这里是一样的套路

veth pair 总是成对出现的,报文从一端进去,从另一端出来

这里我在宿主机上 创建两个端点, veth_left 和 veth_right

然后把 veth_left 绑定到 netns1 , 把 veth_right 绑定到(留给,默认就是在宿主机上创建的)当前宿主机

 

lizhe@ubuntu:~$ sudo ip link add veth_left type veth peer name veth_right
lizhe@ubuntu:~$ sudo ip link set veth_left netns netns1
lizhe@ubuntu:~$ 
lizhe@ubuntu:~$ sudo ip netns exec netns1 ifconfig veth_left 10.1.1.1/24 up
lizhe@ubuntu:~$ sudo ifconfig veth_right 10.1.1.2/24 up
 

 

20200720050057

ping 10.1.1.1

sudo ip netns exec netns1 ping 10.1.1.2

命名空间内 和 命名空间外 都可以互相ping通

20200720051933

 

之前我们说 命名空间 的作用是 隔离

那么路由表 和 防火墙 呢

 

sudo ip netns exec netns1 route

sudo ip netns exec netns1 iptables -L

 

20200720053646

 

 

我们试着使用 NAT 让 netns1 可以访问外网

开启 linux kernel ip forwarding

sudo sysctl net.ipv4.ip_forward=1

20200720060028

将 netns1 的默认路由设为 veth_right ( 宿主机的veth ) 的 IP 地址

sudo ip netns exec netns1 route add default gw 10.1.1.2

20200720054928

 

确认一下网卡名称,这里是 ens33

20200720060905

 

配置 SNAT,将从 myspace 发出的网络包的 soruce IP address 替换为 ens33 的 IP 地址

sudo iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o ens33 -j MASQUERADE

 

 

在默认 FORWARD 规则为 DROP 时显式地允许 veth1 和 eth0 之间的 forwarding

lizhe@ubuntu:~$ sudo iptables -t filter -A FORWARD -i eth0 -o veth_right -j ACCEPT
lizhe@ubuntu:~$ sudo iptables -t filter -A FORWARD -o eth0 -i veth_right -j ACCEPT

20200720055705

sudo iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o ens33 -j MASQUERADE

20200720061336

 

最后我们来检查一下 route 并确认结果

20200720061909

 

每个 Linux 进程都拥有一个属于自己的 /proc/PID/ns , 这个目录下的每个文件都代表一个类型的namespace

在内核版本3.8之前,只包含 ipc、net 和 uts 的硬链接

在内核版本3.8之后,每个文件都是一个特殊的符号链接文件。

20200728110423

 

这些符号链接的其中一个用途是 确定两个进程是否同属于 同一个 namespace,
如果两个进程在同一个namespace中,那么这两个进程的 /proc/PID/ns 目录下对应的符号链接文件的 inode, 就是 【】 中的数字,将会是一样的。

另外一个作用是,通过文件描述符,在不需要进程存在的情况下也能保持 namespace 存在。