導讀
Kubernetes是一個可移植和可擴展的開源平臺,用于管理容器化的工作負載和服務,可以促進聲明式配置和自動化。Kubernetes擁有一個龐大且快速增長的生態系統,其服務、支持和工具被廣泛使用。
作者簡介
劉啟偉,公司網絡管理中心網絡管理系統機房平臺團隊核心專家。近年來,網管系統室一方面大力推進OSS應用建設,賦能“303自”自智能網絡;另一方面,積極推進微服務、容器化、PaaS、DevOps等云原生技術的實踐。在團隊中,負責DevOps平臺和容器云的建設和運營。他在Kubernetes、Istio和DevOps工具鏈的落地方面有著豐富的實踐經驗,致力于克服技術落地難題,用云原生技術實現應用。
1、前言
前段時間Kubernetes推出了1.24版本,曾經轟動一時的Docker被拋棄,正式安裝。這意味著1.24版本之后,Docker將無法作為k8s的容器運行。
Docker是云的基礎技術基礎。如果Kubernetes不再支持Docker,將會在互聯網IT行業引起適度的恐慌。我們做什么呢Docker是不是完全不能用了?
2、技術的真相
事實上,Kubernetes只是拋棄了dockershim,而不是Docker的全部。Docker系統中包含的是CRI兼容的,可以繼續作為Kubernetes的容器運行時運行。OCI標準的實施者RunC也屬于Docker系統。
另一方面,Docker構建的映像符合OCI標準,可以在Kubernetes集群中運行,因此Docker仍然可以在本地用于開發和測試。
2.1 OCI 和 CRI 標準分別是什么?
OCI(Open Container Initiative)是一套圍繞容器技術的開放標準和規范,主要定義了容器的生命周期管理規范。
OCI的實現者通常被稱為“低級容器運行時”,比如runC。底層運行時的主要功能是根據給定的容器文件系統和JSON配置文件,創建容器,管理容器的生命周期。
CRI(Container Runtime Interface)是一組插件接口,定義了Kubernetes(kubelet)與容器運行時之間的接口規范,實現了兩者之間的解耦。
通過CRI與Kubernetes交互的運行時通常被稱為“高級容器運行時”。高級運行時的作用是為容器準備必要的運行環境,如拉映像、解壓映像和創建容器文件系統、創建容器網絡等。然后調用低級容器運行時來創建和運行容器。
2.2 Kubernetes支持哪些容器運行時?
Kubernetes支持任何符合CRI標準的容器運行時。在1.23版本之前,有三種常用的容器運行時:docker、containerd和CRI-O。
Docker
Docker 守護進程是不符合 CRI 標準的。為了支持 Docker 作為容器運行時,kubelet 內置了一個 dockershim 模塊,kubelet 通過 CRI 調用 dockershim,再由它轉換請求,調用 Docker 守護進程,而 1.24 版本將要移除的就是這個模塊。此模式下創建容器時的調用過程如下:
Kubelet 通過 CRI 調用 dockershim
dockershim 轉換請求,調用 docker 守護進程
docker 調用 containerd
containerd 創建 containerd-shim 進程,再由 containerd-shim 調用 runC 完成容器創建。最終容器由 containerd-shim 管理,容器內所有進程都是 containerd-shim 的子進程。
containerd
containerd 是從 docker 守護進程中獨立出來的容器運行時,最終也要通過 runC 運行容器。
在 CRI 標準被提出后,為了兼容 CRI,減少調用開銷,containerd 開發了一個守護進程,叫 CRI-containerd。原先調用鏈 kubelet -> dockershim -> dockerd -> containerd 被簡化成為 kubelet -> CRI-containerd -> containerd。后來,containerd 干脆將 CRI-containerd 以 CRI 插件形式內建在項目中,直接通過方法調用,進一步將調用鏈簡化為 kubelet -> containerd。
cri-o
CRI 標準被提出后,紅帽按照 CRI 開發的一個輕量級容器運行時,是 CRI 標準的最小實現。此模式下kubelet直接調用 cri-o,再由 cri-o 調用 runC 完成容器創建和管理,調用鏈比較簡潔。
廣東公司網絡管理中心網管系統室負責建設和維護O域容器云,近期剛好啟動Kubernetes 版本升級工作,借此機會,我們決定在測試環境上將容器運行時從 docker遷移至 cri-o,并驗證下 Kubernetes 1.23 -> 1.24 版本升級方案,以下是遷移的部分注意事項及詳細步驟。
3、遷移注意事項和詳細步驟
?注意事項:
1、對于使用 docker in docker 的 pod,如果是掛載宿主機的 docker.sock 守護進程,遷移后將不能運行,如果是在容器中安裝獨立的 docker 守護進程,遷移后仍然可以正常運行。
2、/etc/docker/daemon.json 中的配置需要同步到新的運行時,比如倉庫的鏡像站點。
3、檢查各種運維腳本,如果包含 docker 命令需要修改。
4、容器 stdout/stderr 日志形式變更,如果使用 Fluentd 或者 Filebeat 收集日志,需要修改配置。
①日志目錄:使用 docker 時,日志通過 /var/log/containers 鏈接到 /var/log/pods/ 目錄,最后鏈接到 /var/lib/docker/containers/xxx/ 目錄,如果使用其他運行時,一般是通過 /var/log/containers 鏈接到 /var/log/pods/ 目錄,由 kubelet 管理。
②日志格式:使用 docker 時,很多人習慣設置 json 格式,而切換到其他運行時,默認格式是 text,格式為 “time stream log-info”。日志解析配置需要修改。
③日志回滾:使用 docker 時,在 daemon.json 配置,切換運行時后,通過 kubelet 的配置項 containerLogMaxSize、containerLogMaxFiles 設置。
5、其他注意點參考官網FAQ文檔:
https://kubernetes.io/zh/blog/2022/02/17/dockershim-faq/
怎么將 Kubernetes 的容器運行時從 docker 遷移至 cri-o?
操作系統:centOS 7.9
內核版本:5.4.178
kubernetes版本:1.23.3
cri-o:1.22.3
1、遷移按節點進行,先驅逐 pod 并隔離節點
kubectl drain --delete-emptydir-data --force --ignore-daemonsets <NODE_NAME>
2、卸載 docker
systemctl stop kubelet
systemctl stop docker
systemctl disable docker
yum remove -y docker-ce
# docker數據目錄先保留一段時間,運行沒異常再刪除
rm -rf /var/lib/docker
3、內核設置
這些設置一般在k8s安裝前都會設置,這里再確認一次,已經設置好的忽略這一步。
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sysctl --system
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
4、安裝 cri-o
# 設置yum源
export OS=CentOS_7
export VERSION=1.22
curl -L -o
/etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/devel:kubic:libcontainers:stable.repo
curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo
# 安裝cri-o
yum install -y cri-o
5、修改 cri-o 配置
# 查看conmon路徑
which conmon
# 修改cri-o配置文件
vi /etc/crio/crio.conf
# 修改crio.runtime表,加上conmon路徑配置
[crio.runtime]
conmon = "/usr/bin/conmon"
# 修改crio.image表,加上pause鏡像設置。xxx需要換成你的私有鏡像庫
[crio.image]
insecure_registries = ["xxx"]
pause_image = "xxx/k8s/pause:3.6"
# 修改registry配置
vi /etc/containers/registries.conf
# 添加私有鏡像庫,xxx需要替換成你的私有鏡像庫,這里設置了insecure,可按實現情況修改
# 因為我用的是私有倉庫,不需要設置鏡像站點
[[registry]]
prefix = "xxx"
insecure = true
blocked = false
location = "xxx"
6、啟動 cri-o 服務
systemctl enable crio
systemctl start crio
systemctl status crio
7、修改 kubelet 配置
設置 kubelet 命令行啟動參數,指定使用 cri-o 運行時。
vi /etc/sysconfig/kubelet
# 修改內容,加上以下兩個參數
KUBELET_EXTRA_ARGS=--container-runtime=remote --container-runtime-endpoint='unix:///var/run/crio/crio.sock'
修改 /var/lib/kubelet/kubeadm-flags.env 文件,文件中如果有以下3個參數,請刪除。
-- cgroup-driver k8s 建議在配置文件設置,不要在命令行。
-- cni-plugin 1.24 版本后會和 docker-shim 一起被移除。
-- pod-infra-container-image 當使用 cri-o 運行時,kubelet 忽略這個參數,需要在 cri-o 配置中指定。
修改 kubelet 的配置文件 /var/lib/kubelet/config.yaml,修改以下4個參數,如果參數不存在則添加上去。
設置 kubelet 的 cgroup 驅動為 systemd,因為 cri-o 默認驅動是 systemd,必須保持一致。舊版本 kubelet 默認驅動是 cgroupfs,1.22以上才是默認systemd。
cgroupDriver: systemd
設置運行時請求超時:
runtimeRequestTimeout: 5m
容器 stdout/stderr 日志文件的回滾設置,按實際需求修改。
containerLogMaxSize: 100Mi
containerLogMaxFiles: 3
修改了 /var/lib/kubelet/config.yaml 文件后,建議同步修改內容到 kubelet-config-1.xx configmap,1.xx 是 kubernetes 的版本。因為集群擴容時,新節點使用這個 configmap 生成配置文件,這樣可以保證新舊節點配置文件一致。
kubectl edit cm -n kube-system kubelet-config-1.23
8、啟動 kubelet,查看 kubelet 狀態、節點狀態、pod 狀態是否正常
systemctl start kubelet
systemctl status kubelet
9、更新 kubeadm 使用的 cri 運行時
# 查看當前節點的kubeadm使用的cri運行時
kubectl get node <NODE_NAME> -o jsonpath='{.metadata.annotations.kubeadm\.alpha\.kubernetes\.io/cri-socket}'
# 將dokcershim修改為cri-o
kubectl annotate node <NODE_NAME> --overwrite kubeadm.alpha.kubernetes.io/cri-socket=/var/run/crio/crio.sock
10、安裝 podman
podman 是一個開源的容器管理工具,命令幾乎與 Docker 一致,可以用于替換 docker。相較于 Docker,它不存在守護進程,因此 podman 避免了 docker daemon 引入的問題。另一方面,cri-o 專注于 CRI 實現,沒有提供 build、tag 鏡像等功能,而 podman 和 cri-o 的鏡像是共享的,可以為 cri-o 補充鏡像管理功能。
yum install -y podman
podman info
11、重啟服務器
Docker 卸載后可能還有一些配置遺留,例如 iptables 規則,建議重啟服務器,防止被影響。
12、將節點重新加入集群調度
kubectl uncordon <NODE_NAME>
到這里,第一個節點的容器運行時遷移就完成了,可以按照相同的方法再遷移其他節點。
遷移完成后就能愉快地把 K8s 版本升到 1.24.0 了。
4 后記
雖然 k8s 已經正式移除了 dockershim,但是 docker+kubernetes 的方案經過多年發展已經成熟,被廣泛地應用,短期內地位仍然不可撼動。開發、測試環境可以按照需求折騰,遷移容器運行時,積累實踐經驗。生產環境的話建議保持穩定,等時機成熟再遷移。