Ubuntu升级后导致的Kubernetes问题

这是 胆大心不细[My Fault系列] 的第一篇,之鲁莽升级Host OS后k8s集群故障处理。

Ubuntu 16.04 升级到22.04 能有什么坑呢。

1. cgroups 创建失败,Docker containerd Kubernetes Pod创建失败。

syslog 如下
Jan 27 16:54:58 k8s-3 kubelet[159565]: E0127 16:54:58.707563 159565 pod_workers.go:951]

“Error syncing pod, skipping” err=”failed to "CreatePodSandbox"

CreatePodSandboxError: "Failed to create sandbox for pod

rpc error: code = Unknown desc = failed to create containerd task: cgroups: cgroup mountpoint does not exist: unknown"“

Jan 27 16:55:30 k8s-3 kubelet[159565]: E0127 16:55:30.485050 159565 pod_workers.go:951]
“Error syncing pod, skipping” err=”failed to "CreatePodSandbox" for "prometheus-k8s-1_kubesphere-monitoring-system(9040c116-1ef3-4603-a74d-5e9574b260d1)" with CreatePodSandboxError:

rpc error: code = Unknown desc = failed to setup network for sandbox

plugin type=\"flannel\" failed (add): loadFlannelSubnetEnv failed: open /run/flannel/subnet.env: no such file or directory"“

1)解决方案

  • 挂载/sys/fs/cgroup/systemd/

    sudo mkdir /sys/fs/cgroup/systemd
    mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd/
  • 切换内核版本cgroup v1

    编辑 /etc/default/grub,增加 systemd.unified_cgroup_hierarchy=0,重启系统。

    /etc/default/grub
    GRUB_CMDLINE_LINUX_DEFAULT = "systemd.unified_cgroup_hierarchy=0 ..."
  • 升级Kubelet 1.25

    Kubernets升级到1.25,升级过程略。

2)为什么呢

stat -fc %T /sys/fs/cgroup/命令检查系统cgroup版本,cgroup2fs表示v2 tmpfs表示v1。

这个原因是Ubuntu 22.04 默认使用cgroup v2(从21.10开始切换)。当开启cgroup的混合层级模式[上文方案2]或者通过挂载name为systemd的目录兼容cgroup-v1模式(systemd change log)[上文方案1]都能永久或者临时解决问题,但本质是都是在兼容cgroup v1。

我觉得都不是理想解决方案。完美方案还是升级必要的系统组件。

对于Kubernetes,必须满足条件如下:

  • 你的 Linux 发行版在内核版本 5.8 或更高版本上启用 cgroup v2
  • 你的容器运行时支持 cgroup v2。例如:
    • containerd v1.4 或更高版本
    • cri-o v1.20 或更高版本
  • kubelet 和容器运行时配置为使用 systemd cgroup 驱动程序

对于cgroup升级后等等更多问题,或者配置建议,还请参照 https://kubernetes.io/docs/setup/production-environment/container-runtimes/#systemd-cgroup-driver。

2. CoreDNS CrashLoopBackOff

plugin/loop: Loop (127.0.0.1:49720 -> :53) detected for zone ".",
see https://coredns.io/plugins/loop#troubleshooting.

这个错误处理比较简单,方案在日志里。原因是Coredns forward /etc/resolve.conf,查询会循环指向自己,导致死循环,所以Coredns直接退出了。

1)解决方案

  • 修改主机/etc/resolv.conf
    nameserver 172.17.0.53 => realy dns ip(比如223.5.5.5)。
  • 修改coredns configmap
    forward . /etc/resolv.conf = > forward . 223.5.5.5

2)为什么呢

    Ubuntu 16.04一下resolvconf 使用 配置 /etc/resolvconf/resolv.conf.d/head,直接指向了上游DNS。

    Ubuntu 18.04 后使用systemd-237+ 这里有关于/etc/resolv.conf变更,nameserver指向了systemd-resolved的地址127.0.0.53#53。所以导致了递归循环。

3. Pod 频繁重启

bash
Normal   Created         14m (x2 over 14m)     kubelet            Created container kube-rbac-proxy
Normal Started 14m (x2 over 14m) kubelet Started container kube-rbac-proxy
Normal Killing 14m (x2 over 14m) kubelet Stopping container kube-rbac-proxy
Normal SandboxChanged 14m (x2 over 14m) kubelet Pod sandbox changed, it will be killed and re-created.
Warning BackOff 14m (x3 over 14m) kubelet Back-off restarting failed container
Normal Pulled 14m (x3 over 14m) kubelet Container image "prom/node-exporter:v1.3.1" already present on machine
Normal Killing 9m26s (x5 over 14m) kubelet Stopping container node-exporter
Warning BackOff 4m46s (x33 over 14m) kubelet Back-off restarting failed container

这里的关键信息是SandboxChanged

1)解决方案

配置文件/etc/containerd/config.toml中增加下面配置,然后重启containerd

/etc/containerd/config.toml
version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true

2)为什么呢

之前我们配置的Kubernetes的cgroup驱动为systemd,而containerd默认cgroup驱动是cgroupfs

Ubuntu是由systemd初始化的,为了避免创建多套cgroup管理器,产生多余的性能损耗以及其他奇怪的问题,Kubernetes推荐使用systemd操作驱动。

当然containerd作为kubernets的容器运行时,需要保持kubernetes配置与containerd配置一致。kubernetes的配置可从 /var/lib/kubelet/config.yaml中查到。

kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: "systemd"

参照