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

Rancher發表於2023-02-07
作者簡介
鄧宇星,SUSE Rancher 中國區軟體架構師,6 年雲原生領域經驗,參與 Rancher 1.x 到 Rancher 2.x 版本迭代,目前負責 Rancher For openEuler(RFO) 專案開發。

最近我們關注到一個關於 containerd 執行時的 issue,該問題在 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 中進行分發,能更好地對其進行管理和升級,避免給系統執行帶來風險以及潛在的損失。

關於 RFO 的專案說明和部署使用,請點選《Rancher RFO 正式 GA》

相關文章