本文基于 calico/node:v3.11.1
Calico的组网模型可以参考:手动完全模拟calico网络(IP隧道 + BIRD)
calico/node容器在k8s的每个节点都部署,提供calico的基础服务
项目的源代码:https://github.com/projectcalico/node
1. calico/node容器中的运行分析
通过Dockerfile.amd64分析
-
镜像基于debian:10-slim基础镜像
-
从calico/bpftool:v5.0-amd64和BIRD_IMAGE=calico/bird:latest镜像拷贝bpftool和bird
-
从filesystem/文件夹拷贝/etc、/sbin等配置,其中包含了/etc/rc.local、/sbin/start_runit等重要文件
-
容器的启动脚本为/sbin/start_runit。它会调用debian的runsvdir命令来启动/etc/service/enabled目录下的所有服务
-
/etc/service/enabled下的服务是根据部署calico容器的运行环境动态生成的,从/etc/service/available文件夹拷贝需要的
bird
、bird6
、calico-bgp-daemon
、cni
、confd
、felix
、libnetwork
等服务 -
其中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
- 从/etc/rc.local文件中可以看到容器有几个关键的环境变量:
CALICO_NETWORKING_BACKEND
、CALICO_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 -felix
、calico-node -confd
、bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
、bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg
结合calico的架构图分析
- bird作为BGP Client,主要负责
路由信息分发
,当Felix将路由插入Linux内核FIB时,BGP客户端将接收它们并将它们分发到集群中的其他工作节点 - felix作为Calico的核心agent,运行在每台workload节点,主要负责配置路由及ACLs等信息,确保endpoint的连通状态
- k8s中的calico的存储配为
"datastore_type": "kubernetes"
,因此就没有etcd组件 - 架构图中少了confd组件,confd负责读取配置,并将配置写入bird,比如/etc/calico/confd/config/文件中的
bird.cfg
、bird_aggr.cfg
、bird_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