CNI 网络分析 4.1 Calico 介绍与原理(一)

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/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

Calico-node 作为 cni 以 ds 形式部署在每一个节点

初始化

根据 pod 的 initContainers:

  1. 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 本地存储
  1. /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/
  1. 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 ];
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

Felix 内容多且重要,单独文章

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    // ippool
    ipipMode: Always       // ipip 模式
    natOutgoing: true
    nodeSelector: all()    // 所有节点都用该 ippool
  • 通过 cidr + blockSize,切分 ippool,并为该节点分配一个 ip 段,并请求一个 ip 作为隧道 ip
  • 将获取的 ip 地址更新到 node 上
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
  • 一直跑 syncer 监听 node 变化和 ippool 变化。
monitor-addresses

一直检查业务网卡的 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
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 存储
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
multus-cni 是一个 Kubernetes 的多网络 CNI 插件,它是 Kubernetes 上负责多网络管理的代表性插件之一。它允许 Kubernetes 集群中的每个 Pod 拥有多个网络接口,并能针对每个网络接口对应的网络策略和路由进行不同的配置。 multus-cni源码主要分为三部分:CNI 插件相关代码、配置文件相关代码和网络资源相关代码。CNI 插件相关代码包括主程序 main.go、CNI 配置解析器 conf.go、IPAM 相关代码和网络审计相关代码。配置文件相关代码包括 multus.conf 和各种 JSON/YAML 配置文件的解析器。网络资源相关代码主要负责通过 Kubernetes API 获取和管理 Pod、NetworkAttachmentDefinition 和 Service 等网络资源信息。 multus-cni 的核心是 CNI 插件相关代码中的 main.go,它主要负责 CNI 插件的初始化和执行。CNI 插件的执行流程大概可以总结为如下三步:首先,multus-cni 解析 CNI 配置文件并获取 Pod 相关的网络资源信息;接着,multus-cni 调用下层 CNI 插件(比如 flannel、calico、ovs 等)完成网络接口的创建和配置;最后,multus-cni 继续执行其他 CNI 插件(比如 ipvlan、macvlan、bridge 等)完成其他网络接口的创建和配置。 此外,multus-cni 通过 Kubernetes API 获取和管理 NetworkAttachmentDefinition 和 Service 等网络资源信息。在 Kubernetes 中,NetworkAttachmentDefinition 用于定义和配置网络接口,而 Service 用于定义和管理 Kubernetes 集群中的服务。multus-cni 通过获取、解析和应用这些网络资源信息,实现了多网络的管理和配置。 总的来说,multus-cni 是一个非常优秀的多网络 CNI 插件,它利用 Kubernetes API 实现了多网络的管理和配置,并同时支持插件化扩展。它的源码比较清晰,适合对 Kubernetes 网络原理比较熟悉的开发者学习和探究。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值