天天看點

Containerd 的 Bug 導緻容器被重建!如何避免?

作者:openEuler

作者簡介

鄧宇星,SUSE Rancher 中國區軟體架構師,6 年雲原生領域經驗,參與Rancher 1.x 到 Rancher 2.x 版本疊代,目前負責 Rancher For openEuler(RFO) 項目開發。

最近我們關注到一個關于 containerd 運作時的 issue

(https://github.com/containerd/containerd/issues/7843),該問題在 containerd v1.6.9/v1.5.15 被引入。出現的問題是,當 containerd 重新開機後,在其中運作的 Pod 中繼資料中關于網絡相關的資料(如 pod ip)丢失,核心原因在于部分資料沒有落盤。

受影響的版本:

  • v1.6.9 ~ v1.6.14,問題在 v1.6.15 版本中被修複。
  • v1.5.15 ~ v1.5.16,問題在 v1.5.17 版本中被修複。

通過以下步驟,可以快速重制該問題,并驗證該問題的修複情況。

本文使用 rke2 為例進行示範,版本為 rke2 v1.24.9+rke2r1,該版本使用了 k3s-containerd v1.6.12-k3s1,受該 containerd 問題影響。

在 containerd 的預設行為中,重新開機 containerd 服務不會影響正在運作的業務容器,并在啟動容器時,通過将容器父程序綁定 Pid 1 的方式進行展現。即使使用 systemctl 對服務進行重新開機,也不會影響到已經在運作的容器狀态。

—— 問題重制 ——

# 配置rke2使用國内鏡像倉庫下載下傳鏡像
mkdir -p /etc/rancher/rke2
echo "system-default-registry: registry.cn-hangzhou.aliyuncs.com" > /etc/rancher/rke2/config.yaml
# 使用指令安裝 rke2,以下指令使用了我們在國内維護的 rke2 安裝鏡像腳本,會從aliyun OSS下載下傳RKE2資源
curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/rke2/install.sh | INSTALL_RKE2_MIRROR=cn INSTALL_RKE2_VERSION=v1.24.9+rke2r1 sh -
# [INFO]  using v1.24.9-rke2r1 as release
# [INFO]  downloading checksums at https://rancher-mirror.rancher.cn/rke2/releases/download/v1.24.9-rke2r1/sha256sum-amd64.txt
# [INFO]  downloading tarball at https://rancher-mirror.rancher.cn/rke2/releases/download/v1.24.9-rke2r1/rke2.linux-amd64.tar.gz
# [INFO]  verifying tarball
# [INFO]  unpacking tarball file to /usr/local
# 啟動 rke2 服務,并等待服務啟動成功
systemctl start rke2-server
# 配置 rke2 相關的 PATH 路徑以及 kube-config 路徑
export KUBECONFIG=/etc/rancher/rke2/rke2.yaml
export PATH=/var/lib/rancher/rke2/bin:$PATH
# 使用 kubectl 查詢目前叢集狀态
kubectl get po -A | grep rke2-metrics-server-5b987d776b-gqxv9
# kube-system   rke2-metrics-server-5b987d776b-gqxv9                    1/1     Running     0          15m           

至此,rke2 單節點服務啟動完成,但我們的目标是 containerd,接下來繼續操作:

# 配置 containerd 相關環境變量
export CRI_CONFIG_FILE=/var/lib/rancher/rke2/agent/etc/containerd/config.toml CONTAINER_RUNTIME_ENDPOINT=unix:///var/run/k3s/containerd/containerd.sock
# 使用 crictl 查詢pods以及container資訊
crictl pods | grep rke2-metrics-server
# bfad445917423       18 minutes ago      Ready               rke2-metrics-server-5b987d776b-gqxv9                    kube-system         0                   (default)
crictl ps | grep rke2-metrics-server
# db5d6392a310e       f6dc23a68f5fb       18 minutes ago      Running             metrics-server                  0                   bfad445917423       rke2-metrics-server-5b987d776b-gqxv9           

我們以 metrics-server 的 pod 為例,查詢 pod 詳情中的網絡部分内容,并對 containerd 進行重新開機,對問題進行重制:

# 查詢 metrics-server pod的詳情
crictl inspectp bfad445917423 | jq .status.network
# {
#   "additionalIps": [],
#   "ip": "10.42.0.6"
# }
# 停止rke2-server服務并單獨啟動containerd,避免kubelet影響重制結果
systemctl stop rke2-server
# 單獨啟動 containerd
containerd -c /var/lib/rancher/rke2/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/rke2/agent/containerd           

通過新的 terminal,使用 crictl 查詢 containerd 運作狀态

crictl pods | grep rke2-metrics-server
# bfad445917423       24 minutes ago      Ready               rke2-metrics-server-5b987d776b-gqxv9                    kube-system         0                   (default)
# 再次查詢metrics-server pod詳情
crictl inspectp bfad445917423 | jq .status.network
# {
#   "additionalIps": [],
#   "ip": ""
# }
           

從最後的傳回結果可以看出,containerd 重新開機後容器的 IP 丢失。

—— 問題影響 ——

通過在上述例子中重新開機 rke2-server 可以看到,由于 ip 資訊丢失,導緻了業務容器被重建,帶來了業務中斷的風險。

# 在中斷 containerd程序後,重新開機rke2-server程序(以下資料為重新驗證後的資料)
systemctl restart rke2-server
kubectl get po -A |grep rke2-metrics-server-5b987d776b-8vg69
# kube-system   rke2-metrics-server-5b987d776b-8vg69                    1/1     Running     2 (115s ago)   23m
crictl pods | grep rke2-metrics-server
# caba6d8d15823       41 seconds ago      Ready               rke2-metrics-server-5b987d776b-8vg69                    kube-system         1                   (default)
# 2dec6a11fd36f       22 minutes ago      NotReady            rke2-metrics-server-5b987d776b-8vg69                    kube-system         0                   (default)           

可以看到,在 rke2-server 重新開機後,使用了 cni 的 pod 發生了重新開機,在 crictl pods 傳回中可以看到重新建立的 pods。

—— 問題修複驗證 ——

下載下傳新版本 containerd,這次驗證使用 k3s-containerd v1.6.14+k3s1。該版本為 Rancher 在 containerd v1.6.15 釋出前緊急釋出的修複更新檔版本。

# 拉取新鏡像
docker pull rancher/hardened-containerd:v1.6.14-k3s1-build20230105
mkdir container-new
cd container-new
# 從鏡像中擷取新版本containerd
docker run --rm -it -v ${PWD}:/output rancher/hardened-containerd:v1.6.14-k3s1-build20230105 cp -r /usr/local/bin /output
./output/bin/containerd --version
# containerd github.com/k3s-io/containerd v1.6.14-k3s1 6f9c63d571f5026e85a0768f0f2ef03d1c8dbc6e
# 關閉目前運作的容器
pkill -f /var/lib/rancher/rke2/data/v1.24.9-rke2r1-d4d8faf800d0/bin/containerd-shim-runc-v2
# 替換containerd binary版本
cp ./bin/* /var/lib/rancher/rke2/bin
/var/lib/rancher/rke2/bin/containerd --version
# containerd github.com/k3s-io/containerd v1.6.14-k3s1 6f9c63d571f5026e85a0768f0f2ef03d1c8dbc6e
# 啟動 rke2
systemctl start rke2-server
# 此時使用 crictl 查詢新的 metrics-server pod
crictl pods | grep " Ready" |grep metrics-server
# ad8b101f819df       3 minutes ago       Ready               rke2-metrics-server-5b987d776b-gqxv9                    kube-system         1                   (default)
# 停止 rke2 并使用指令行啟動 containerd
systemctl stop rke2-server
containerd -c /var/lib/rancher/rke2/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/rke2/agent/containerd           

通過新的 terminal,使用 crictl 查詢 containerd 運作狀态

crictl inspectp ad8b101f819df | jq .status.network
# {
#   "additionalIps": [],
#   "ip": "10.42.0.13"
# }
           

可以看到 containerd 重新開機後,pod ip 沒有丢失。

—— RKE2 與 RFO ——

RKE2 以下版本受該 issue 影響:

  • v1.23.15+rke2r1
  • v1.24.9+rke2r1
  • v1.25.5+rke2r1
  • v1.26.0+rke2r1

該 issue 在 2022 年 12 月 20 日被送出,RKE2 團隊在 2023 年 1 月 6 日緊急合并了 containerd 中修複該 issue 的 commit,釋出了 k3s-containerd v1.6.14+k3s1 版本,并釋出了新的 rke2 rc 版本進行測試驗證。

最終在 1 月 11 日,RKE2 團隊釋出以下已經修複 containerd 問題的版本:

  • v1.23.16+rke2r1
  • v1.24.9+rke2r2
  • v1.25.5+rke2r2
  • v1.26.0+rke2r2

RFO 是 Rancher For openEuler 的縮寫,顧名思義,目的在于面向 openEuler 打造 Rancher 基礎平台。

由于 RFO 版本釋出周期在 RKE2 之後,RFO 并沒有受到該 issue 影響,并在近期釋出了以下版本:

  • v1.23.16+rfor1
  • v1.24.9+rfor1
  • v1.24.10+rfor1
  • v1.25.5+rfor1
  • v1.25.6+rfor1
  • v1.26.0+rfor1
  • v1.26.1+rfor1

—— 寫在最後 ——

由于作業系統的軟體包釋出存在一定的時間延後性,在大部分情況下都無法及時修複軟體出現的問題。像 CVE、功能缺陷等問題都比較緊急,等待作業系統供應商提供修複版本将是一個漫長的過程,甚至有時候由于一些限制,作業系統提供商無法提供新版本的軟體包,這會給系統運作帶來不确定因素。

在這種情況下,将軟體自身依賴的元件打包到自己的 rootfs 中進行分發,能更好地對其進行管理和更新,避免給系統運作帶來風險以及潛在的損失。

繼續閱讀