k8s-的网络模型及常用网络插件

Docker网络

容器网络

Docker使用Linux桥接模式,在宿主机虚拟一个Docker容器网桥(docker0)

桥接模式:桥接模式就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信

在桥接的作用下,类似于把物理主机虚拟为一个交换机,所有桥接设置的虚拟机连接到这个交换机的一个接口上,物理主机也同样插在这个交换机当中,所以所有桥接下的网卡与网卡都是交换模式的,相互可以访问而不干扰。在桥接模式下,虚拟机ip地址需要与主机在同一个网段,如果需要联网,则网关与DNS需要与主机网卡一致。

[root@bogon WEB-INF]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:fc:57:e2 brd ff:ff:ff:ff:ff:ff
    inet 172.31.202.45/24 brd 172.31.202.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fefc:57e2/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:98:04:68:a9 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:98ff:fe04:68a9/64 scope link 
       valid_lft forever preferred_lft forever
#lo是本机回环地址 ens33是阿里云的内网地址 docker0是docker默认的网卡

Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

[root@bogon /]# docker run -d -P --name tomcat01 tomcat
83b4703873b5213054e7e506e721a5d68f1ca40521ac68b363616a7f333fa981
#查看容器内ip
[root@bogon /]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
       
[root@bogon /]# docker run -d -P --name tomcat02 tomcat
56bb3fef856fa86b39bd862c5227893fad81b2cc64daaabd67f54680e6708782
[root@bogon /]# docker exec -it tomcat02 ip addr        
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
       
#发现linux能ping通容器内部
[root@bogon /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.207 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.065 ms

查看主机ip

[root@bogon /]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:fc:57:e2 brd ff:ff:ff:ff:ff:ff
    inet 172.31.202.45/24 brd 172.31.202.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fefc:57e2/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:98:04:68:a9 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:98ff:fe04:68a9/64 scope link 
       valid_lft forever preferred_lft forever
15: veth77b0c46@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 22:b3:44:bf:da:48 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::20b3:44ff:febf:da48/64 scope link 
       valid_lft forever preferred_lft forever
17: veth6dbc1f1@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether be:44:4f:0f:dd:ea brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::bc44:4fff:fe0f:ddea/64 scope link 
       valid_lft forever preferred_lft forever

#evth pair就是一对的虚拟设备接口,都是成对出现的,一段连着协议,一段连着彼此
#测试后容器1、2都互通,因为都是通过172.17.0.1桥接

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

img

img

#有些时候,我们面临服务ip更换情况,该如何通过服务名字访问容器?

–link

[root@bogon /]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
#发现名字不通,通过--link可以解决
[root@bogon /]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
a88d674661576633a7a4431e8adbe78fc8352a7f1802b1681b950b6b01a98140
[root@bogon /]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.124 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.075 ms
#我们发现可以ping通,那么反向可以ping通吗?
[root@bogon /]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
#ping不通

#我们通过docker ipspect查看容器网卡内容
#其实是tomcat03本地配置了一个tomcat02的配置,而tomcat02并没有配置
[root@bogon /]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3      tomcat02 56bb3fef856f #此处为配置的容器2的ip
172.17.0.4      a88d67466157

–link其实是在hosts中配置了一个172.17.0.3的名字映射,docker0并不支持容器名访问

自定义网络

查看所有网络

[root@bogon /]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.
[root@bogon /]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
22afa40fd7c0   bridge    bridge    local
459c2f2fb892   host      host      local
a2db766f6b7d   none      null      local

网络模式

img

bridge模式

在bridge模式下,Docker Daemon首次启动时会创建一个虚拟网桥docker0,地址通常为172.x.x.x开头,在私有的网络空间中给这个网络分配一个子网。由Docker创建处理的每个容器,都会创建一个虚拟以太设备(Veth设备对),一端关联到网桥,另一端使用Namespace技术映射到容器内的eth0设备,然后从网桥的地址段内给eth0接口分配一个IP地址。

img

一般情况,宿主机IP与docker0 IP、容器IP是不同的IP段,默认情况,外部看不到docker0和容器IP,对于外部来说相当于docker0和容器的IP为内网IP。

#我们可以定义一个网络
[root@bogon /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
0f87b54b4ddb7fb5176cf6374eba394137bc779e371cbcf1ff48725cf63b7e3c
[root@bogon /]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
22afa40fd7c0   bridge    bridge    local
459c2f2fb892   host      host      local
0f87b54b4ddb   mynet     bridge    local
a2db766f6b7d   none      null      local
#发现我们增加的一张网卡mynet有了
#查看我们自己的网卡
[root@bogon /]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "0f87b54b4ddb7fb5176cf6374eba394137bc779e371cbcf1ff48725cf63b7e3c",
        "Created": "2021-02-23T21:02:43.683566918Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
#指定子网创建容器
[root@bogon /]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
fec147df5306fefca7351a4dbc468f57fe2b6bbf0c42ae149faea542ba6f7c7f
[root@bogon /]# docker run -d -P --name tomcat-net-02 --net mynet tomcat 
f71e3b62d14cc55d227741f245408ea2f4e3c08bd189daa340a2dbc1dc5b5dfe
[root@bogon /]# docker network inspect mynet
        "Containers": {
            "f71e3b62d14cc55d227741f245408ea2f4e3c08bd189daa340a2dbc1dc5b5dfe": {
                "Name": "tomcat-net-02",
                "EndpointID": "8d4405c2b71e935eae8f9d7036654d53c46907660a92bcc73676ce6f1ff47796",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "fec147df5306fefca7351a4dbc468f57fe2b6bbf0c42ae149faea542ba6f7c7f": {
                "Name": "tomcat-net-01",
                "EndpointID": "fdd6d46a987477ef5abb882c6ec19831c6dc4c6830909448537901056e6d5ce4",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
#我们发现了自己创建的容器的ip,开始测试ping
[root@bogon /]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.113 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.079 ms
[root@bogon /]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.065 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.081 ms
#我们发现互相连通,并可以访问服务

img

网络连接

#使用docker network connect使容器桥接到另一张网卡,因为此时tomcat01其实是桥接在了docker0上的
[root@bogon /]# docker network connect mynet tomcat01
[root@bogon /]# docker exec -it tomcat02 ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.121 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=0.080 ms
64 bytes from 192.168.0.1: icmp_seq=4 ttl=64 time=0.106 ms
^C
--- 192.168.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.059/0.091/0.121/0.025 ms
[root@bogon /]# docker exec -it tomcat02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
#其实此时就相当于tomcat01有两个ip,一个公网一个私网
[root@bogon /]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
25: eth1@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:c0:a8:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.0.4/16 brd 192.168.255.255 scope global eth1
       valid_lft forever preferred_lft foreve

img

Kubernetes

Kubernetes网络模型

在Kubernetes网络中存在两种IP(Pod IP和Service Cluster IP),Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,Service Cluster IP它是一个虚拟IP,是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。

Kubernetes Pod网络设计模型:

1、基本原则:

每个Pod都拥有一个独立的IP地址(IPper Pod),而且假定所有的pod都在一个可以直接连通的、扁平的网络空间中。

2、设计原因:

用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑将容器端口映射到主机端口等问题。

3、网络要求:

所有的容器都可以在不用NAT的方式下同别的容器通讯;所有节点都可在不用NAT的方式下同所有容器通讯;容器的地址和别人看到的地址是同一个地址。

Kubernetes网络基础

容器间通信:

img

  • 在k8s中每个Pod中管理着一组Docker容器,这些Docker容器共享同一个网络命名空间。(pause容器)
  • Pod中的每个Docker容器拥有与Pod相同的IP和port地址空间,并且由于他们在同一个网络命名空间,他们之间可以通过localhost相互访问。

什么机制让同一个Pod内的多个docker容器相互通信那?其实是使用Docker的一种网络模型:–net=container

每个Pod容器有有一个pause容器其有独立的网络命名空间(pause容器就相当于自定义的网络),在Pod内启动Docker容器时候使用 –net=container就可以让当前Docker容器加入到Pod容器拥有的网络命名空间(pause容器)
img

Pod与Pod之间的网络:

img

  • k8s中,每个Pod拥有一个ip地址,不同的Pod之间可以直接使用改ip与彼此进行通讯
  • 在同一个Node上,从Pod的视角看,它存在于自己的网络命名空间中,并且需要与该Node上的其他网络命名空间上的Pod进行通信。

那么是如何做到的?是使用linux虚拟以太网设备或者说是由两个虚拟接口组成的veth对使不同的网络命名空间链接起来而实现的,这些虚拟接口分布在多个网络命名空间上(这里是指多个Pod上)。

为了让多个Pod的网络命名空间链接起来,我们可以让veth对的一端链接到root网络命名空间(宿主机的),另一端链接到Pod的网络命名空间。

每对Veth就像一根接插电缆,连接两侧并允许流量在它们之间流动;这种veth对可以推广到同一个Node上任意多的Pod上,如上图这里展示使用veth对链接每个Pod到虚拟机的root网络命名空间。

同一Node中Pod间通信:

鉴于每个Pod有自己独立的网络命名空间,我们使用虚拟以太网设备把多个Pod的命名空间链接到了root命名空间,并且使用网桥让多个Pod之间进行通信

img

  • 通过网桥这里把veth0和veth1组成为一个以太网,他们直接是可以直接通信的,另外这里通过veth对让pod1的eth0和veth0、pod2的eth0和veth1关联起来,从而让pod1和pod2相互通信。
  • Pod 1通过自己默认的以太网设备eth0发送一个数据包,eth0把数据传递给veth0,数据包到达网桥后,网桥通过转发表把数据传递给veth1,然后虚拟设备veth1直接把包传递给Pod2网络命名空间中的虚拟设备eth0.

img

同一Node中Pod的默认路由都是docker0的地址,由于它们关联在同一个docker0网桥上,地址网段相同,所有它们之间应当是能直接通信的。

不同Node中Pod间通信:

k8s网络模型需要每个pod必须通过ip地址可以进行访问,每个pod的ip地址总是对网络中的其他pod可见

不同Node中Pod间通信要满足2个条件: Pod的IP不能冲突; 将Pod的IP和所在的Node的IP关联起来,通过这个关联让Pod可以互相访问。

k8s中每个集群中的每个Node都会被分配了一个CIDR块(无类别域间路由选择,把网络前缀都相同的连续地址组成的地址组称为CIDR地址块)用来给该Node上的Pod分配IP地址,保证不同Node中Pod间通信的2个条件

img

  • 如上图Node1上的Pod1与Node2上Pod2之间进行交互。

  • 首先pod1通过自己的以太网设备eth0把数据包发送到关联到的vethx上,然后数据包被Node1上的网桥设备docker0接受到,网桥查找转发表发现找不到pod2的Mac地址,则会把包转发到默认路由(eth0设备),然后数据包经过eth0就离开了Node1,被发送到网络。

  • 数据包到达Node2后,首先会被Node2命名空间的eth0设备,然后通过网桥docker0把数据路由到虚拟设备vethx,最终数据表会被流转到与vethx配对的另外一端

每个Node都知道如何把数据包转发到其内部运行的Pod,当一个数据包到达Node后,其内部数据流就和Node内Pod之间的流转类似了。

对于如何来配置网络,k8s在网络这块自身并没有实现网络规划的具体逻辑,而是制定了一套CNI(Container Network Interface)接口规范,开放给社区来实现。

Pod与Service之间的网络

上面展示了Pod之间如何通过他们自己的ip地址进行通信,但是pod的ip地址是不持久的,当集群中pod的规模缩减或者pod故障或者node故障重启后,新的pod的ip就可能与之前的不一样的。所以k8s中衍生出来Service来解决这个问题。

k8s中 Service管理了一系列的Pods,每个Service有一个虚拟的ip,要访问service管理的Pod上的服务只需要访问你这个虚拟ip就可以了,这个虚拟ip是固定的,当service下的pod规模改变、故障重启、node重启时候,对使用service的用户来说是无感知的,因为他们使用的service的ip没有变。

当数据包到达Service虚拟ip后,数据包会被通过k8s给该servcie自动创建的负载均衡器路由到背后的pod容器

看看具体是如何做到的

netfilter

为了实现负载均衡,k8s依赖linux内建的网络框架-netfilter。Netfilter是Linux提供的内核态框架,允许使用者自定义处理接口实现各种与网络相关的操作。 Netfilter为包过滤,网络地址转换和端口转换提供各种功能和操作,以及提供禁止数据包到达计算机网络内敏感位置的功能。在linux内核协议栈中,有5个跟netfilter有关的钩子函数,数据包经过每个钩子时,都会检查上面是否注册有函数,如果有的话,就会调用相应的函数处理该数据包

  • NF_IP_PRE_ROUTING: 接收的数据包刚进来,还没有经过路由选择,即还不知道数据包是要发给本机还是其它机器。

  • NF_IP_LOCAL_IN: 已经经过路由选择,并且该数据包的目的IP是本机,进入本地数据包处理流程。

  • NF_IP_FORWARD: 已经经过路由选择,但该数据包的目的IP不是本机,而是其它机器,进入forward流程。

  • NF_IP_LOCAL_OUT: 本地程序要发出去的数据包刚到IP层,还没进行路由选择。

  • NF_IP_POST_ROUTING: 本地程序发出去的数据包,或者转发(forward)的数据包已经经过了路由选择,即将交由下层发送出去。

iptables

iptables是运行在用户态的用户程序,其基于表来管理规则,用于定义使用netfilter框架操作和转换数据包的规则。根据rule的作用分成了好几个表,比如用来过滤数据包的rule就会放到filter表中,用于处理地址转换的rule就会放到nat表中,其中rule就是应用在netfilter钩子上的函数,用来修改数据包的内容或过滤数据包。目前iptables支持的表有下面这些:

  • Filter:从名字就可以看出,这个表里面的rule主要用来过滤数据,用来控制让哪些数据可以通过,哪些数据不能通过,它是最常用的表。

  • NAT(*):里面的rule都是用来处理网络地址转换的,控制要不要进行地址转换,以及怎样修改源地址或目的地址,从而影响数据包的路由,达到连通的目的,这是家用路由器必备的功能。

  • Mangle:里面的rule主要用来修改IP数据包头,比如修改TTL值,同时也用于给数据包添加一些标记,从而便于后续其它模块对数据包进行处理(这里的添加标记是指往内核skb结构中添加标记,而不是往真正的IP数据包上加东西)。

  • Raw:在netfilter里面有一个叫做connection tracking的功能,主要用来追踪所有的连接,而raw表里的rule的功能是给数据包打标记,从而控制哪些数据包不被connection tracking所追踪。

  • Security:里面的rule跟SELinux有关,主要是在数据包上设置一些SELinux的标记,便于跟SELinux相关的模块来处理该数据包。

在k8s中,iptables规则由kube-proxy控制器配置,该控制器监视K8s API服务器的更改。当对Service或Pod的虚拟IP地址进行修改时,iptables规则也会更新以便让service能够正确的把数据包路由到后端Pod。

iptables规则监视发往Service虚拟IP的流量,并且在匹配时,从可用Pod集合中选择随机Pod IP地址,iptables规则将数据包的目标IP地址从Service的虚拟IP更改为选定的Pod的ip。总的来说iptables已在机器上完成负载平衡,并将指向Servcie的虚拟IP的流量转移到实际的pod的IP。

在从service到pod的路径上,IP地址来自目标Pod。 在这种情况下,iptables再次重写IP头以将Pod IP替换为Service的IP,以便Pod认为它一直与Service的虚拟IP通信。

IPVS

k8s的最新版本(1.11)包括了用于集群内负载平衡的第二个选项:IPVS。 IPVS(IP Virtual Server)也构建在netfilter之上,并实现传输层负载平衡(属于Linux内核的一部分)。 IPVS包含在LVS(Linux虚拟服务器)中,它在主机上运行,并在真实服务器集群前充当负载均衡器。 IPVS可以将对基于TCP和UDP的服务的请求定向到真实服务器,并使真实服务器的服务在单个IP地址上显示为虚拟服务。这使得IPVS非常适合Kubernetes服务。

声明Kubernetes服务时,您可以指定是否要使用iptables或IPVS完成群集内负载平衡。 IPVS专门用于负载平衡,并使用更高效的数据结构(哈希表),与iptables相比,允许几乎无限的规模。在创建IPVS负载时,会发生以下事情:在Node上创建虚拟IPVS接口,将Service的IP地址绑定到虚拟IPVS接口,并为每个Service额IP地址创建IPVS服务器。将来,期望IPVS成为集群内负载平衡的默认方法。

Kubernetes网络开源组件

技术术语

**IPAM:**IP地址管理;这个IP地址管理并不是容器所特有的,传统的网络比如说DHCP其实也是一种IPAM,到了容器时代我们谈IPAM,主流的两种方法: 基于CIDR的IP地址段分配地或者精确为每一个容器分配IP。但总之一旦形成一个容器主机集群之后,上面的容器都要给它分配一个全局唯一的IP地址,这就涉及到IPAM的话题。

**Overlay:**在现有二层或三层网络之上再构建起来一个独立的网络,这个网络通常会有自己独立的IP地址空间、交换或者路由的实现。

**IPSesc:**一个点对点的一个加密通信协议,一般会用到Overlay网络的数据通道里。

**vxLAN:**由VMware、Cisco、RedHat等联合提出的这么一个解决方案,这个解决方案最主要是解决VLAN支持虚拟网络数量(4096)过少的问题。因为在公有云上每一个租户都有不同的VPC,4096明显不够用。就有了vxLAN,它可以支持1600万个虚拟网络,基本上公有云是够用的。

网桥Bridge: 连接两个对等网络之间的网络设备,但在今天的语境里指的是Linux Bridge,就是大名鼎鼎的Docker0这个网桥。

BGP: 主干网自治网络的路由协议,今天有了互联网,互联网由很多小的自治网络构成的,自治网络之间的三层路由是由BGP实现的。

SDN、Openflow: 软件定义网络里面的一个术语,比如说我们经常听到的流表、控制平面,或者转发平面都是Openflow里的术语。

CNM & CNI阵营

为了使容器之间的通信更加方便,容器网络发展到现在,形成了两大阵营,就是Docker的CNM和Google、CoreOS、Kuberenetes主导的CNI。首先明确一点,CNM和CNI并不是网络实现,他们是网络规范和网络体系,从研发的角度他们就是一堆接口,你底层是用Flannel也好、用Calico也好,他们并不关心,CNM和CNI关心的是网络管理的问题。

CNM(Docker LibnetworkContainer Network Model):

Docker Libnetwork的优势就是原生,而且和Docker容器生命周期结合紧密;缺点也可以理解为是原生,被Docker“绑架”。

  • Docker Swarm overlay

  • Macvlan & IP networkdrivers

  • Calico

  • Contiv

  • Weave

CNI(Container NetworkInterface):

CNI的优势是兼容其他容器技术(e.g. rkt)及上层编排系统(Kubernetes & Mesos),而且社区活跃势头迅猛,Kubernetes加上CoreOS主推;缺点是非Docker原生。

  • Kubernetes

  • Weave

  • Macvlan

  • Calico

  • Flannel

  • Contiv

  • Mesos CNI

Flannel容器网络

Flannel之所以可以搭建kubernets依赖的底层网络,是因为它可以实现以下两点:

  • 它给每个node上的docker容器分配相互不冲突的IP地址;
  • 它能给这些IP地址之间建立一个覆盖网络,同过覆盖网络,将数据包原封不动的传递到目标容器内。

Flannel介绍

  • Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。

  • 在默认的Docker配置中,每个节点上的Docker服务会分别负责所在节点容器的IP分配。这样导致的一个问题是,不同节点上容器可能获得相同的内外IP地址。并使这些容器之间能够之间通过IP地址相互找到,也就是相互ping通。

  • Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。

  • Flannel实质上是一种“覆盖网络(overlaynetwork)”,也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持udp、vxlan、host-gw、aws-vpc、gce和alloc路由等数据转发方式,默认的节点间数据通信方式是UDP转发。

img

总的来说,Flannel是大多数用户的不错选择。从管理角度来看,它提供了一个简单的网络模型,用户只需要一些基础知识,就可以设置适合大多数用例的环境。一般来说,在初期使用Flannel是一个稳妥安全的选择,直到你开始需要一些它无法提供的东西。

https://www.kubernetes.org.cn/4887.html

Calico容器网络

Calico介绍

  • Calico是一个纯3层的数据中心网络方案,而且无缝集成像OpenStack这种IaaS云架构,能够提供可控的VM、容器、裸机之间的IP通信。Calico不使用重叠网络比如flannel和libnetwork重叠网络驱动,它是一个纯三层的方法,使用虚拟路由代替虚拟交换,每一台虚拟路由通过BGP协议传播可达信息(路由)到剩余数据中心。

  • Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。

  • Calico节点组网可以直接利用数据中心的网络结构(无论是L2或者L3),不需要额外的NAT,隧道或者Overlay Network。

  • Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。

在Calico插件中,用户可以自定义网络规则,提高安全性并控制网络环境。因此,如果在你的应用场景中,对于网络的控制要求严格,那Calico应该会是你的首选

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐