了解service的案例 容器网络的方案可以通过接入、流控、通道这三个层面: 接入是容器和宿主机之间是使用哪一种机制做连接,比如 Veth + bridge(docker)、Veth + pair(calico) 这样的经典方式,也有利用高版本内核的新机制等其他方式(如 mac/IPvlan 等),来把包送入到宿主机空间;https://developer.aliyun.com/learning/course/572/detail/7865?spm=a2c6h.21258778.0.0.33031a5fMRoyGU&accounttraceid=fb95338e4daf46dcb031b634aed61868ewzb

flannel

flannel作为一个container互联解决方案,不仅提供基于封装类型的互联技术,也提供基于路由技术的互联技术,比如host-gw模式。

host-gw模式:

​ flannel一种协议叫host-gw(host gateway),即****++Node节点把自己的网络接口当做pod的网关使用++****,从而使不同节点上的node进行通信,这个性能比VxLAN高,因为它没有额外开销。不过他有个缺点, 就是各node节点必须在同一个网段中 。 ​ host-gw模式通过建立主机IP到主机上对应flannel子网的mapping,以**++直接路由++**的方式联通flannel的各个子网。这种互联方式没有vxlan等封装方式带来的负担,通过路由机制,实现flannel网络数据包在主机之间的转发。但是这种方式也有不足,那就是所有节点之间都要相互有点对点的路由覆盖,并且所有加入flannel网络的主机需要在同一个LAN里面;所以每个节点上有n-1个路由,而n个节点一共有n(n-1)/2个路由以保证flannel的flat网络能力。

image-20211207120804117 IP Address Management (IPAM) is an integrated suite of tools to enable end-to-end planning, deploying, managing and monitoring of your IP address infrastructure, with a rich user experience. IPAM automatically discovers IP address infrastructure servers and Domain Name System (DNS) servers on your network and enables you to manage them from a central interface.

IPVS模式

​ 从k8s的1.8版本开始,kube-proxy引入了IPVS模式,IPVS模式与iptables同样基于Netfilter,但是采用的hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。IPVS会从TCP SYNC包开始为一个TCP连接所有的数据包建立状态跟踪机制,保证一个TCP连接中所有的数据包能到同一个后端。所以IPVS是基于TCP状态机进行控制管理,++只感知TCP头而不对TCP的payload进行查看++。 ipvs只能做负载均衡,而做不了nat转换。ipvs 会使用 iptables 进行包过滤、SNAT、masquared(伪装)。具体来说,ipvs 将使用ipset来存储需要DROPmasquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的

邻居子系统:

MAC地址唯一标识一台主机,当系统要发送数据到其他主机时,必须事先知道它的MAC地址, 并且上层应用协议并不关心MAC地址,然而在数据链接层,必须要获取发送方和接收方的MAC地址,这样数据才能正确到达接收方。邻居子系统的作用就是把IP地址转换成对应的MAC地址. 如果目的主机不是和发送发位于同一局域网时,解析的MAC地址就是下一跳网关地址。

邻居子系统支持多种实现,例如ARP,ND等,这些实现需要在其初始化的时候,调用neigh_table_init将邻居表项添加到全局邻居子系统数组中,并对实例中的字段(如hash,定时器等)进行相关初始化

Calico

Calico是Kubernetes生态系统中另一种流行的网络选择。Calico CNI插件在CNI框架内封装了Calico的功能。Calico是一个基于BGP的纯三层的网络方案。Calico在每个计算节点都利用Linux Kernel实现了一个高效的虚拟路由器vRouter来负责数据转发。为了支持三层网络,Calico还推出了IP-in-IP叠加的模型,它也使用Overlay的方式来传输数据。IPIP的包头非常小,而且也是内置在内核中,因此理论上它的速度要比VxLAN快一点 ,但安全性更差。Calico 3.x的默认配置使用的是IPIP类型的传输方案而非BGP。
vim calico-etcd.yaml
            # Enable IPIP
            - name: CALICO_IPV4POOL_IPIP
              value: "Always"

image.png

实验环境:

# alias k=kubectl
[root@k8s-master01 ~]# k get node -owide
NAME           STATUS   ROLES                  AGE    VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
k8s-master01   Ready    control-plane,master   219d   v1.22.4   192.168.31.201   <none>        CentOS Linux 7 (Core)   3.10.0-1160.49.1.el7.x86_64   docker://20.10.11
k8s-master02   Ready    control-plane,master   219d   v1.21.0   192.168.31.202   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   docker://19.3.15
k8s-master03   Ready    control-plane,master   219d   v1.21.0   192.168.31.203   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   docker://19.3.15
k8s-node01     Ready    <none>                 219d   v1.21.0   192.168.31.204   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   docker://19.3.15
k8s-node02     Ready    <none>                 47h    v1.21.0   192.168.31.205   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   docker://19.3.15
k8s-node03     Ready    <none>                 40h    v1.22.4   192.168.31.10    <none>        CentOS Linux 8          4.18.0-348.2.1.el8_5.x86_64   docker://19.3.15
信息 备注
系统版本 CentOS 7.9
Docker版本 19.03.x
K8s版本 1.20.x
Pod网段 172.168.0.0/16
Service网段 10.96.0.0/12

基础知识:

calico网络原理、组网方式和使用 - 云+社区 - 腾讯云 (tencent.com)

1、flanel只支持网络通讯,但是不支持网络策略。

calico网络通讯和网络策略都支持。

——在 IP 地址或端口层面(OSI 第 3 层或第 4 层)控制网络流量,可以考虑为集群中特定应用使用 Kubernetes 网络策略(NetworkPolicy)。 NetworkPolicy 是一种以应用为中心的结构,允许你设置如何允许 Pod 与网络上的各类网络“实体” 。

网络策略通过网络插件 来实现。要使用网络策略,你必须使用支持 NetworkPolicy 的网络解决方案。 创建一个 NetworkPolicy 资源对象而没有控制器来使它生效的话,是没有任何作用的。

Calico on Kubernetes 从入门到精通_Kubernetes中文社区

Calico可以创建并管理一个3层平面网络,为每个工作负载分配一个完全可路由的IP地址。 工作负载可以在没有IP封装或网络地址转换的情况下进行通信,以实现裸机性能,简化故障排除和提供更好的互操作性。 在需要使用overlay网络的环境中,Calico提供了IP-in-IP隧道技术,或者也可以与flannel等其他overlay网络配合使用。

2、calico组网的核心原理就是IP路由,每个容器或者虚拟机会分配一个workload-endpoint(wl)。

calico的好处是endpoints组成的网络是单纯的三层网络,报文的流向完全通过路由规则控制,没有overlay等额外开销。

calico的endpoint可以漂移,并且实现了acl。

calico的每个node上会设置大量(海量)的iptables规则、路由,运维、排障难度大。)

calico的原理决定了它不可能支持VPC,容器只能从calico设置的网段中获取ip

名词解释

endpoint:  接入到calico网络中的网卡称为endpoint
AS:        网络自治系统,通过BGP协议与其它AS网络交换路由信息
ibgp:      AS内部的BGP Speaker,与同一个AS内部的ibgp、ebgp交换路由信息。
ebgp:      AS边界的BGP Speaker,与同一个AS内部的ibgp、其它AS的ebgp交换路由信息。
workloadEndpoint:  虚拟机、容器使用的endpoint
hostEndpoints:     物理机(node)的地址

3、nodeA怎样得知下一跳的地址?

答案是node之间通过BGP协议交换路由信息。

每个node上运行一个软路由软件bird,并且被设置成BGP Speaker,与其它node通过BGP协议交换路由信息。

可以简单理解为,每一个node都会向其它node通知这样的信息:

我是X.X.X.X,某个IP或者网段在我这里,它们的下一跳地址是我。 通过这种方式每个node知晓了每个workload-endpoint的下一跳地址。

[root@k8s-master03 ~]# find / -name bird.cfg
/var/lib/docker/overlay2/4035c130109250840989aaf87fb518aad812d5bed3f718a5164caa530d5c47c4/diff/etc/calico/confd/config/bird.cfg
/var/lib/docker/overlay2/4035c130109250840989aaf87fb518aad812d5bed3f718a5164caa530d5c47c4/merged/etc/calico/confd/config/bird.cfg
/var/lib/docker/overlay2/5fc0cd2787f3de4382ec9f9ec1e3de7b350cff441e68a652a0df93f3b4fbe285/diff/etc/calico/confd/config/bird.cfg

4、Calico的IPIP与BGP模式

  • IPIP是一种将各Node的路由之间做一个tunnel,再把两个网络连接起来的模式。启用IPIP模式时,Calico将在各Node上创建一个名为**”tunl0″的虚拟网络接口**。如下图所示。

  • BGP模式则直接使用物理机作为虚拟路由路(vRouter),不再创建额外的tunnel。

    [root@k8s-master01 ~]# ps -ef |grep felix
    root       7301   6460  0 Dec03 ?        00:00:00 runsv felix
    root       7313   7301  2 Dec03 ?        03:07:54 calico-node -felix
    root     100105 128511  0 10:41 pts/1    00:00:00 grep --color=auto felix
    

    img

  • img IPIP 是linux内核的驱动程序,可以对数据包进行隧道,上图可以看到两个不同的网络 vlan1 和 vlan2。基于现有的以太网将原始包中的原始IP进行一次封装,通过tunl0解包,这个tunl0类似于ipip模块,和Flannel vxlan的veth很类似。 Pod 1访问Pod 2大致流程如下:

  1. 数据包从容器1出到达Veth Pair另一端(宿主机上,以cali前缀开头);
  2. 进入IP隧道设备(tunl0),由Linux内核IPIP驱动封装在宿主机网络的IP包中(新的IP包目的地之是原IP包的下一跳地址,即192.168.31.63),这样,就成了Node1到Node2的数据包;
  3. 数据包经过路由器三层转发到Node2;
  4. Node2收到数据包后,网络协议栈会使用IPIP驱动进行解包,从中拿到原始IP包;
  5. 然后根据路由规则,根据路由规则将数据包转发给cali设备,从而到达容器2。

测试记录:

[root@k8s-master01 ~]# k get pod -owide
NAME                                READY   STATUS    RESTARTS   AGE   IP                NODE           NOMINATED NODE   READINESS GATES
busybox                             1/1     Running   19         19h   172.168.135.131   k8s-node03     <none>           <none>
nginx-deployment-8575f5d999-xblpd   1/1     Running   0          18h   172.168.195.12    k8s-master03   <none>           <none>

1、Pod1(busybox) 访问 Pod2(nginx) 流程

busybox位于k8s-node03(192.168.31.10)

[root@k8s-master01 ~]#  kubectl exec -ti busybox sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ifconfig -a
eth0      Link encap:Ethernet  HWaddr 46:F0:E9:07:67:11
          inet addr:172.168.135.131  Bcast:0.0.0.0  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1440  Metric:1
          RX packets:922 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1372 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:91481 (89.3 KiB)  TX bytes:131880 (128.7 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

tunl0     Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          NOARP  MTU:1480  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
/ # ip route
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
/ # ip neigh
169.254.1.1 dev eth0 lladdr ee:ee:ee:ee:ee:ee used 0/0/0 probes 1 STALE

从路由表可以知道 169.254.1.1 是容器的默认网关;通过 ip neigh 命令查看一下本地的 ARP 缓存:MAC 地址是 ee:ee:ee:ee:ee:ee,实际上 Calico 利用了网卡的代理 ARP 功能。代理 ARP 是 ARP 协议的一个变种,当 ARP 请求目标跨网段时,网关设备收到此 ARP 请求,会用自己的 MAC 地址返回给请求者,这便是代理 ARP(Proxy ARP)。 **- Calico 通过一个巧妙的方法将 workload 的所有流量引导到一个特殊的网关 169.254.1.1,从而引流到主机的 calixxx 网络设备上,最终将二三层流量全部转换成三层流量来转发。

  • 在主机上通过开启代理 ARP 功能来实现 ARP 应答,使得 ARP 广播被抑制在主机上,抑制了广播风暴,也不会有 ARP 表膨胀的问题。**
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1440 qdisc noqueue
    link/ether 46:f0:e9:07:67:11 brd ff:ff:ff:ff:ff:ff
    inet 172.168.135.131/32 scope global eth0
       valid_lft forever preferred_lft forever

eth0@if14: 为在宿主机上创建的虚拟网桥的一端,另一端为 cali12d4a061371

[root@k8s-node03 ~]# ifconfig -a
cali12d4a061371: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1440
        inet6 fe80::ecee:eeff:feee:eeee  prefixlen 64  scopeid 0x20<link>
        ether ee:ee:ee:ee:ee:ee  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@k8s-node03 ~]# route -n |grep 172.168.135.131
172.168.135.131 0.0.0.0         255.255.255.255 UH    0      0        0 cali12d4a061371

在busybox容器内

 # ping 192.168.31.203
PING 192.168.31.203 (192.168.31.203): 56 data bytes
64 bytes from 192.168.31.203: seq=0 ttl=63 time=0.416 ms

在k8s-master03查看:

[root@k8s-master03 ~]# tcpdump -i ens33 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
11:01:37.870635 IP 192.168.31.10 > 192.168.31.203: ICMP echo request, id 43952, seq 0, length 64

在busybox容器内ping位于k8s-master03上的容器nginx的IP

 # ping 172.168.195.12
PING 172.168.195.12 (172.168.195.12): 56 data bytes
64 bytes from 172.168.195.12: seq=0 ttl=62 time=0.510 ms

在k8s-master03查看:没有icmp记录

[root@k8s-master03 ~]# tcpdump -i ens33 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

说明使用IPIP模式,走的**”tunl0″的虚拟网络接口**:(ipip-proto-4)

隧道:192.168.31.10 > 192.168.31.203

封装的业务负载:172.168.135.131 > 172.168.195.12

[root@k8s-master03 ~]#  tcpdump -i ens33 -nn host 192.168.31.203 |grep 172.168.195.12
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
11:09:41.640089 IP 192.168.31.10 > 192.168.31.203: IP 172.168.135.131 > 172.168.195.12: ICMP echo request, id 17, seq 0, length 64 (ipip-proto-4)
11:09:41.640320 IP 192.168.31.203 > 192.168.31.10: IP 172.168.195.12 > 172.168.135.131: ICMP echo reply, id 17, seq 0, length 64 (ipip-proto-4)

k8s-master03上的容器nginx的IP:172.168.195.12,到calic10780a64b4;到172.168.135.128的走隧道tunl0

[root@k8s-master03 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.168.135.128 192.168.31.10   255.255.255.192 UG    0      0        0 tunl0
172.168.195.12  0.0.0.0         255.255.255.255 UH    0      0        0 calic10780a64b4

#Destination:目标路由; #Gateway:网关;如果是默认路由的网关则可称为默认网关;其中Gateway为0.0.0.0的路由条目为无需 网关之意,表示该目标路由为本地主机路由,又称直连路由。 #Genmask:子网掩码; #Flags:路由的标志位;U表示启用状态,G表示默认网关,H表示主机路由; #Metric:度量值;表示到达该目标路由的开销; #Iface:使用哪个接口将报文发送出去;

[root@k8s-master03 ~]# netstat -antp|grep bird
tcp        0      0 0.0.0.0:179             0.0.0.0:*               LISTEN      4982/bird
tcp        0      0 192.168.31.203:38277    192.168.31.10:179       ESTABLISHED 4982/bird
tcp        0      0 192.168.31.203:41001    192.168.31.201:179      ESTABLISHED 4982/bird
tcp        0      0 192.168.31.203:179      192.168.31.204:43835    ESTABLISHED 4982/bird
tcp        0      0 192.168.31.203:179      192.168.31.205:33053    ESTABLISHED 4982/bird
tcp        0      0 192.168.31.203:38307    192.168.31.202:179      ESTABLISHED 4982/bird

k8s-node03上的容器busybox的IP:172.168.135.131,到cali12d4a061371,到172.168.195网段的走隧道tunl0

[root@k8s-node03 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.168.135.131 0.0.0.0         255.255.255.255 UH    0      0        0 cali12d4a061371
172.168.195.0   192.168.31.203  255.255.255.192 UG    0      0        0 tunl0

https://cloud.tencent.com/developer/article/1482739 虚拟网桥cali12d4a061371:虚拟网卡,多个容器共用一个虚拟网卡进行通信; 以cali+命名的网卡收到的报文,这部分报文是本node上的endpoint发出的;(k8s中,容器的内发出的所有报文都会发送到对应的cali网卡上,通过在容器内添加静态arp,将容器网关的IP映射到cali网卡的MAC上实现) ——在calico中,IP被称为Endpoint,宿主机上的容器IP称为workloadEndpoint,物理机IP称为hostEndpoint。ipPool等一同被作为资源管理。 其他网卡接收的报文,这部分报文可能是其它node发送过来, 也可能是node上本地进程发出的。

[root@k8s-node03 ~]# netstat -antp|grep bird
tcp        0      0 0.0.0.0:179             0.0.0.0:*               LISTEN      120601/bird
tcp        0      0 192.168.31.10:179       192.168.31.204:50055    ESTABLISHED 120601/bird
tcp        0      0 192.168.31.10:179       192.168.31.205:55801    ESTABLISHED 120601/bird
tcp        0      0 192.168.31.10:179       192.168.31.201:53679    ESTABLISHED 120601/bird
tcp        0      0 192.168.31.10:179       192.168.31.202:43151    ESTABLISHED 120601/bird
tcp        0      0 192.168.31.10:179       192.168.31.203:38277    ESTABLISHED 120601/bird

Calico 管理工具

# wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v3.13.3/calicoctl
# chmod +x /usr/local/bin/calicoctl
查看集群节点状态
# calicoctl node status