Calico替换为Cilium 有两个做法,一种鲁莽版,一种思路清晰版。
今天这遍文章是官方最佳实践版本。
一、思路
迁移CNI插件的3种办法:
1、创建一个新的集群,通过Gitops的方式迁移负载,然而,这可能涉及大量的准备工作和潜在的中断。
2、另一种方法是重新配置/etc/cni/net.d/指向Cilium。但是,现有的pod仍将由旧的网络插件配置,而新的pod将由较新的CNI插件配置。为了完成迁移,必须回收集群上由旧CNI配置的所有pod,以便由新的CNI插件管理。3、直接强行进行替换,然后逐个重启。问题就是会业务中断而且在节点在迁移的过程中会形成两个孤岛。
在常见迁移CNI插件时,有几种可行的方法,各有优缺点。
而Cililum官方指导手册中提供了一种不中断业务的方式:
Cilium CRD:CiliumNodeConfig
可以逐个节点地迁移正在运行的集群,而不会中断现有的流量,也不需要完全中断集群或重建集群。
ciilium支持混合模式,即跨集群建立两个独立的覆盖。虽然给定节点上的Pods只能连接到一个网络,但在迁移过程中,它们可以访问纤毛和非纤毛Pods。只要ciilium和现有的网络提供商使用单独的IP范围,Linux路由表就会负责分离流量。
在本实验室中,我们将使用一个模型在两个已部署的CNI实现之间进行实时迁移。这将有利于减少节点和工作负载的停机时间,并确保两个已配置的CNIs上的工作负载在迁移期间能够通信。
为了实时迁移工作,ciilium将安装一个独立的CIDR范围和封装端口,而不是当前安装的CNI。只要ciilium和现有的CNI使用单独的IP范围,Linux路由表就会负责分离流量。实时迁移需要满足以下要求:
1、一个现有的CNI插件,它使用Linux路由栈,如Flannel、Calico或AWS-CNI
2、一个Cilium-CIDR不同于之前的CNI插件
3、与之前的CNI插件不同的Cilium覆盖层,可以通过更改协议或端口实现
4、使用Cilium集群池IPAM模式
迁移过程利用每节点配置特性选择性地启用ciilium CNI。这允许在不中断现有工作负载的情况下进行受控的ciilium部署。
首先,Cilium将被安装在一种模式中,在这种模式中,它将建立一个覆盖层,但不为任何pod提供CNI网络。然后,单个节点将被迁移。
总之,整个过程如下所示:
1、准备集群并以“次要”模式安装Cilium。
2、封锁、清除、迁移并重启每个节点
3、删除现有的网络提供程序
4、(可选)重新启动各节点
二、迁移过程
一、集群信息
root@server:~# yq cluster.yaml
---
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
# nodepinger
- containerPort: 32042
hostPort: 32042
# goldpinger
- containerPort: 32043
hostPort: 32043
- role: worker
- role: worker
- role: worker
- role: worker
networking:
disableDefaultCNI: true
podSubnet: 192.168.0.0/16
1、检查节点状态。
root@server:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 3m48s v1.29.2
kind-worker Ready <none> 3m27s v1.29.2
kind-worker2 Ready <none> 3m25s v1.29.2
kind-worker3 Ready <none> 3m24s v1.29.2
kind-worker4 Ready <none> 3m24s v1.29.2
2、 检查现有网络插件calico的状态。
root@server:~# kubectl -n calico-system rollout status ds/calico-node
daemon set "calico-node" successfully rolled out
3、检查并确认每个节点的CIDR.
root@server:~# kubectl get ipamblocks.crd.projectcalico.org \
-o jsonpath="{range .items[*]}{'podNetwork: '}{.spec.cidr}{'\t NodeIP: '}{.spec.affinity}{'\n'}{end}"
podNetwork: 192.168.110.128/26 NodeIP: host:kind-worker2
podNetwork: 192.168.162.128/26 NodeIP: host:kind-worker
podNetwork: 192.168.195.192/26 NodeIP: host:kind-worker3
podNetwork: 192.168.218.192/26 NodeIP: host:kind-worker4
podNetwork: 192.168.82.0/26 NodeIP: host:kind-control-plane
二、节点网络监控
1、部署节点监控
软件名称:Goldpinger
下面的yaml会部署对应的Pod,因为亲和性部署在不同的节点上,当作我们测试联通性的探针。
保存为:goldpinger_deploy.yaml
root@server:~# cat /tmp/goldpinger_deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: goldpinger
namespace: default
spec:
selector:
matchLabels:
app: goldpinger
replicas: 10
template:
metadata:
labels:
app: goldpinger
spec:
containers:
- env:
- name: HOSTNAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: HOST
value: 0.0.0.0
- name: PORT
value: "8080"
- name: LABEL_SELECTOR
value: app=goldpinger
image: bloomberg/goldpinger:v3.7.0
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /
port: http
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: goldpinger-daemon
ports:
- containerPort: 8080
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /
port: http
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /config
name: zap
serviceAccount: nodepinger-goldpinger
serviceAccountName: nodepinger-goldpinger
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Exists
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
operator: Exists
volumes:
- configMap:
defaultMode: 420
name: nodepinger-goldpinger-zap
name: zap
保存为:goldpinger_cmp.yaml
root@server:~# kubectl get cm/nodepinger-goldpinger-zap -o yaml
apiVersion: v1
data:
zap.json: |
{
"level": "info",
"encoding": "json",
"outputPaths": [
"stdout"
],
"errorOutputPaths": [
"stderr"
],
"initialFields": {
},
"encoderConfig": {
"messageKey": "message",
"levelKey": "level",
"levelEncoder": "lowercase",
"timeKey": "ts",
"timeEncoder": "ISO8601",
"callerKey": "caller",
"callerEncoder": "Short"
}
}
2、 部署Pop和配套的cm并且暴露服务和端口。
kubectl apply -f goldpinger_deploy.yaml
kubectl apply -f goldpinger_cmp.yaml
kubectl expose deployment goldpinger --type NodePort \
--overrides '{"spec":{"ports": [{"port":80,"protocol":"TCP","targetPort":8080,"nodePort":32043}]}}'
root@server:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9m43s
nodepinger-goldpinger NodePort 10.96.142.57 <none> 80:32042/TCP 9m14s
3、检查部署状态
kubectl rollout status deployment goldpinger kubectl get po -l app=goldpinger -o wide
每个节点都会部署一个。是一个deployment资源类型。他提供一个web ui 与url地址,可视化查看节点的网络通信状态。注意是节点部署-他们能通则代表节点上的网络是ok的,节点网络可通,那么业务pod的网络也不会断。
curl -s http://localhost:32042/check | jq
curl -s http://localhost:32042/metrics | grep '^goldpinger_nodes_health_total'
*上面代码中的localhost替换你node节点的ip即可。返回如下:
*状态码:200 则通过验证。
*下面的healthy为你实际节点的数量则通过。
三、配置文件修改
/etc/cni/net.d/
目录通常用于保存 CNI(容器网络接口)插件的配置文件。CNI:
1、分配IP地址(es)
2、创建和配置Pod的网络接口
3、(可能)建立覆盖网络
4、Pod的网络配置与Pod沙盒共享相同的生命周期。
1、确认Calico-CIDR
上面我们通过cluster.yaml中的pod cidr进行确认,那么如果cluster.yaml没有保管好,那么可以通过下面的命令获取:
kubectl get installations.operator.tigera.io default \ -o jsonpath='{.spec.calicoNetwork.ipPools[*].cidr}{"\n"}'
*可以看到calico默认的子网为192.168.0.0/16 替换需要CIDR不一样,我们demo使用 10.244.0.0/16 .
2、确认封装协议和协议端口
kubectl get installations.operator.tigera.io default \ -o jsonpath='{.spec.calicoNetwork.ipPools[*].encapsulation}{"\n"}'
*如图使用的是VXLAN封装,默认端口是8472,我们需要使用不同的端口号:8473.
3、编辑cilium配置文件-helm
root@server:~# yq values-migration.yaml
---
operator:
unmanagedPodWatcher:
restart: false
tunnel: vxlan
tunnelPort: 8473
cni:
customConf: true
uninstall: false
ipam:
mode: "cluster-pool"
operator:
clusterPoolIPv4PodCIDRList: ["10.244.0.0/16"]
policyEnforcementMode: "never"
bpf:
hostLegacyRouting: true
*解释:
operator: unmanagedPodWatcher: restart: false
*cilium管理的pod需要重启: true(如果选是,那么没有被cilium管理的pod会重启) false (不重启)
tunnelPort: 8473
*定义vxlan封装的端口号,需要和calico封装使用不同端口号。
cni: customConf: true uninstall: false
*customConf : 暂时跳过编写CNI配置。这是为了防止cilium立即接管。
*uninstall: 上面的第二个设置(uninstall: false)将阻止Cilium删除Calico的CNI配置文件和插件二进制文件,从而允许临时迁移状态。
ipam: mode: "cluster-pool" operator: clusterPoolIPv4PodCIDRList: ["10.244.0.0/16"]
*实时迁移需要使用集群池IPAM模式,以及与Calico不同的Pod CIDR来执行迁移
policyEnforcementMode: "never"
上述操作将禁用网络策略的实施,直到迁移完成。我们将执行迁移后的网络政策。
bpf: hostLegacyRouting: true
该标志通过主机堆栈路由通信,以在迁移期间提供连接。我们将在迁移过程中验证calico管理的pod和cilium管理的pod是否具有连通性。
将上面的内容保存为: values-migration.yaml
四、cilium-cli
cilium-cli: cilium安装工具。
1、下载链接
2、 用values-migration.yaml填充helm value.yaml
*values-migration.yaml就是我们刚才编辑的配置文件。)其实就是helm的value
cilium install \ --helm-values values-migration.yaml \ --dry-run-helm-values > values-initial.yaml
3、完成yaml展示。
yq values-initial.yaml
root@server:~# yq values-initial.yaml
bpf: hostLegacyRouting: true cluster: name: kind-kind cni: customConf: true uninstall: false ipam: mode: cluster-pool operator: clusterPoolIPv4PodCIDRList: - 10.244.0.0/16 operator: replicas: 1 unmanagedPodWatcher: restart: false policyEnforcementMode: never routingMode: tunnel tunnel: vxlan tunnelPort: 8473 tunnelProtocol: vxlan
4、确认calico的默认物理接口
kubectl get installations.operator.tigera.io default \
-o jsonpath='{.spec.calicoNetwork.nodeAddressAutodetectionV4}{"\n"}'
*因为calico的firstfound机制,他会默认使用第一个会检测到的物理接口。
*因为cilium会创建cilium-host接口,所以我们要避免calico使用这个接口。
根据您的Tigera Operator设置(例如,如果您使用interface或skipInterface选项),您可能需要调整参数以确保不考虑cilium_host。
***这点可以通过修改calico的operator.tigera的参数来修改。
Installation reference | Calico DocumentationInstallation API referencehttps://docs.tigera.io/calico/latest/reference/installation/api#operator.tigera.io/v1
kubectl patch installations.operator.tigera.io default --type=merge \ --patch '{"spec": {"calicoNetwork": {"nodeAddressAutodetectionV4": {"firstFound": false, "kubernetes": "NodeInternalIP"}}}}'
* firstFound:设置为false
*kubernetes": "NodeInternalIP*上面的命令是修改firstfound,改为Node InternalIP.
kubectl get installations.operator.tigera.io default \ -o jsonpath='{.spec.calicoNetwork.nodeAddressAutodetectionV4}{"\n"}'
*就是上面的Node InternalIP.
五、Cilium-安装
1、使用Cilium-cli安装Cilium,(使用我们创建的配置文件- values-initial.yaml)
helm repo add cilium https://helm.cilium.io/ helm upgrade --install --namespace kube-system cilium cilium/cilium \ --values values-initial.yaml
2、cilium status --wait (检查并跟踪状态)
*注意上面的:Cluster Pods: 0/26 managed by Cilium
*没有pod被Cilium管理。
3、kubectl get po -n kube-system -o wide
*上面这张图其实就可以看到,cilium之所以不管理是是他使用的网络模式是hostnetwork. 不需要calico分配ip地址。
curl -s http://localhost:32042/check | jq
curl -s http://localhost:32042/metrics | grep '^goldpinger_nodes_health_total'
*还记得我们上面验证节点联通性的测试吗?
*可以看到Cilium的安装并没有影响到节点之间的通信。
*且其他Pod的CIDR依然是Calico的管理的。
ls /etc/cni/net.d/
*检查CNI配置文件是否被修改
六、Cilium-节点配置
1、编写config ConfigMap
*在标准安装中,所有Cilium代理都具有相同的配置,由Cilium -config ConfigMap资源控制。
*我们现在需要在配置一个crd-CiliumNodeConfig.
*CiliumNodeConfig实现在某个符合标签的节点配置cilium.
将下面的代码配置为:ciliumnodeconfig.yaml
apiVersion: cilium.io/v2alpha1 kind: CiliumNodeConfig metadata: namespace: kube-system name: cilium-default spec: nodeSelector: matchLabels: io.cilium.migration/cilium-default: "true" defaults: write-cni-conf-when-ready: /host/etc/cni/net.d/05-cilium.conflist custom-cni-conf: "false" cni-chaining-mode: "none" cni-exclusive: "true"
*此配置将用于将节点的CNI配置从Calico切换到Cilium。
spec
:定义了资源的具体配置。
nodeSelector
:用于选择应用该配置的节点。
matchLabels
:通过标签选择节点。
io.cilium.migration/cilium-default: "true"
:选择具有该标签的节点。defaults
:包含默认配置。
write-cni-conf-when-ready: /host/etc/cni/net.d/05-cilium.conflist
:指定 CNI 配置文件的路径,当准备好时写入该文件。custom-cni-conf: "false"
:表示不使用自定义的 CNI 配置。cni-chaining-mode: "none"
:指定 CNI 链接模式为 "none"。cni-exclusive: "true"
:表示 Cilium 是唯一的 CNI 插件。
2、应用ciliumnodeconfig.yaml
kubectl appy -f ciliumnodeconfig.yaml
*请注意你应用配置之前需要确认你的节点上没有配置文件中的标签。
七、正式开始迁移
1、确认封锁节点
kubectl cordon $NODE
*选择一个节点并且排空
NODE="kind-worker" (替换为你的节点名称)
kubectl drain $NODE --ignore-daemonsets
*将不会有新的节点调度到kind-worker节点上。
kubectl get pods -o wide --field-selector spec.nodeName=kind-worker
2、标记节点
kubectl label node $NODE --overwrite "io.cilium.migration/cilium-default=true"
*注意上面的标签要和你配置文件中一致。
3、重启节点上的Cilium-pod
kubectl -n kube-system delete pod --field-selector spec.nodeName=$NODE -l k8s-app=cilium
kubectl -n kube-system rollout status ds/cilium -w
*这将应用我们刚才配置的CiliumNodeConfig.
4、检查cni配置
docker exec $NODE ls /etc/cni/net.d/
Cilium已经重命名了Calico配置(10- Calico . conflict),并部署了自己的配置文件05-cilium。冲突,因此该节点上的Kubelet现在配置为使用Cilium作为其CNI提供程序。
5、检查pod cidr
kubectl get po -l app.kubernetes.io/instance=nodepinger \
--field-selector spec.nodeName=$NODE -o wide
*因为pod没有重启,还是用的calico的cidr.
6、 强制重启pod
kubectl delete po -l app.kubernetes.io/instance=nodepinger \
--field-selector spec.nodeName=$NODE
7、再次验证
kubectl get po -l app.kubernetes.io/instance=nodepinger \
--field-selector spec.nodeName=$NODE -o wide
*可以看到已经在使用Cilium的Cidr.
8、测试pod的联通性
curl -s http://localhost:32042/metrics | grep '^goldpinger_nodes_health_total'
*说明哪怕你已经使用了Cilium-cni替换为Calico的cni依旧可以通。
9、检查Cilium的状态
cilium status --wait
*可以看到被Cilium管理的pod为1个。
10、解除封锁节点
kubectl uncordon $NODE
*我们通过一个pod验证了,这个节点上的pod依旧可以和其他节点进行通信,那么我们就可以解除封锁节点,允许其他pod进行调度。
11、扩容测试并验证调度
kubectl scale deployment goldpinger --replicas 15
kubectl get po -l app=goldpinger --field-selector spec.nodeName=$NODE -o wide
12、 验证联通性
curl -s http://localhost:32043/metrics | grep '^goldpinger_nodes_health_total'
八、让我们通过循环来迁移所有其他工作节点
1、脚本
for i in $(seq 2 4); do
node="kind-worker${i}"
echo "Migrating node ${node}"
kubectl drain $node --ignore-daemonsets
kubectl label node $node --overwrite "io.cilium.migration/cilium-default=true"
kubectl -n kube-system delete pod --field-selector spec.nodeName=$node -l k8s-app=cilium
kubectl -n kube-system rollout status ds/cilium -w
kubectl uncordon $node
done
*如果是生产环境,建议还是一台一台来。
2、验证Cilium-状态
cilium status --wait
3、重启pod获取新的CIDR
kubectl rollout restart daemonset nodepinger-goldpinger
kubectl rollout status daemonset nodepinger-goldpinger
九、迁移控制节点
1、一样的思路
1、封锁节点
2、打标签
3、检查允许上的ds pod 状态
4、解除封锁-允许调度。
5、重启pod
6、Cilium-CLi工具验证
NODE="kind-control-plane"
kubectl drain $NODE --ignore-daemonsets
kubectl label node $NODE --overwrite "io.cilium.migration/cilium-default=true"
kubectl -n kube-system delete pod --field-selector spec.nodeName=$NODE -l k8s-app=cilium
kubectl -n kube-system rollout status ds/cilium -w
kubectl uncordon $NODE
其他验证命令参考work节点。
十、 Cilium正确替换
1、在2.3章节中cilium配置文件,我们设置了几个参数,我们现在需要对这些参数进行替换:
cilium install \
--helm-values values-initial.yaml \
--helm-set operator.unmanagedPodWatcher.restart=true \
--helm-set cni.customConf=false \
--helm-set policyEnforcementMode=default \
--dry-run-helm-values > values-final.yaml
root@server:~# cat values-final.yaml
bpf:
hostLegacyRouting: true
cluster:
name: kind-kind
cni:
customConf: false
uninstall: false
ipam:
mode: cluster-pool
operator:
clusterPoolIPv4PodCIDRList:
- 10.244.0.0/16
operator:
replicas: 1
unmanagedPodWatcher:
restart: true
policyEnforcementMode: default
routingMode: tunnel
tunnel: vxlan
tunnelPort: 8473
tunnelProtocol: vxlan
从检查两个文件之间的差异可以看出,我们更改了三个参数:
1、通过禁用每个节点的配置,使Cilium能够写入CNI配置文件(customConf)
2、使Cilium重新启动无人管理的豆荚
3、启用网络策略实施
2、通过helm进行更新
*其实Cilium安装就是通过helm.
helm upgrade --install \
--namespace kube-system cilium cilium/cilium \
--values values-final.yaml
kubectl -n kube-system rollout restart daemonset cilium
cilium status --wait
3、删除我们之前配置的CiliumNodeConfig.
十一、删除Calico
1、命令
kubectl delete --force -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml
kubectl delete --force -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/custom-resources.yaml
kubectl delete --force namespace calico-system
十二、重启节点
1、重启工作节点
for i in " " $(seq 1 4); do
node="kind-worker${i}"
echo "Restarting node ${node}"
docker restart $node
sleep 5 # wait for cilium to catch that the node is missing
kubectl -n kube-system rollout status ds/cilium -w
done
2、重启控制节点
docker restart kind-control-plane
sleep 5
kubectl -n kube-system rollout status ds/cilium -w
3、检查工作状态
Cilium status