k8s搭配containerd

一直在关注Kubernetes动态,眼看着1.20 版本要发布了,抱着好奇的心理去Github看看这个版本更新了啥?结果在弃用位置发现了一个焦点,说要“弃用对Docker支持”

Kubelet 中对 Docker 支持被弃用,并将在以后的版本中删除。

目前Kubelet 使用一个名为 dockershim 的模块,该模块实现了对Docker的 CRI 支持,后续版本将删除dockershim

每一个容器运行时都需要自己实现一个 CRI shim,即完成对 CRI 这个抽象接口的具体实现。这样容器运行时就可以接收来自 Kubelet 的请求。

从上图可以看出,新增的 CRI shim 是 Kubelet 和容器运行时之间的交互纽带,Kubelet 只需要跟 CRI shim 进行交互。Kubelet 调用 CRI shim 的接口,CRI shim 响应请求后会调用底层的运行容器时,完成对容器的相关操作。

这里我们需要将 Kubelet、CRI shim 以及容器运行时都部署在同一个节点上。一般来说,大多数的容器运行时都默认实现了 CRI 的接口,比如containerd。

名词的解释

https://blog.csdn.net/weixin_40864891/article/details/86655846

CRI:容器运行时接口 container runtime interface,CRI 中定义了容器和镜像两个接口

实现了这两个接口目前主流的是:

CRI-O:   相关介绍: https://linux.cn/article-9015-1.html

Containerd: 相关介绍 :https://segmentfault.com/a/1190000023618092

其主要的作用:

  • 针对容器操作的接口,包括容器的创建、启动和停止等
  • 针对镜像的操作,拉去、删除镜像等
  • 针对 podsandbox(容器沙箱环境)
  • 以上全是接口

OCI 中定义了两个标准:

容器运行时标准 和 容器镜像标准,实现了这一标准的主流是:

runc(也即我们日常说的 Docker,因为是docker 开源出来的)

Kata-Container  介绍文章 https://segmentfault.com/a/1190000021845002?utm_medium=referral&utm_source=tuicool

主要作用,制作容器:

  • 容器镜像制作内容,即 ImageSpec
  • 容器需要接收哪些指令,即 runtimeSpec

Dockershim 作用:把外部收到的请求转化成 Docker Daemon 能听懂的请求,让 Docker Daemon 执行创建、删除等容器操作。

 

 

 组件介绍:

  • docker:命令行管理工具

  • dockerd:Docker守护进程,负责与docker client交互;

  • containerd:负责镜像管理和容器管理的守护进程,containerd是一个标准的容器运行时,可以独立管理容器生命周期,也就是即使不运行dockerd,容器也能正常工作;
  • containerd-shim:是一个真实运行的容器的载体,每启动一个容器都会起一个新的shim的一个进程;
  • runC:一个命令行工具,根据OCI标准来创建和运行容器。

当我们执行docker run创建一个容器时,大致流程:

1.docker工具向dockerd守护进程发送创建容器请求;

2.dockerd收到请求后再向containerd请求创建一个容器;

3.containerd收到请求后并不会直接创建容器,而让shim创建容器;

4.docker-shim又调用runC创建容器(准备容器所需的namespace和cgroups就退出了),docker-shim就作为了该容器进程的父进程,负责收集容器状态并上报给containerd。

通过上面来看,Docker Daemon 和 dockershim 看上去就是两个不干活的东西,Kubelet 为啥不直接调用 containerd 呢?其实和容器历程有关,这里不在阐述。

有兴趣可以看张磊老师的博客https://time.geekbang.org/column/intro/100015201

尽管现在已经有 CRI-Ocontainerd-plugin 这样更精简轻量的 Runtime 架构,但 dockershim 这一套作为经受了最多生产环境考验的方案,迄今为止仍是 Kubernetes 默认的 Runtime 实现

   

 

 

 

 

可以看出,调用链还是很复杂的,多层封装和调用,导致性能降低、提升故障率、不易排查,我想这也是弃用对Docker支持的主要原因吧!

如果把容器运行时换成containerd,如图所示

 

 

 

 

 

可见,Containerd 调用链更短,组件更少,占用节点资源也比较少

containerd 1.1 版本已经内置了对 CRI 的实现,比直接使用 Docker 的性能要高很多。

如果使用containerd我们就需要配置

kubelet 的 --container-runtime 参数为 remote,

设置 --container-runtime-endpoint 为对应的容器运行时的监听地址

比如:

--container-runtime=remote 
--container-runtime-endpoint=unix:///run/containerd/containerd.sock 

我这边用的是centos8的系统,所以需要安装containerd 和runc  相关的软件包

dnf install runc -y 

https://github.com/containerd/containerd

wget  https://github.com/containerd/containerd/releases/download/v1.3.9/containerd-1.3.9-linux-amd64.tar.gz

tar -zxvf containerd-1.3.9-linux-amd64.tar.gz 

cd bin/

cp * /usr/bin/

mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

 

这里重点修改一下 Cgroup

说明一下Cgroup drivers:systemd cgroupfs 区别

 那么 systemd 和 cgroupfs 这两种驱动有什么区别呢?

1. systemd cgroup driver 是 systemd 本身提供了一个 cgroup 的管理方式,使用systemd 做 cgroup 驱动的话,所有的 cgroup 操作都必须通过 systemd 的接口来完成,不能手动更改 cgroup 的文件

2. cgroupfs 驱动就比较直接,比如说要限制内存是多少、要用 CPU share 为多少?直接把 pid 写入对应的一个 cgroup 文件,然后把对应需要限制的资源也写入相应的 memory cgroup 文件和 CPU 的 cgroup 文件就可以了

所以可以看出来 systemd 更加安全,因为不能手动去更改 cgroup 文件,当然我们也推荐使用 systemd 驱动来管理 cgroup。

 

 

 

 

同时未必保证修改kubelet 

cgroupDriver: systemd

 

通过systemd-cgls命令我们可以看到systemd工作的进程PID是1,而目录/sys/fs/cgroup/systemd是systemd维护的自己使用的非subsystem的cgroups层级结构

查考文档:

https://blog.csdn.net/avatar_2009/article/details/109603870

https://github.com/containerd/containerd/issues/4900

https://www.pianshen.com/article/89821412857/


cat <<EOF > /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStartPre=/sbin/modprobe br_netfilter
ExecStart=/usr/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
[Install]
WantedBy=multi-user.target
EOF
systemctl enable containerd
systemctl restart containerd
systemctl status containerd

安装完成,就可以使用ctr客户端工具测试

containerd 相比于docker , 多了namespace概念, 每个image和container 都会在各自的namespace下可见
默认k8s使用的镜像都放置到 k8s.io 这个名称空间,使用离线镜像尽量导入到这个名词空间

https://github.com/containerd/containerd/blob/master/docs/namespaces.md

私用仓库的调用用户名和密码认证方式是:

ctr i pull -u "devops:xxxx" harbor.xxx.net/devops/pause:3.2

如果不想一直输入密码,可以增加配置文件

 vim /etc/containerd/config.toml

ctr -n k8s.io images ls 

ctr --namespace=k8s.io i tag harbor.xxx.net/devops/pause:3.2 k8s.gcr.io/pause:3.2

crictl是一个命令行接口,用于与CRI兼容的容器运行时

https://kubernetes.io/zh/docs/tasks/debug-application-cluster/crictl/

需要安装相应的工具包

cat <<EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF

使用K8S 离线包:

crictl pull --creds devops:xxxx  harbor.xxx.net/devops/pause:3.2 

 

 看到的镜像一个和ctr -n k8s.io i ls  看到的镜像是一样的

目前官网支持的几种容器运行时的安装方式:

https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#containerd

 

 

 

虽然未来 Kubelet 删除 dockershim 支持,但并不说明 Docker 马上就不能在 Kubernetes 中使用,目前容器市场 Docker 还是占用很大的比例。这中间会有一个过渡期,大家可以关注 Containerd 或者 Podman。Centos8 开始,仓库源默认容器已经从 Docker 切换为 Podman

参考文章:

https://blog.51cto.com/juestnow/2440775

https://www.infoq.cn/article/odslclsjvo8bnx*mbrbk

https://www.likecs.com/show-305973752.html#sc=400

https://cloud.tencent.com/developer/article/1895808

https://www.likecs.com/show-132453.html

 

posted @ 2020-12-07 15:24  屌丝的IT  阅读(10718)  评论(0编辑  收藏  举报