作者 | 张攀(豫哲)
起源 | 尔达 Erda 公众号
导读:Erda 作为一站式云原生 PaaS 平台,现已面向宽广开发者实现 70w+ 外围代码全副开源!** 在 Erda 开源的同时,咱们打算编写《基于 K8s 的云原生 PaaS 平台基础架构》系列文章,心愿咱们的一点教训能够帮忙更多企业欠缺 PaaS 平台基础架构的建设。本文为系列文的第一篇。
缘起
Kubernetes 在 1.20 版本之后将弃用 Docker 作为容器运行时:
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md#deprecation
2020 年底,Kubernetes 官网发布公告,发表自 v1.20 起放弃对 Docker 的反对,届时用户在 kubelet 启动日志中将收到 docker 弃用正告。这个大瓜的爆出,对还在应用 Kubernetes 的 docker 开发者和工程师来说无疑是一项惨重的累赘。那么 Kubernetes 弃用 docker,对咱们有哪些影响呢?别慌,这件事件,没有设想中的那么可怕。
If you’re rolling your own clusters, you will also need to make changes to avoid your clusters breaking. At v1.20, you will get a deprecation warning for Docker. When Docker runtime support is removed in a future release (currently planned for the 1.22 release in late 2021) of Kubernetes it will no longer be supported and you will need to switch to one of the other compliant container runtimes, like containerd or CRI-O. Just make sure that the runtime you choose supports the docker daemon configurations you currently use (e.g. logging).
这段话翻译过去大抵是说,在 v1.20 的版本中,只会收到一个 docker 的弃用正告,在将来 v1.22 版本之前是不会删除的,这意味着到 2021 年底的 v1.23 版本,咱们还有 1 年的 buffer 工夫来寻找适合的 CRI 运行时来确保顺利的过渡,比方 containerd 和 CRI- O。
缘灭
为什么 Kubernetes 要放弃 docker,改用其它 CRI 呢?
咱们晓得,CRI 是 Kubernetes 在 v1.5 版本中引入的,充当 kubelet 和容器运行时之间的桥梁。简略概述:CRI 是以容器为核心的 API,设计的初衷是不心愿向容器(比方 docker)裸露 pod 信息或 pod 的 api 接口,通过这种接口模式,Kubernetes 毋庸从新编译就能够应用更多的容器运行时。然而呢,Docker 与 CRI 不兼容,为了适配 Docker,Kubernetes 就搞进去了 dockershim 这么个东东,将 CRI 转换成 Docker API,kubelet 应用 dockershim 和 docker 进行通信,docker 再和上面的 containerd 进行通信。这样就能够欢快地工作了。如下图所示:
- Dockershim 为了反对多种 OCI Runtime,负责为每个启动的容器拉起一个新的 docker-shim 过程,指定容器 ID、Bundle 目录、运行时的二进制(runc),dockershim 容许 kubelet 与 docker 交互,就如同 docker 是一个 CRI 兼容的运行时一样。
原本大家相安无事,直到去年年底,这场均衡被 Kubernetes 公开突破了。Kubernetes 介绍说是因为保护 dockershim 曾经成为 Kubernetes 维护者的沉重负担。dockershim 始终都是 Kubernetes 社区为了能让 docker 成为其反对的容器运行时,所保护的一个兼容程序。本次所谓的废除,也仅仅是 Kubernetes 要放弃对当初 Kubernetes 代码仓库中的 dockershim 的保护反对。而 Docker 自身目前没有实现 CRI,因而是本次事件的问题所在。
简略理解过 Kubernetes 为什么要弃用 docker 当前,咱们须要晓得 docker 的弃用,对咱们有哪些影响?又有哪些代替计划呢?
- If you are relying on the underlying docker socket (/var/run/docker.sock) as part of a workflow within your cluster today, moving to a different runtime will break your ability to use it.
- Make sure no privileged Pods execute Docker commands.
- Check that scripts and apps running on nodes outside of Kubernetes infrastructure do not execute Docker commands.
- Third-party tools that perform above mentioned privileged operations.
- Make sure there is no indirect dependencies on dockershim behavior.
对使用者来说,Kbernetes 的此举决定会影响依赖 docker.sock 的应用程序及事件流(比方 kubelet 的 container-runtime-endpoint 参数),影响执行 docker 命令和那些对 dockershim 组件的依赖。
缘生
有哪些代替计划呢?
代替计划 1:Containerd
Containerd(https://containerd.io)是 Docker 公司在 OCI 成立时,募捐给 CNCF,目前曾经从 CNCF 毕业的开源我的项目。Containerd 是一个行业标准的容器运行时,强调简略性、健壮性和可移植性,旨在嵌入到更大的零碎中,而不是由开发人员或最终用户间接应用。Kubernetes 通过 CRI 接口的模式将 Containerd 用作 Kubernetes 集群的容器运行时,如下图所示:
- cri plugin 是 containerd 的原生插件,从 containerd v1.1 开始,CRI 插件内置在公布的 containerd 二进制文件中。
containerd 部署
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# 设置必须的 sysctl 参数,这些参数在重新启动后依然失效
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# 利用 sysctl 参数而无需重新启动
sudo sysctl --system
# 应用 docker-ce yum 源
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 装置 containerd
sudo yum install -y containerd.io
# 配置 containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
批改配置文件,新增 "SystemdCgroup = true",应用 systemd 作为 cgroup 驱动程序
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
# 重新启动 containerd
sudo systemctl restart containerd
应用 crictl 连贯到 containerd,验证 CRI 插件的应用:
查看 K8s 集群应用的 CRI 类型:
查看 kubelet 指定的 cri socket:
至此,咱们曾经实现了 containerd 代替 docker,Kubernetes 集群改用其它(containerd)runC 的实现。
代替计划 2:CRI-O
CRI-O(https://cri-o.io)是由红帽发动并开源的一款容器运行时,是面向 Kubernetes 的 OCI(Open Container Initiative)的容器运行时,是 Kubernetes 的 CRI 规范实现,并且容许 Kubernetes 间接应用 OCI 兼容的容器运行时,能够把 cri-o 看成 Kubernetes 应用 OCI 兼容的容器运行时的中间层,如下图所示:
CRI-O 部署
# 创立 .conf 文件以在启动时加载模块
cat <<EOF | sudo tee /etc/modules-load.d/crio.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# 配置 sysctl 参数,这些配置在重启之后依然起作用
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
# 设置与 kubernetes 相匹配的 CRI- O 版本(本次环境验证应用了 k8s 1.21.1 版本)VERSION=1.21
OS=CentOS_8
# 下载 yum 源,执行装置
sudo 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
sudo 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
sudo yum install cri-o -y
# 启动 CRI-O
sudo systemctl daemon-reload
sudo systemctl start crio
sudo systemctl enable crio
# 更改 kubelet 参数, 指定 cri-o 的 socket 文件
cat /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--container-runtime=remote --container-runtime-endpoint=/run/crio/crio.sock --pod-infra-container-image=k8s.gcr.io/pause:3.4.1"
# 重启 kubelet
应用 crictl 连贯到 cri-o,验证 CRI 插件的应用:
查看 K8s 集群应用的 CRI 类型及 kubelet 指定的 cri socket:
至此,咱们曾经实现了 CRI- O 代替 docker,Kubernetes 集群改用其它(cri-o)runC 的实现。
用在当下
对于以后正在运行的 K8s 集群,如何更改容器运行时呢?咱们以 cri-o 为例:
- 版本适配性,抉择对应的版本
- 更改 registry 仓库及 pause image
- pod 迁徙
# 为须要更改 CRI 的 node 节点增加污点,开释节点上的所有 pod,并且不在接管新的 pod 申请
kubectl drain [node-name] --force --ignore-daemonsets --delete-local-data
# 停用 docker,启用 cri-o,更改 kubelet --container-runtime-endpoint=/run/crio/crio.sock
# 查看 node 状态,确认无问题后,kubectl get node
# 复原 node 节点,接管新的 pod 申请
kubectl uncordon [node-name]
范例:
setp1:确定环境信息。
setp2:应用 kubectl drain 从节点平安地逐出所有 Pod。
# kubectl drain izj6cco138rpkaoqqn6ldnz --force --ignore-daemonsets --delete-local-data
node/izj6cco138rpkaoqqn6ldnz cordoned
WARNING: ignoring DaemonSet-managed Pods: calico-system/calico-node-7l4gc, kube-system/kube-proxy-kztbh
evicting pod default/kube-demo-7456947cdc-wmqb5
evicting pod default/kube-demo-7456947cdc-kfrqr
evicting pod calico-system/calico-typha-5f84f554ff-hzxbg
pod/calico-typha-5f84f554ff-hzxbg evicted
pod/kube-demo-7456947cdc-wmqb5 evicted
pod/kube-demo-7456947cdc-kfrqr evicted
node/izj6cco138rpkaoqqn6ldnz evicted
setp3:验证以后 Pod 状态。
setp4:卸载 docker,装置 cri-o(过程略)。
setp5:批改 kubelet,指定 container-runtime-endpoint。
# vim /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k9s.gcr.io/pause:3.2 --resolv-conf=/run/systemd/resolve/resolv.conf --container-runtime=remote --container-runtime-endpoint=/run/crio/crio.sock"
setp6:复原 node 节点,接管新的 pod 申请,验证。
setp7:
因为 master 节点不能 drain,所以只能进行 kubelet,work 节点和 pods 会持续运行,但此时集群是托管状态。
更改 kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock。
更改 kubelet(同 setp5)。
验证 master 节点。
参考资料
- 《Don’t Panic: Kubernetes and Docker》:
https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/
- 《Dockershim Deprecation FAQ》:
https://kubernetes.io/blog/2020/12/02/dockershim-faq/
- 《Getting started with containerd》:
https://containerd.io/docs/getting-started/
- containerd GitHub 地址:
https://github.com/containerd/containerd
- cri-o GitHub 地址:
https://github.com/cri-o/cri-o
欢送参加开源
Erda 作为开源的一站式云原生 PaaS 平台,具备 DevOps、微服务观测治理、多云治理以及快数据治理等平台级能力。点击下方链接即可参加开源 ,和泛滥开发者一起探讨、交换,共建开源社区。 欢送大家关注、奉献代码和 Star!
- Erda Github 地址:https://github.com/erda-project/erda
- Erda Cloud 官网:https://www.erda.cloud/