Kubernetes 网络升级:安装 Cilium 用上 eBPF(基于阿里云弹性网卡ENI)


之前网络组件用的是 calico,本来想基于 calico 启用 eBPF,但折腾多次没有成功,详见博文 。

于是改用 cilium,这篇博文简单记录一下安装步骤,官方帮助文档 Setting Up Cilium in AlibabaCloud ENI Mode

确认 linux 内核版本 Kernel >= 5.10,不然无法启用 eBPF Host-Routing,详见 https://q.cnblogs.com/q/139828/

在 阿里云 RAM 访问控制 控制台添加子账号

  • 添加用户 cilium,访问方式是 Open API 调用访问
  • 得到 AccessKey IDAccessKey Secret
  • 添加下面的名为 ENIAccess 的授权策略,并授权给 cilium 用户
{
  "Version": "1",
  "Statement": [{
      "Action": [
        "ecs:CreateNetworkInterface",
        "ecs:DescribeNetworkInterfaces",
        "ecs:AttachNetworkInterface",
        "ecs:DetachNetworkInterface",
        "ecs:DeleteNetworkInterface",
        "ecs:DescribeInstanceAttribute",
        "ecs:DescribeInstanceTypes",
        "ecs:AssignPrivateIpAddresses",
        "ecs:UnassignPrivateIpAddresses",
        "ecs:DescribeInstances"
      ],
      "Resource": [
        "*"
      ],
      "Effect": "Allow"
    },
    {
      "Action": [
        "vpc:DescribeVSwitches",
        "vpc:ListTagResources"
      ],
      "Resource": [
        "*"
      ],
      "Effect": "Allow"
    }
  ]
}
  • 除了添加上面的权限,还需要添加 AliyunVPCReadOnlyAccess 权限(只读访问专有网络(VPC)的权限)
  • 在 k8s 集群中创建 secret 并保存 AccessKey ID 与 AccessKey Secret(用 echo -n "access_key" | base64 命令编码)
apiVersion: v1
kind: Secret
metadata:
  name: cilium-alibabacloud
  namespace: kube-system
type: Opaque
data:
  ALIBABA_CLOUD_ACCESS_KEY_ID: ""
  ALIBABA_CLOUD_ACCESS_KEY_SECRET: ""

采用 helm 安装 cilium

helm repo add cilium https://helm.cilium.io/
helm upgrade cilium cilium/cilium --version 1.11.4 \
  --install \
  --namespace kube-system \
  --set alibabacloud.enabled=true \
  --set ipam.mode=alibabacloud \
  --set enableIPv4Masquerade=false \
  --set tunnel=disabled

安装 cilium cli

curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz{,.sha256sum}

强制重启所有 pod 以使用 cilium

kubectl get pods --all-namespaces -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,HOSTNETWORK:.spec.hostNetwork --no-headers=true | grep '' | awk '{print "-n "$1" "$2}' | xargs -L 1 -r kubectl delete pod --force --grace-period 0

检查 cilium pod 是否已正常启动

$ kubectl get pods -l k8s-app=cilium -n kube-system -o wide                                                                                      130 ?
NAME           READY   STATUS    RESTARTS       AGE   IP           NODE                NOMINATED NODE   READINESS GATES
cilium-587m5   1/1     Running   0              10h   10.0.9.198   kube-temp3-16c16g              

检查 cilium 的运作状态

阿里云弹性网卡控制台可以看到 pod 所使用的弹性网卡

接下来用 cilium 取代 kube-proxy。

注:阿里云负载均衡与 Cilium’s kube-proxy replacement 存在兼容问题,暂时不能使用这种方式,详见 https://q.cnblogs.com/q/139841/

先禁用 kube-proxy

kubectl patch ds -n kube-system kube-proxy -p '{"spec":{"template":{"spec":{"nodeSelector":{"non-calico": "true"}}}}}'

然后设置 kubeProxyReplacement

helm upgrade cilium cilium/cilium --version 1.11.4 \
    --namespace kube-system \
    --set kubeProxyReplacement=strict \
    --set k8sServiceHost=k8s-api \
    --set k8sServicePort=6443

注:k8sServiceHostk8sServicePort 是 api-server 的主机名与端口号,可以通过下面的命令获取

kubectl get configmap -n kube-system kube-proxy -o yaml | grep server

确认是否成功取代 kube-proxy

$ kubectl exec -it -n kube-system ds/cilium -- cilium status | grep KubeProxyReplacement   
Defaulted container "cilium-agent" out of: cilium-agent, mount-cgroup (init), clean-cilium-state (init)
KubeProxyReplacement:   Strict   [eth0 10.0.9.171 (Direct Routing), tunl0 192.168.69.192]

KubeProxyReplacement: Strict 说明已成功取代。

Cilium 取代 kube-proxy 之后,通过 service NodePort 暴露的端口在 node 服务器上用 netstat -lntp 命令查看不到,要通过 cilium 命令查看

$ kubectl exec -it -n kube-system daemonset/cilium -- cilium service list
...
130   0.0.0.0:31080         NodePort       1 => 10.0.4.215:80

测试 NodePort 是否可以连上

$ telnet 10.0.9.206 31080
Trying 10.0.9.206...
Connected to 10.0.9.206.
Escape character is '^]'.

Cilium 安装完成,成功用上 eBPF!

收尾工作

在每天节点删除 kube-proxy 生成的 iptables 配置

iptables-save | grep -v KUBE | iptables-restore

删除 calico

kubectl delete -f calico.yaml

删除 kube-proxy

$ # 首先备份 kube-system ConfigMap
$ kubectl get cm kube-proxy -n kube-system -o yaml > kube-proxy-cm.yaml
$ kubectl -n kube-system delete ds kube-proxy
$ kubectl -n kube-system delete cm kube-proxy

遇到的问题

  • K8s 集群基于阿里云弹性网卡 ENI 部署 Cilium 遇到问题
  • Kubernetes control-plane 上 cilium pod 无法正常启动