★★★K8S中的Calico网络分析(一)—— 进程、文件结构、路由、网络、配置

olivee 4年前 ⋅ 1646 阅读

本文基于 calico/node:v3.11.1

Calico的组网模型可以参考:手动完全模拟calico网络(IP隧道 + BIRD)

calico/node容器在k8s的每个节点都部署,提供calico的基础服务

项目的源代码:https://github.com/projectcalico/node

1. calico/node容器中的运行分析

通过Dockerfile.amd64分析

  1. 镜像基于debian:10-slim基础镜像

  2. 从calico/bpftool:v5.0-amd64和BIRD_IMAGE=calico/bird:latest镜像拷贝bpftool和bird

  3. 从filesystem/文件夹拷贝/etc、/sbin等配置,其中包含了/etc/rc.local、/sbin/start_runit等重要文件

  4. 容器的启动脚本为/sbin/start_runit。它会调用debian的runsvdir命令来启动/etc/service/enabled目录下的所有服务

  5. /etc/service/enabled下的服务是根据部署calico容器的运行环境动态生成的,从/etc/service/available文件夹拷贝需要的birdbird6calico-bgp-daemoncniconfdfelixlibnetwork等服务

  6. 其中bird服务的配置/etc/service/enabled/bird/run如下:

#!/bin/sh
exec 2>&1
exec bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
  1. 从/etc/rc.local文件中可以看到容器有几个关键的环境变量:CALICO_NETWORKING_BACKENDCALICO_DISABLE_FILE_LOGGING
  • 7.1 CALICO_NETWORKING_BACKEND: 有none、vxlan、gobgp、bird等模式,默认为'bird'模式
  • 7.2 CALICO_DISABLE_FILE_LOGGING: 表示禁用日志,默认安装的calico禁用了日志,如果要打开日志,要清除CALICO_DISABLE_FILE_LOGGING环境变量(或设置为false)

2. 进入到服务中运行的calico/node容器内部分析

查看容器中的进程:

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 Jul28 ?        00:00:05 /usr/bin/runsvdir -P /etc/service/enabled
root        50     1  0 Jul28 ?        00:00:00 runsv felix
root        51     1  0 Jul28 ?        00:00:00 runsv bird
root        52     1  0 Jul28 ?        00:00:00 runsv bird6
root        53     1  0 Jul28 ?        00:00:00 runsv confd
root        54    50  1 Jul28 ?        02:10:41 calico-node -felix
root        55    53  0 Jul28 ?        00:01:33 calico-node -confd
root       134    51  0 Jul28 ?        00:02:52 bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
root       135    52  0 Jul28 ?        00:02:53 bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg
root      6906 14516  0 07:30 pts/1    00:00:00 ps -ef
root      9069     0  0 02:41 pts/0    00:00:00 sh
root     14516     0  0 05:36 pts/1    00:00:00 sh

可以看到容器中运行的四个主要进程calico-node -felixcalico-node -confdbird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfgbird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg

calico.png 结合calico的架构图分析

  1. bird作为BGP Client,主要负责路由信息分发,当Felix将路由插入Linux内核FIB时,BGP客户端将接收它们并将它们分发到集群中的其他工作节点
  2. felix作为Calico的核心agent,运行在每台workload节点,主要负责配置路由及ACLs等信息,确保endpoint的连通状态
  3. k8s中的calico的存储配为"datastore_type": "kubernetes",因此就没有etcd组件
  4. 架构图中少了confd组件,confd负责读取配置,并将配置写入bird,比如/etc/calico/confd/config/文件中的bird.cfgbird_aggr.cfgbird_ipam.cfg文件都是confd组件写进去的

2.1 calico中的bird

bird官方各协议配置主要参考:https://bird.network.cz/?get_doc&v=20&f=bird-6.html

其中krt_tunnel是calico修改bird后的源码projectcalico\bird中加入的参数,所以要如果是bird官方文档中没有的配置,就要到calico的官网去查资料(或者尝试看看calico修改bird后的源码,C语言写的)

calico修改过的bird官网地址:https://github.com/projectcalico/bird/tree/v0.3.3

3. 通过运行中的Pod分析Calico生成的网络(IPIP模式)

比如我这里创建一个busybox的容器

kubectl run busybox --image=busybox --generator=run-pod/v1 --command -- sleep 36000

再进入到容器:

kubectl exec -ti  busybox sh

查看容器内部的路由表(这个路由表是calico给容器生成的一个特定的路由表,路由包的默认网关为一个特定的IP地址169.254.1.1):

# kubectl exec -ti  busybox ip route
default via 169.254.1.1 dev eth0 
169.254.1.1 dev eth0 scope link

查看容器内部的ARP表(169.254.1.1的MAC地址是Calico利用PROXY_ARP技术返回的一个固定的Mac地址ee:ee:ee:ee:ee:ee):

# kubectl exec -ti  busybox ip nei
169.254.1.1 dev eth0 lladdr ee:ee:ee:ee:ee:ee ref 1 used 0/0/0 probes 4 REACHABLE

查看容器的IP地址(这里发现与容器内eth0网卡配对的网卡编号为if12):

# kubectl exec -ti  busybox ip address
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@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1440 qdisc noqueue 
    link/ether 0e:bd:22:8e:18:5e brd ff:ff:ff:ff:ff:ff
    inet 10.244.218.94/32 scope global eth0
       valid_lft forever preferred_lft forever

再到容器所在主机中查看对应的配对虚拟网卡if12的信息(发现cali12d4a061371网卡的Mac地址为ee:ee:ee:ee:ee:ee,同时cali12d4a061371@if4说明这块网卡的配对网卡编号为4,也与容器内部显示的网卡编号一致):

# ip address show cali12d4a061371
12: cali12d4a061371@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default 
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 7
    inet6 fe80::ecee:eeff:feee:eeee/64 scope link 
       valid_lft forever preferred_lft forever

同时查看cali12d4a061371网卡的Proxy_ARP配置(看到proxy_arp的值为1,说明cali12d4a061371网卡开启的代理ARP功能):

# cat /proc/sys/net/ipv4/conf/cali12d4a061371/proxy_arp
1

查看主机的路由,发现Calico在主机中生成了两个路由(这两个路由表示10.244.163.128/26和10.244.253.192/26的路由网关分别为192.168.19.162和192.168.19.160,路由设备网口为tunl0,协议为bird):

10.244.163.128/26 via 192.168.19.162 dev tunl0 proto bird onlink
10.244.253.192/26 via 192.168.19.160 dev tunl0 proto bird onlink

再看看tunl0设备的信息(看到tunl0的IP地址是一个单点局域网地址10.244.218.64/32,它的IPIP配为0.0.0.0 brd 0.0.0.0,表示它可以通过隧道技术发送本地任意来源的IP到其它主机的任意IP):

# ip -d address  show tunl0
11: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1440 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0 promiscuity 0 
    ipip remote any local any ttl inherit nopmtudisc numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    inet 10.244.218.64/32 brd 10.244.218.64 scope global tunl0
       valid_lft forever preferred_lft forever