社区编辑申请
注册/登录
实战直击:Kubernetes弃用Docker?
开发
前段时间,kubernetes推出了1.24版本,曾经轰动一时的docker弃用也正式实装了,这意味着1.24版本之后,docker将不能作为k8s的容器运行时。docker作为云原生的基础技术底座,如果kubernetes不再支持docker,这在互联网IT业界都会引发不大不小的恐慌,这到底该怎么办?

作者 | 刘启伟,广东公司网络管理中心网管系统室平台团队核心专家。近年来,网管系统室一方面大力推进OSS应用建设,为“三零三自”的自智网络赋能;另一方面,积极推动微服务、容器化、PaaS、DevOps等云原生技术的实践落地。在团队中负责DevOps平台和容器云的建设运营工作,拥有丰富的Kubernetes、Istio、DevOps工具链落地实践经验,致力于克服技术落地难题,用云原生技术赋能应用。

Labs 导读

​Kubernetes是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes拥有一个庞大且快速增长的生态系统,其服务、支持和工具的使用范围广泛。

1前言

前段时间,kubernetes推出了1.24版本,曾经轰动一时的docker弃用也正式实装了,这意味着1.24版本之后,docker将不能作为k8s的容器运行时。docker作为云原生的基础技术底座,如果kubernetes不再支持docker,这在互联网IT业界都会引发不大不小的恐慌,这到底该怎么办?是不是docker完全不能使用了?

2技术的真相

其实kubernetes只是弃用了dockershim,并不是弃用了docker的全部。docker体系中的containerd是符合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设置。

怎么将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运行时在node annotations中定义,需要单独修改,否则下次使用kubeadm时会出错,比如升级k8s版本的时候。

# 查看当前节点的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的方案经过多年发展已经成熟,被广泛地应用,短期内地位仍然不可撼动。开发、测试环境可以按照需求折腾,迁移容器运行时,积累实践经验。生产环境的话建议保持稳定,等时机成熟再迁移。

责任编辑:未丽燕 来源: 移动Labs
相关推荐

2020-12-18 09:23:41

KubernetesDocker

2020-12-03 18:29:30

KubernetesDocker容器

2021-03-16 08:35:14

Kubernetes Docker容器

2021-06-04 05:21:19

KubernetesDocker容器

2021-12-21 15:31:40

2022-05-12 08:01:18

2018-02-02 16:32:10

KubernetesDocker命令

2015-07-17 10:25:43

kubernetesDocker集群系统

2017-10-18 07:42:23

2020-12-04 14:19:08

2022-03-21 08:23:22

Kubernetes容器密钥

2020-12-07 07:48:35

2016-07-29 15:49:58

DockerKubernetesMongoDB

2019-11-11 21:34:33

DockerKubernetes容器

2020-02-05 14:31:04

两种互通方法

2019-09-12 10:43:44

2019-12-27 10:33:43

运维架构技术

2022-07-08 15:13:21

DockerLinux命令

2019-08-05 14:23:43

2020-09-25 08:00:57

同话题下的热门内容

该不该将单体架构迁移到微服务?如何创建一个无代码的自助客户聊天机器人功能测试vs.非功能测试:能否非此即彼地进行选择?JMS VS Kafka:苹果与橘子之战!「芯片法案」下周签署!台积电沉默以对佩洛西,三星、SK海力士谨慎观望Java 服务 Docker 容器化优秀实践说实话,今年互联网人跳槽的逻辑变了八个流行的 Python 可视化工具包,你喜欢哪个?

编辑推荐

2017年9月编程语言排行榜:Java、C与C++三巨头还能统治排行榜多久?2017年最受欢迎的5个前端框架比较2017年11月编程语言排行榜:脚本语言怎么了?2017年3月编程语言排行榜:Swift首次进入前十最近租房有点烦!技术人如何用Python找到称心如意的“小窝”?
我收藏的内容
点赞
收藏

51CTO技术栈公众号