CNI 网络流量分析(六)Calico 介绍与原理(一)
文章目录
- CNI 网络流量分析(六)Calico 介绍与原理(一)
- 介绍
- 安装
- Calico-node
- 初始化
- Calico-node 服务
- Felix
- confd
- allocate-tunnel-addrs
- monitor-addresses
- monitor-token
- status-reporter
- bird
- calico-kube-controllers
CNI 网络流量分析(六)Calico 介绍与原理(一)
介绍
Calico是一套开源的网络和网络安全解决方案,用于容器、虚拟机、宿主机之前的网络连接,它是一个纯三层的虚拟化网络解决方案,它把每个节点都作为一个虚拟路由器,并把每个节点上的Pod当作是节点路由器后的一个终端设备并为其分配一个IP地址。各节点路由器通过BGP协议生成路由规则,从而实现不通节点上Pod间的通信。
与Flannel相比,Calico的一个显著优势是对网络策略的支持,它允许用户定义访问控制规则以管控进出Pod的数据报文,从而为Pod间的通信施加安全策略。
BGP是一个去中心化自治路由协议,它通过维护IP路由表或“前缀”来实现自治系统之间的可达性,通常作为大规模数据中心维护不同自治系统之间路由信息的矢量路由协议。Linux内核原生支持BGP,因此可以把一台Linux主机配置为边界网关。
Calico把每个节点上Pod组成的网络视为一个自治系统(AS),而每个节点就相当于自治系统的边界网关。各节点之间通过BGP协议交换路由信息并生成路由规则。但并非所有的网络环境都能支持BGP,而且BGP路由模型要求所有节点位于同一个二层网络中,所以Calico还支持基于IPIP和VXLAN的Overlay网络模型。
另外,类似于Flannel的 VXALN后端启用Directrouting时的网络模型,Calico也支持混合使用路由和Overlay网络模型,BGP路由模型用于二层网络的高性能通信,IPIP或VXLAN用于跨二层网络节点间Pod报文的转发
Calico可以将关键配置抽象为资源类型,并允许用户按需自定义资源对象已完成系统配置。
如 pod 对应 WorkloadEndpoint,同名的 node,networkpolicy 等,都有 calico 独特的结构
apiVersion: projectcalico.org/v3
items:
- apiVersion: projectcalico.org/v3kind: WorkloadEndpointmetadata:creationTimestamp: "2023-02-06T13:03:01Z"labels:projectcalico.org/namespace: defaultprojectcalico.org/orchestrator: k8sprojectcalico.org/serviceaccount: defaultname: node111-k8s-pod1-eth0namespace: defaultresourceVersion: "4288996"uid: 2fb01a9c-2796-4ef5-aea1-a3deb12c64fespec:containerID: 96999978a9691f840410abadc6751f8a99bf1840df882242dcb59554c922b2c0endpoint: eth0interfaceName: calice0906292e2ipNetworks:- 10.244.153.204/32node: node111orchestrator: k8spod: pod1ports:- hostIP: ""hostPort: 0name: nginx-portport: 80protocol: TCPprofiles:- kns.default- ksa.default.defaultserviceAccountName: default
安装
获取 yaml
wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml
修改并 apply,默认是 ipip 类型
使用 bgp
- name: CALICO_IPV4POOL_IPIP
value: Always
- name: CALICO_AUTODETECTION_METHOD
value: interface=eth0
安装完成后,cni 配置如下
/etc/cni/net.d/10-calico.conflist
{"name": "k8s-pod-network","cniVersion": "0.3.1","plugins": [{"type": "calico","log_level": "info","log_file_path": "/var/log/calico/cni/cni.log","datastore_type": "kubernetes","nodename": "node111","mtu": 0,"ipam": {"type": "calico-ipam"},"policy": {"type": "k8s"},"kubernetes": {"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"}},{"type": "portmap","snat": true,"capabilities": {"portMappings": true}},{"type": "bandwidth","capabilities": {"bandwidth": true}}]
}
部署共有一个 deployment calico-kube-controller,一个 ds calico-node。
Calico-node
Calico-node 作为 cni 以 ds 形式部署在每一个节点
初始化
根据 pod 的 initContainers:
- calico-ipam -upgrade
-upgrade 如果为 true 将在节点上迁移 host-local 到 calico-ipam;获取 k8s 权限
- 获取 node 信息,使用 host-local 分配的子网
- 获取 隧道 ip 并 通过 IPAM().AssignIP 进行分配
tunIp := ip.To4()tunIp[3]++ // 最后一位加 1,即 10.244.0.1 对于 10.244.0.0/16
- 从 host-local 本地存储的 pod IP 信息,再获取 pod 列表进行分析并 通过 IPAM().AssignIP 进行分配
- 清空 host-local 本地存储
- /opt/cni/bin/install
- 通过 env 获取配置
CNIConfName: 10-calico.conflist
CNINetworkConfig: cni 配置内容
SLEEP:False
UpdateCNIBinaries:True
- 利用 k8s 配置文件生成 k8s client
- 拷贝镜像中 二进制到 /opt/cni/bin/
- 将 k8s 认证信息存在 /etc/cni/net.d/calico-kubeconfig
- 生成 cni 配置在 /etc/cni/net.d/10-calico.conflist
- 不停循环检查 etcd 认证是否更新,更新了存在 /etc/cni/net.d/calico-tls/
- calico-node -init -best-effort
配置节点内容,参数很多,根据不同参数对 node 做配置
如默认的 -init -best-effort:确保 bpf 文件和 cgroupv2 系统挂载(cat /proc/mounts |grep bpf)
如有 从 /etc/calico/felix.cfg 配置运行 felix 等等
Calico-node 服务
Liveness 和 readiness 通过 /bin/calico-node -felix-live -bird-live 进行检查
关闭时 /bin/calico-node -shutdown
启动时运行 start_runit 脚本
#!/bin/sh
# From https://github.com/faisyl/alpine-runit
env > /etc/envvars/etc/rc.local
retval=$?
if [ $retval -ne 0 ];
thenecho >&2 "Calico node failed to start"exit $retval
fi# Export the nodename set by the startup procedure.
export NODENAME=$(cat /var/lib/calico/nodename)RUNSVDIR=$(/usr/bin/which runsvdir) // /usr/local/bin/runsvdir
exec ${RUNSVDIR} -P /etc/service/enabled
runit 当服务器启动时启动定义好的服务,监控运行的服务,当服务中断时,将服务拉起;
如 runsvdir -P /etc/service/enabled 即 pod 启动后运行和监控 /etc/service/enabled 服务。
/etc/service/enabled 路径下有以下文件夹,即有以下服务
allocate-tunnel-addrs bird6 confd monitor-addresses
bird cni felix node-status-reporter
比如其中 allocate-tunnel-addrs 目录下有 run 脚本
#!/bin/sh
exec 2>&1
exec calico-node -allocate-tunnel-addrs
实际运行 calico-node -allocate-tunnel-addrs
查看进程,8 个进程
root 2235412 1.1 0.7 2042928 62252 ? Sl Feb06 22:55 calico-node -felix
root 2235413 0.0 0.6 1673500 53488 ? Sl Feb06 0:12 calico-node -allocate-tunnel-addrs
root 2235414 0.0 0.6 1673244 50064 ? Sl Feb06 0:12 calico-node -status-reporter
root 2235415 0.0 0.6 1673756 51672 ? Sl Feb06 0:13 calico-node -monitor-addresses
root 2235416 0.0 0.6 1821220 52772 ? Sl Feb06 0:13 calico-node -confd
root 2235417 0.0 0.5 1673500 48024 ? Sl Feb06 0:08 calico-node -monitor-token
root 2235714 0.0 0.0 1896 1452 ? S Feb06 0:27 bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
root 2235715 0.0 0.0 1908 1456 ? S Feb06 0:23 bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg
主要看这些服务
Felix
Felix是一个守护程序,在每个 endpoints 的节点上运行。Felix 负责编制路由和 ACL 规则等,以便为该主机上的 endpoints 资源正常运行提供所需的网络连接
主要实现一下工作
- 管理网络接口,Felix 将有关接口的一些信息写到内核,以使内核能够正确处理该 endpoint 发出的流量。 特别是,它将确保主机正确响应来自每个工作负载的ARP请求,并将为其管理的接口启用IP转发支持。它还监视网络接口的出现和消失,以便确保针对这些接口的编程得到了正确的应用。
- 编写路由,Felix负责将到其主机上endpoints的路由编写到Linux内核FIB(转发信息库)中。 这可以确保那些发往目标主机的endpoints的数据包被正确地转发。
- 编写 ACLs,Felix还负责将ACLs编程到Linux内核中。 这些ACLs用于确保只能在endpoints之间发送有效的网络流量,并确保endpoints无法绕过Calico的安全措施。
- 报告状态,Felix 负责提供有关网络健康状况的数据。 特别是,它将报告配置其主机时发生的错误和问题。 该数据会被写入etcd,以使其对网络中的其他组件和操作才可见
- Felix 启动配置 /etc/calico/felix.cfg
[global]
MetadataAddr = None
LogFilePath = None
LogSeverityFile = None
LogSeveritySys = None
- 从 env 加载配置比较重要的有
DatastoreType: Kubernetes
-
开启 http 服务,上报健康状态供 liveness and readiness 查询 /bin/calico-node -felix-live
-
解析 IP Pool 资源,集群启动时创建了 IPPool 资源
kubectl get IPPool -oyaml
apiVersion: v1
items:
- apiVersion: crd.projectcalico.org/v1kind: IPPoolmetadata:name: default-ipv4-ippool...spec:allowedUses:- Workload- TunnelblockSize: 26cidr: 10.244.0.0/16ipipMode: Always // ipipMode, 且 ippool 10.244.0.0/16natOutgoing: truenodeSelector: all()vxlanMode: Never
kind: List
metadata:resourceVersion: ""selfLink: ""
-
如果配置了 calico-typha,则启动相应 client,在节点数比较多的情况下,Felix 可通过 Typha 直接和 ETCD 进行数据交互
-
Dataplane
dpDriver, dpDriverCmd = dp.StartDataplaneDriver(configParams.Copy(), // Copy to avoid concurrent access.healthAggregator,configChangedRestartCallback,fatalErrorCallback,k8sClientSet)
- 通过 kube-ipvs0 判断是否是 ipvs,如果 BPF 开启的话,ipvs 改为 false。
- 如果 BPF 开启的话,确认 BPF 程序 mark bits 在允许范围内 IptablesMarkMask:0xffff0000
- 获取到可用 mark 范围 iptables mark bits acceptMark=0x10000 endpointMark=0xfff00000 endpointMarkNonCali=0x100000 passMark=0x20000 scratch0Mark=0x40000 scratch1Mark=0x80000
即:ACCEPT 标记 0x10000,endpoint 标记为 0xfff00000 等 - 循环保证 IPtables 的配置
intDP := intdataplane.NewIntDataplaneDriver(dpConfig)intDP.Start()
具体配置分析可见 https://blog.csdn.net/zhonglinzhang/article/details/97630093
confd
主要任务:监控 Calico 数据存储以了解 BGP 配置和全局默认值(例如 AS 编号、日志记录级别和 IPAM 信息)的更改。开源、轻量级的配置管理工具。
Confd 根据数据存储中数据的更新动态生成 BIRD 配置文件。当配置文件发生变化时,confd 会触发 BIRD 加载新文件。
监控文件目录,该文件目录下,其中 template 提供 配置 bird 的模板,conf.d 生成配置文件的 toml,config 是生成实际的 配置
conf.d config templates
然后进程 bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg 去更新 bird。
allocate-tunnel-addrs
- 保证隧道 ip 正确,ipip wireguard 或 vxlan;
func reconcileTunnelAddrs
- 通过 calicoclient 获取 ippool 和 node 信息
blockSize: 26 // 每个网段的 ip 数量cidr: 10.244.0.0/16 // ippoolipipMode: Always // ipip 模式natOutgoing: truenodeSelector: all() // 所有节点都用该 ippool
- 通过 cidr + blockSize,切分 ippool,并为该节点分配一个 ip 段,并请求一个 ip 作为隧道 ip
- 将获取的 ip 地址更新到 node 上
spec:addresses:- address: 192.168.100.111/24type: CalicoNodeIP- address: 172.18.22.111type: InternalIPbgp:ipv4Address: 192.168.100.111/24ipv4IPIPTunnelAddr: 10.244.153.192 // 拿到的是 10.244.153.192/26 网段orchRefs:- nodeName: node111orchestrator: k8s
status:podCIDRs:- 10.244.0.0/24
- 一直跑 syncer 监听 node 变化和 ippool 变化。
monitor-addresses
一直检查业务网卡的 ip 是否变化,检查默认频率 1min,如果变化,就对应更新 node 信息
addresses:- address: 192.168.100.111/24type: CalicoNodeIP- address: 172.18.22.111type: InternalIPbgp:ipv4Address: 192.168.100.111/24ipv4IPIPTunnelAddr: 10.244.153.192
monitor-token
间隔随机时间刷新 sa token
tokenRequest, err := t.clientset.CoreV1().ServiceAccounts(t.namespace).CreateToken(context.TODO(), t.serviceAccountName, tr, metav1.CreateOptions{})
status-reporter
循环上报状态
bird
BIRD:BGP协议客户端,负责将Felix生成的路由信息载入内核并通告到整个网络中
BGP路由反射器:Calico的BGP路由模型默认采用节点网格模式(node-to-node mesh),随着节点数量的增加,节点之间的连接数量会快速增长,给集群网络带来较大的压力。因此,一般建议大规模集群使用BGP路由反射器模式进行路由学习,BGP的点到点通信也就转换为与中心节点的单路通信模型。另外,处于冗余考虑,生产环境应该配置多个BGP路由反射器。对于Calico来说,BGP客户端程序除了作为客户端使用,也可以配置为路由反射器。
calico-kube-controllers
负责把k8s的各种变化更新到calico网络中
- 初始化 controller ,分别创建 podController,namespaceController,policyController,nodeController,serviceAccountController 和对应的 informer。
controllerCtrl.InitControllers(ctx, runCfg, k8sClientset, calicoClient)podController := pod.NewPodController(ctx, k8sClientset, calicoClient, *cfg.Controllers.WorkloadEndpoint, podInformer)namespaceController := namespace.NewNamespaceController(ctx, k8sClientset, calicoClient, *cfg.Controllers.Namespace)policyController := networkpolicy.NewPolicyController(ctx, k8sClientset, calicoClient, *cfg.Controllers.Policy)nodeController := node.NewNodeController(ctx, k8sClientset, calicoClient, *cfg.Controllers.Node, nodeInformer, podInformer)serviceAccountController := serviceaccount.NewServiceAccountController(ctx, k8sClientset, calicoClient, *cfg.Controllers.ServiceAccount)
- 初始化监控
- 启动,启动后 watch 上面资源的变化
- Pod 资源变化时,将 pod 转为 workloadendpoint 存储
- 监听 namespace,创建对应的 profile
- nodeController 也监听 pod 变化
- 监听 serviceAccount,创建对应的 profile
- 监听 networkpolicy,转为 calico NetworkPolicy 存储