DockOne微信分享(二五四):阿里云如何构建高性能云原生容器网络? 这篇文章挺厉害的,介绍了cilium在service和networkpolicy上的作用
cilium可以在内核转发和过滤数据包,可以解决现有的kube-proxy性能问题

里面介绍到

Kubernetes Service 性能和扩展性问题

默认的 Kubernetes 的 Service 实现 kube-proxy,它是使用了 iptables 去配置 Service IP 和负载均衡:

容器 配置网卡 容器网络cilium_初始化

如上图所示:
负载均衡过程的 iptables 链路长,导致网络延时显著增加,就算是 IPVS 模式也是绕不开 iptables 的调用;
扩展性差。iptables 规则同步是全量刷的,Service 和 Pod 数量多了,一次规则同步都得接近 1s;Service 和 Pod 数量多了之后,数据链路性能大幅降低。

容器 配置网卡 容器网络cilium_kubernetes_02

NetworkPolicy 性能和扩展性问题

NetworkPolicy 是 Kubernetes 控制 Pod 和 Pod 间是否允许通信的规则。目前主流的 NetworkPolicy 实现基于 iptables 实现,同样有 iptables 的扩展性问题:
iptables 线性匹配,性能不高, Scale 能力差
iptables 线性更新,更新速度慢

容器 配置网卡 容器网络cilium_初始化_03

性能对比
通过 eBPF 对链路的简化,性能有明显提升,相对 iptables 提升 32%,相对 IPVS 提升 62%;
通过编程的 eBPF 的形式,让 Service 数量增加到 5000 时也几乎没有性能损耗,而 iptables 在 Service 增加到 5000 时性能损失了 61%。

这些图都很直观,cilium的突出之处就是,ebpf能让service维持高性能不衰减,也能避免iptables的链路损失。
这篇文章思路其实很好,就是网络层用ipvlan走underlay,networkpolicy和service转发用cilium走ebpf过滤和转发网络包。


调整时间


yum install -y chrony;
timedatectl set-ntp true;
timedatectl set-timezone Asia/Shanghai;
systemctl restart chronyd;


安装或升级containerd



下载最新版的nerdctl,里面有containerd和runc二进制


nerdctl官方github地址https://github.com/containerd/nerdctl/releases


#下载到/root目录下,nerdctl github地址为https://github.com/containerd/nerdctl/releases
tar zxvf nerdctl-full-0.20.0-linux-amd64.tar.gz;

#复制二进制文件、cni文件与systemd文件
\cp -f bin/* /usr/local/bin/;\cp -f lib/systemd/system/* /etc/systemd/system;mkdir -p /opt/cni/bin;\cp -f libexec/cni/* /opt/cni/bin;

#修改buildkitd工作目录与estargz
sed -i "s#ExecStart=/usr/local/bin/buildkitd\(.*\)#ExecStart=/usr/local/bin/buildkitd --root /opt/buildkit --containerd-worker-snapshotter=stargz#g" /etc/systemd/system/buildkit.service

#修改stargz-snapshotter工作目录
sed -i "s#ExecStart=\(.*\)#ExecStart=/usr/local/bin/containerd-stargz-grpc --root /opt/containerd-stargz-grpc --log-level=debug --config=/etc/containerd-stargz-grpc/config.toml#g" /etc/systemd/system/stargz-snapshotter.service

#生成默认配置
mkdir /etc/containerd;containerd config default > /etc/containerd/config.toml;

#修改crictl配置文件,获得containerd的sock信息,否则从yum源安装的crictl无法读取镜像或者清理镜像之类的操作
echo 'runtime-endpoint: unix:///run/containerd/containerd.sock' > /etc/crictl.yaml;

#替换snapshotter与使用 systemd cgroup 驱动程序
sed -i -e 's#registry.k8s.io#registry.aliyuncs.com/google_containers#g' -e 's#registry-1.docker.io#3i61yr6w.mirror.aliyuncs.com#g' -e "s#SystemdCgroup\(.*\)#SystemdCgroup\ =\ true#g" /etc/containerd/config.toml

#下面几段来自kubernetes官网https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#containerd

cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay;
sudo modprobe br_netfilter;
sysctl --system;

systemctl enable --now containerd.service;systemctl restart containerd;


安装kubernetes并初始化集群



安装kubernetes并初始化集群,apiserver地址自己改


#关闭防火墙和selinux,如需开启防火墙请参考kubernetes和选用的cni的官方文档,放行具体端口
systemctl disable firewalld;systemctl stop firewalld;
sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
setenforce 0
#安装kubernetes yum源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.cloud.tencent.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
EOF
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes;
systemctl enable --now kubelet;
#添加内核参数,不执行modprobe br_netfilter会提示下面两个nf-call找不到文件
modprobe br_netfilter
cat << EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.ipv4.ip_forward = 1
net.ipv4.conf.lxc*.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.*.rp_filter = 0
EOF
sysctl -p /etc/sysctl.d/k8s.conf;
#初始化kubernetes集群,cilium的kube-proxy free模式不安装kube-proxy组件。也不安装coredns,因为1.8.0的coredns在阿里云镜像里没有。先初始化集群化再安装coredns。默认忽略所有错误只能是忽略preflight里无法下载registry.aliyuncs.com/google_containers/coredns:v1.8.0这个镜像的错误,如有其他错误就不能忽略。
kubeadm init --image-repository registry.aliyuncs.com/google_containers  --kubernetes-version=stable  --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=$(ifconfig eth0|sed -nr '2s/.*inet ([0-9.]+) .*/\1/p') --skip-phases=addon/kube-proxy --ignore-preflight-errors=all;
#添加kubeconfig
rm -rf $HOME/.kube
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
#开启kubernetes命令补全
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
#设置master节点也参与pod调度
#NoSchedule: 一定不能被调度
#PreferNoSchedule: 尽量不要调度
#NoExecute: 不仅不会调度, 还会驱逐Node上已有的Pod
#消除master污点
kubectl taint nodes --all node-role.kubernetes.io/master-
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

如果发现master主机名没设置好就已经初始化了,可以执行以下命令进行重置

kubeadm reset

这个时候的kubernetes是还没安装完的,要安装cilium整个kubernetes集群才算正常的。


安装helm


cilium要求helm版本要大于等于3.6.0
yum install -y tar;
curl https://mirrors.huaweicloud.com/helm/v3.9.2/helm-v3.9.2-linux-amd64.tar.gz |tar zx;
\cp -f linux-amd64/helm /usr/local/bin;
chmod u+x /usr/local/bin/helm;


安装elrepo主线内核



更新内核,用elrepo内核


安装内核有极大风险,请慎重!!!毕竟用的是kernel-ml,最新的内核,风险不是一般地高


#centos8
yum install -y https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm
#centos7
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
#安装内核
yum install kernel-ml --enablerepo=elrepo-kernel
#centos8不用更改内核启动顺序
#centos7的bios启动,选择第一个启动
grub2-set-default 0;grub2-mkconfig -o /boot/grub2/grub.cfg;
#centos7的efi启动,选择第一个启动
grub2-set-default 0;grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg;

重启电脑后,查看内核是否新的

uname -r


systemd开机挂载bpf



systemd开机挂载bpf,centos8无法使用这个,建议使用下方nodeinit.enabled=true初始化


cat <<EOF | sudo tee /etc/systemd/system/sys-fs-bpf.mount
[Unit]
Description=Cilium BPF mounts
Documentation=https://docs.cilium.io/
DefaultDependencies=no
Before=local-fs.target umount.target
After=swap.target
[Mount]
What=bpffs
Where=/sys/fs/bpf
Type=bpf
Options=rw,nosuid,nodev,noexec,relatime,mode=700
[Install]
WantedBy=multi-user.target
EOF
systemctl enable sys-fs-bpf.mount
systemctl restart sys-fs-bpf.mount


安装cilium



安装cilium,kubeProxyReplacement为strict就是完全替换kube-proxy,k8sServiceHost就是apiserver地址,这里默认是用最新的内核和最新的cilium版本,有些选项一定要elrepo内最新的mainline内核以及最新版本的cilium才能生效,不要乱用,否则无法启动。nativeRoutingCIDR不能乱写。如果网卡驱动符合native xdp要求,可以加上–set loadBalancer.acceleration=native开启native xdp。cilium只支持native xdp,不支持offload xdp和generic xdp。


helm repo add cilium https://helm.cilium.io
helm upgrade -i cilium cilium/cilium --namespace kube-system \
     --set nodeinit.enabled=true \
	 --set routing-mode=native \
	 --set tunnel=disabled \
	 --set k8sClientRateLimit.qps=30 \
	 --set k8sClientRateLimit.burst=40 \
	 --set rollOutCiliumPods=true \
	 --set bpf.masquerade=true \
	 --set bpfClockProbe=true \
	 --set bpf.preallocateMaps=true \
	 --set bpf.tproxy=true \
	 --set bpf.hostLegacyRouting=false \
	 --set autoDirectNodeRoutes=true \
	 --set localRedirectPolicy=true \
	 --set enableCiliumEndpointSlice=true \
	 --set enableK8sEventHandover=true \
	 --set externalIPs.enabled=true \
	 --set hostPort.enabled=true \
	 --set socketLB.enabled=true \
	 --set nodePort.enabled=true \
	 --set sessionAffinity=true \
	 --set annotateK8sNode=true \
	 --set nat46x64Gateway.enabled=false \
	 --set ipv6.enabled=false \
	 --set pmtuDiscovery.enabled=true \
	 --set enableIPv6BIGTCP=false \
	 --set sctp.enabled=true \
	 --set wellKnownIdentities.enabled=true \
	 --set hubble.enabled=false \
	 --set ipv4NativeRoutingCIDR=192.168.31.254/32 \
	 --set ipam.operator.clusterPoolIPv4PodCIDRList[0]="10.244.0.0/16" \
	 --set devices=enp7s0 \
	 --set installNoConntrackIptablesRules=true \
	 --set enableIPv4BIGTCP=true \
	 --set egressGateway.enabled=false \
	 --set endpointRoutes.enabled=false \
	 --set kubeProxyReplacement=true \
	 --set loadBalancer.mode=dsr \
	 --set loadBalancer.serviceTopology=true \
	 --set bandwidthManager.enabled=true \
	 --set bandwidthManager.bbr=true \
	 --set highScaleIPcache.enabled=false \
	 --set l2announcements.enabled=false \
	 --set l2podAnnouncements.interface=enp7s0 \
	 --set image.useDigest=false \
	 --set operator.image.useDigest=false \
	 --set operator.rollOutPods=true \
	 --set authentication.enabled=false \
	 --set operator.image.repository=registry.cn-shenzhen.aliyuncs.com/liweilun1/operator \
	 --set image.repository=registry.cn-shenzhen.aliyuncs.com/liweilun1/cilium \
	 --set k8sServiceHost=192.168.31.254 \
	 --set k8sServicePort=6443

到了这步,cilium就算安装完成了,查看pod状态也应该正常运行了。
最关键的一步就是查看iptables里面是否真的没有了长篇的转发规则
以前的iptables,满眼看上去都是转发规则

iptables-save|grep KUBE

容器 配置网卡 容器网络cilium_sed_04

容器 配置网卡 容器网络cilium_容器 配置网卡_05


现在的iptables

iptables-save|grep KUBE

容器 配置网卡 容器网络cilium_容器 配置网卡_06

我测试的时候还建了两个服务,但是也没看到转发规则了
这个时候可以进去查看cilium 控制的服务,pod名称要替换

kubectl exec -it -n kube-system cilium-srpvh -- cilium service list

容器 配置网卡 容器网络cilium_kubernetes_07


服务转发规则一目了然

下面是官网的检测例子

cilium Kubernetes without kube-proxy

容器 配置网卡 容器网络cilium_sed_08


容器 配置网卡 容器网络cilium_sed_09

容器 配置网卡 容器网络cilium_sed_10


以上是官网上的例子