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/v3
kind: WorkloadEndpoint
metadata:
creationTimestamp: "2023-02-06T13:03:01Z"
labels:
projectcalico.org/namespace: default
projectcalico.org/orchestrator: k8s
projectcalico.org/serviceaccount: default
name: node111-k8s-pod1-eth0
namespace: default
resourceVersion: "4288996"
uid: 2fb01a9c-2796-4ef5-aea1-a3deb12c64fe
spec:
containerID: 96999978a9691f840410abadc6751f8a99bf1840df882242dcb59554c922b2c0
endpoint: eth0
interfaceName: calice0906292e2
ipNetworks:
- 10.244.153.204/32
node: node111
orchestrator: k8s
pod: pod1
ports:
- hostIP: ""
hostPort: 0
name: nginx-port
port: 80
protocol: TCP
profiles:
- kns.default
- ksa.default.default
serviceAccountName: default
获取 yaml
wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml
修改并 apply,默认是 ipip 类型,可以通过 CALICO_AUTODETECTION_METHOD 选择网卡
如 指定网卡:value: “interface=ens10”;跳过网卡:value: “skip-interface=ens3”;通过连通性 value: “can-reach=192.168.100.1”
- 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 作为 cni 以 ds 形式部署在每一个节点
根据 pod 的 initContainers:
tunIp := ip.To4()
tunIp[3]++ // 最后一位加 1,即 10.244.0.1 对于 10.244.0.0/16
CNIConfName: 10-calico.conflist
CNINetworkConfig: cni 配置内容
SLEEP:False
UpdateCNIBinaries:True
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 ];
then
echo >&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 内容多且重要,单独文章
主要任务:监控 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。
func reconcileTunnelAddrs
blockSize: 26 // 每个网段的 ip 数量
cidr: 10.244.0.0/16 // ippool
ipipMode: Always // ipip 模式
natOutgoing: true
nodeSelector: all() // 所有节点都用该 ippool
spec:
addresses:
- address: 192.168.100.111/24
type: CalicoNodeIP
- address: 172.18.22.111
type: InternalIP
bgp:
ipv4Address: 192.168.100.111/24
ipv4IPIPTunnelAddr: 10.244.153.192 // 拿到的是 10.244.153.192/26 网段
orchRefs:
- nodeName: node111
orchestrator: k8s
status:
podCIDRs:
- 10.244.0.0/24
一直检查业务网卡的 ip 是否变化,检查默认频率 1min,如果变化,就对应更新 node 信息
addresses:
- address: 192.168.100.111/24
type: CalicoNodeIP
- address: 172.18.22.111
type: InternalIP
bgp:
ipv4Address: 192.168.100.111/24
ipv4IPIPTunnelAddr: 10.244.153.192
间隔随机时间刷新 sa token
tokenRequest, err := t.clientset.CoreV1().ServiceAccounts(t.namespace).CreateToken(context.TODO(), t.serviceAccountName, tr, metav1.CreateOptions{})
循环上报状态
BIRD:BGP协议客户端,负责将Felix生成的路由信息载入内核并通告到整个网络中
BGP路由反射器:Calico的BGP路由模型默认采用节点网格模式(node-to-node mesh),随着节点数量的增加,节点之间的连接数量会快速增长,给集群网络带来较大的压力。因此,一般建议大规模集群使用BGP路由反射器模式进行路由学习,BGP的点到点通信也就转换为与中心节点的单路通信模型。另外,处于冗余考虑,生产环境应该配置多个BGP路由反射器。对于Calico来说,BGP客户端程序除了作为客户端使用,也可以配置为路由反射器。
负责把k8s的各种变化更新到calico网络中
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)