Container Networking From Scratch观后笔记

最近观看了《Container Networking From Scratch》这个视频,看完之后,需要记录一下。

Q: Kubernetes对于网络的要求?

A: kubernetes的官方描述:

Kubernetes imposes the following fundamental requirements on any networking implementation (barring any intentional network segmentation policies):

  • pods on a node can communicate with all pods on all nodes without NAT
  • agents on a node (e.g. system daemons, kubelet) can communicate with all pods on that node

Note: For those platforms that support Pods running in the host network (e.g. Linux):

  • pods in the host network of a node can communicate with all pods on all nodes without NAT

简单来说,k8s对于网络的要求是:

  • 在没有进行NAT的情况下(without NAT),一个节点(node)上的pods可以同所有节点上的所有pods进行通信
  • 节点上的代理(agents),比如kubelet和system daemons,能够同该节点上的所有pods进行通信
  • 对于支持Pods运行在主机网络上的平台,比如linux,一个位于主机网络上的节点(node)的pods能够在不使用NAT的情况下同所有节点上的所有pods进行通信

这里,我有两个疑问:

  • 什么叫without NAT?NAT就是Network Address translation,简单来说就是网络包在从内网发往外网的时候,将网络包的source ip或者destination ip转换为另一个IP地址。其原因为内部网络的IP地址仅为内部使用,外部无法以该IP定位主机,因此网络包从内部网络经某个设备出去的时候,该网络包的source ip会被translate为该设备的IP地址,以接收返回的网络包。同理,在网络包进来的时候,destination ip也会被变换为网络内部的节点的ip地址。
    那么without NAT的意思呢?我理解的就是当网络包从一个pod发送到另一个pod的时候,源IP或者目的IP都是对应的pod的地址,而不是其他地址。即没有经过NAT转换,不能出现源IP不是发送包的pod的ip二是另外一个ip。
  • 什么叫“支持pod运行在主机网络上的平台,比如linux”?这里理解的就是pods之间可以通过pod所在的主机网络进行通信。

视频里面还有一条:

  • the ip that a container sees itself as is the same IP that others see it

就是说一个容器自己的ip同其他容器看到的值是一样的。

视频里面从什么都没有到完成一个overlay网络,走了四部:

  • Step 1: Single network namespace.
  • Step 2: Single node, 2 network namespaces.
  • Step 3: Multiple nodes, same L2 network.
  • Step 4: Multiple nodes, overlay network.

具体情况,下面记录。

基础知识

  • 容器就是通过一系列的linux 隔离技术,各种namespaces形成的一个isolated process,也就是容器是linux上的一个进程,该进行同其他进程进行了资源隔离。
  • 从网络的角度上来看,一个容器就是一个独立的同其他容器隔离的network namespace(网络命名空间)
  • 主机是一个网络命名空间。
  • 每个独立的网络命名空间,具有独立的ethernet、iptable、route等
  • veth pair。veth即virtual ethernet,虚拟的ethernet。veth pair,即veth对,就是两个虚拟ethernet,他们组成一个pair(对)。我们可以认为veth pair的两个virtual ethernet,就是一根线的两端,请求从一端进入就会从另外一端出去,换句话说就是发往pair中一个ethernet的网络包同时也会被另一个ethernet接收到。

第一步,Single network namespace

先看图:


step1.png

解释一下:

  • node,表示节点,即最大的框
  • con,表示container,即容器,大框里面的小框
  • veth1和veth2是一对veth pair,veth2在容器中,veth1在节点的root namespace里
  • enp0s8是node的ethernet
  • 容器里面的route表明所有的流量默认走veth2
  • 节点上的route表示到172.16.0.1的流量走veth1

该图表示了流量是如何从节点通过route流向veth1,再到容器中的。同时也表明了流量如何从容器,通过容器内的route,veth2流向节点的。

接下来看看代码:

#!/bin/bash -e

. env.sh

echo "Creating the namespace"
sudo ip netns add $CON

echo "Creating the veth pair"
sudo ip link add veth1 type veth peer name veth2

echo "Adding one end of the veth pair to the namespace"
sudo ip link set veth2 netns $CON

echo "Configuring the interface in the network namespace with an IP address"
sudo ip netns exec $CON ip addr add $IP dev veth2

echo "Enabling the interface inside the network namespace"
sudo ip netns exec $CON ip link set dev veth2 up

echo "Enabling the interface on the node"
sudo ip link set dev veth1 up

echo "Setting the loopback interface in the network namespace"
sudo ip netns exec $CON ip link set lo up

echo "Setting the routes on the node"
sudo ip route add $IP/32 dev veth1

echo "Setting the default route in the network namespaces"
sudo ip netns exec $CON ip route add default via $IP dev veth2                                                                                                              

大概流程为:

  • 创建netns,即network namespace
  • 创建veth1和veth2,并将其作为一个pair
  • 将veth2放入刚刚创建的netns
  • 设置veth2的ip地址
  • 启动veth1和veth2
  • 启动netns里面的loopback interface
  • 设置veth1的route(路由),将流量导向veth1
  • 设置netns中的route(路由)

第二步,Single node, 2 network namespaces.

先看图:


step2.jpg

解释一下:

  • 容器1和容器2里面的veth通过veth pair,连接到节点上的网桥br0上
  • 网桥br0连接了veth10和veth20,也就间接连通了容器1和容器2
  • 通过主机的路由,将所有172.16.0.0/24的流量导向网桥br0
  • 设置容器内部路由,将所有流量导向veth

看看代码:

#!/bin/bash -e

. env.sh

echo "Creating the namespaces"
sudo ip netns add $CON1
sudo ip netns add $CON2

echo "Creating the veth pairs"
sudo ip link add veth10 type veth peer name veth11
sudo ip link add veth20 type veth peer name veth21

echo "Adding the veth pairs to the namespaces"
sudo ip link set veth11 netns $CON1
sudo ip link set veth21 netns $CON2

echo "Configuring the interfaces in the network namespaces with IP address"
sudo ip netns exec $CON1 ip addr add $IP1/24 dev veth11
sudo ip netns exec $CON2 ip addr add $IP2/24 dev veth21

echo "Enabling the interfaces inside the network namespaces"
sudo ip netns exec $CON1 ip link set dev veth11 up
sudo ip netns exec $CON2 ip link set dev veth21 up

echo "Creating the bridge"
sudo ip link add name br0 type bridge

echo "Adding the network namespaces interfaces to the bridge"
sudo ip link set dev veth10 master br0
sudo ip link set dev veth20 master br0

echo "Assigning the IP address to the bridge"
sudo ip addr add $BRIDGE_IP/24 dev br0

echo "Enabling the bridge"
sudo ip link set dev br0 up

echo "Enabling the interfaces connected to the bridge"
sudo ip link set dev veth10 up
sudo ip link set dev veth20 up

echo "Setting the loopback interfaces in the network namespaces"
sudo ip netns exec $CON1 ip link set lo up
sudo ip netns exec $CON2 ip link set lo up

echo "Setting the default route in the network namespaces"
sudo ip netns exec $CON1 ip route add default via $BRIDGE_IP dev veth11
sudo ip netns exec $CON2 ip route add default via $BRIDGE_IP dev veth21

相对上一步来说:

  • 创建了两个network namespace
  • 创建网桥
  • 将主机network namespace中的veth加入到网桥上
  • 设置网桥IP地址
  • 设置主机路由规则,将对应的流量导向网桥

第三步,Multiple nodes, same L2 network.

先看图:


step3.jpg

解释一下:

  • 两台主机通过swith进行了连接
  • 主机里面依然同上一步一样,只是在主机路由中,增加了到其他node的路由规则,比如左边节点上的172.16.1.0/24 via 10.0.0.20 enp0s8表明,所有到右边节点的请求都会通过enp0s8发出

看看代码:

#!/bin/bash -e

. env.sh

echo "Creating the namespaces"
sudo ip netns add $CON1
sudo ip netns add $CON2

echo "Creating the veth pairs"
sudo ip link add veth10 type veth peer name veth11
sudo ip link add veth20 type veth peer name veth21

echo "Adding the veth pairs to the namespaces"
sudo ip link set veth11 netns $CON1
sudo ip link set veth21 netns $CON2

echo "Configuring the interfaces in the network namespaces with IP address"
sudo ip netns exec $CON1 ip addr add $IP1/24 dev veth11
sudo ip netns exec $CON2 ip addr add $IP2/24 dev veth21

echo "Enabling the interfaces inside the network namespaces"
sudo ip netns exec $CON1 ip link set dev veth11 up
sudo ip netns exec $CON2 ip link set dev veth21 up

echo "Creating the bridge"
sudo ip link add name br0 type bridge

echo "Adding the network namespaces interfaces to the bridge"
sudo ip link set dev veth10 master br0
sudo ip link set dev veth20 master br0

echo "Assigning the IP address to the bridge"
sudo ip addr add $BRIDGE_IP/24 dev br0

echo "Enabling the bridge"
sudo ip link set dev br0 up

echo "Enabling the interfaces connected to the bridge"
sudo ip link set dev veth10 up
sudo ip link set dev veth20 up

echo "Setting the loopback interfaces in the network namespaces"
sudo ip netns exec $CON1 ip link set lo up
sudo ip netns exec $CON2 ip link set lo up

echo "Setting the default route in the network namespaces"
sudo ip netns exec $CON1 ip route add default via $BRIDGE_IP dev veth11
sudo ip netns exec $CON2 ip route add default via $BRIDGE_IP dev veth21

# ------------------- Step 3 Specific Setup --------------------- #

echo "Setting the route on the node to reach the network namespaces on the other node"
sudo ip route add $TO_BRIDGE_SUBNET via $TO_NODE_IP dev enp0s8

echo "Enables IP forwarding on the node"
sudo sysctl -w net.ipv4.ip_forward=1

同上一步不同的是:

  • 开启了每个节点上的IP转发
  • 设置了到其他节点的路由规则sudo ip route add $TO_BRIDGE_SUBNET via $TO_NODE_IP dev enp0s8

第四步,Multiple nodes, overlay network.

先看图:


step4.jpg

解释一下:

  • 每个节点增加了tun0这样一个ethernet
  • 将到其他节点的流量导入到tun0,而不是上一步中的enp0s8
  • 每个节点上会运行一个进程,该进程负载对到达tun0的网络包进行处理,比如通过vxlan协议将网络包发往另一个节点上的某个端口,该节点上的对应进程会监听该端口,处理接收到的vxlan包,然后根据路由规则(比如172.16.1.0/24 br0)将网络包拆解之后发往网桥,再由网桥转发到对应的veth,最终到达容器内部
  • overlay网络的建立,其关键就是每个节点上有一个进程,由该进程进行封包和转发。其目的地是其他节点上的同样进程监听的端口。

看看代码:

#!/bin/bash -e

. env.sh

echo "Creating the namespaces"
sudo ip netns add $CON1
sudo ip netns add $CON2

echo "Creating the veth pairs"
sudo ip link add veth10 type veth peer name veth11
sudo ip link add veth20 type veth peer name veth21

echo "Adding the veth pairs to the namespaces"
sudo ip link set veth11 netns $CON1
sudo ip link set veth21 netns $CON2

echo "Configuring the interfaces in the network namespaces with IP address"
sudo ip netns exec $CON1 ip addr add $IP1/24 dev veth11
sudo ip netns exec $CON2 ip addr add $IP2/24 dev veth21

echo "Enabling the interfaces inside the network namespaces"
sudo ip netns exec $CON1 ip link set dev veth11 up
sudo ip netns exec $CON2 ip link set dev veth21 up

echo "Creating the bridge"
sudo ip link add name br0 type bridge

echo "Adding the network namespaces interfaces to the bridge"
sudo ip link set dev veth10 master br0
sudo ip link set dev veth20 master br0

echo "Assigning the IP address to the bridge"
sudo ip addr add $BRIDGE_IP/24 dev br0

echo "Enabling the bridge"
sudo ip link set dev br0 up

echo "Enabling the interfaces connected to the bridge"
sudo ip link set dev veth10 up
sudo ip link set dev veth20 up

echo "Setting the loopback interfaces in the network namespaces"
sudo ip netns exec $CON1 ip link set lo up
sudo ip netns exec $CON2 ip link set lo up

echo "Setting the default route in the network namespaces"
sudo ip netns exec $CON1 ip route add default via $BRIDGE_IP dev veth11
sudo ip netns exec $CON2 ip route add default via $BRIDGE_IP dev veth21

echo "Enables IP forwarding on the node"
sudo sysctl -w net.ipv4.ip_forward=1

# ------------------- Step 4 Specific Setup --------------------- #

echo "Starts the UDP tunnel in the background"
sudo socat TUN:$TUNNEL_IP/16,iff-up UDP:$TO_NODE_IP:9000,bind=$NODE_IP:9000 &

echo "Setting the MTU on the tun interface"
sudo ip link set dev tun0 mtu 1492

echo "Disables reverse path filtering"
sudo bash -c 'echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
sudo bash -c 'echo 0 > /proc/sys/net/ipv4/conf/enp0s8/rp_filter'
sudo bash -c 'echo 0 > /proc/sys/net/ipv4/conf/br0/rp_filter'
sudo bash -c 'echo 0 > /proc/sys/net/ipv4/conf/tun0/rp_filter'

同上一步不同的地方在于:

  • 使用socat创建了UDP隧道用于跨节点的流量。该命名将tunnel_ip/16的流量发往节点地址的9000端口
  • 禁用了reverse path filtering
  • 设置了mtu

参考资料:
[1] https://www.youtube.com/watch?v=6v_BDHIgOY8
[2] https://github.com/kristenjacobs/container-networking
[3] https://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容