Kubernetes容器运行时弃用Docker转型Containerd

Kubernetes社区在2020年7月份发布的版本中已经开始了dockershim的移除计划,在1.20版本中将内置的dockershim进行分离,这个版本依旧还可以使用dockershim,但是在1.24中被删除。从1.24开始,大家需要使用其他受到支持的运行时选项(例如containerd或CRI-O);如果选择Docker Engine作为运行时,则需要使用cri-dockerd

文章目录

  • 容器进行时调用过程
  • Kubernetes 1.20 版本开始将弃用 Docker,是时候拥抱 Containerd 和 Podman 了!
  • CRI 详解
  • Containerd 发展史
  • 哪些容器运行时引擎支持CRI?
  • Containerd
  • Containerd 安装
  • 容器进行时调用过程

    1651113933261.png

    起因

        <img alt>
    
            <img alt>
    
                圈子话题

    Kubernetes 1.20 版本开始将弃用 Docker,是时候拥抱 Containerd 和 Podman 了!

    当Docker要创建一个容器时,需要进行下面的步骤:

    1652382926896.png
  • Kubelet 通过CRI接口(gRPC)调用dockershim,请求创建一个容器。(CRI即容器运行时接口)
  • dockershim 收到请求后,转换成Docker Daemon能听懂的请求,发到Docker Daemon上请求创建容器。
  • Docker Daemon 早在1.12版本中就已经针对容器的操作转移到另外一个进程--containerd,因此Docker Daemon不会帮我们创建容器,而是要求containerd创建一个容器
  • Containerd收到请求后,并不会直接去操作容器,而是创建一个叫做containerd-shim的进程,让containerd-shim去操作容器。这是因为容器进程需要一个父进程来做收集状态,而加入这个父进程就是containerd,那每次containerd挂掉或者升级,整个宿主机上的容器都会退出。而引用containerd-shim就避免了这个问题 (containerd和shim并不是父子进程的关系)
  • OCI (Open Container Initiative,开放容器标准)。OCI执行namespace和cgroups,挂载root filesystem等操作,OCI参考RunC,containerd-shim在这一步调用RunC命令行来启动容器。实际上RunC就是一个二进制命令
  • runC启动完成后本身会直接退出,containerd-shim则会为容器进程的父进程,负责收集容器进程的状态,上报给containerd,并在容器中pid为1的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程
  • OCI (Open Container Initiative,开放容器标准) runC实际上就是参考OCI实现,OCI实际上就是一个标准文档,主要规定了容器镜像的结构、以及容器需要接收那些操作指令,比如create、start、stop、delete等

    实际上我们是可以直接通过调用RunC来实现容器的创建,实际上RunC就是调用的我们内核来进行操作。但是我们直接调用Runc不是很方便,所以就有了OCI。不需要了解底层原理,也可以通过调用OCI来进行容器的创建 containerd-shim则会为容器进程的父进程,负责收集容器进程的状态,上报给containerd,并在容器中pid为1的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程

    [root@k8s-01 ~]# ps -ef|grep docker
    root      1100     1  1 Apr19 ?        05:43:15 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
    root      1425  1043  0 Apr19 ?        00:00:50 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/306ca6264fdd2bf673b65ba64ef91b9ec4357cb7a21545085199826ad991a3f1 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup
    root      2120  1043  0 Apr19 ?        00:00:46 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/b608189a56350e04d20057f4b4158fe1ef0e6521ecae4030fdc5b03d7cee55c2 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup
    root      2121  1043  0 Apr19 ?        00:00:51 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/847c04dc6aa2ba3e2df261629dee8ff934b27a548392d928c8737f29688ddd1f -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup
    ...

    通过ps -ef过滤docker,我们可以看到docker中实际上就是通过containerd-shim来创建的

    containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/306ca6264fdd2bf673b65ba64ef91b9ec4357cb7a21545085199826ad991a3f1 -address /run/containerd/containerd.sock -containerd-binary

    containerd-shim垫片的主要作用是用于containerd与Runc的匹配CRI-shim垫片主要用于kubelet与containerd之间的匹配,并且两者之间没有任何关联

    CRI 详解

    为什么在Kubernetes 1.20之后不推荐使用docker了?可以继续往下看

    在Kubernetes早起的时候,Kubernetes为了支持Docker,通过硬编码的方式直接调用Docker API。后面随着Docker的不断发展以及Google的主导,出现了更多容器运行时可以使用,Kubernetes为了支持更多精简的容器运行时,google就和redhat主导推出了OCI标准,用于将Kubernetes平台和特定的容器运行时解耦 CRI (Container Runtime Interface容器运行时接口)本质就是Kubernetes定义的一组与容器运行时进行交互的接口 CRI实际上就是一组单纯的gRPC接口,核心有如下:

  • RuntimeService 对容器操作的接口,包括创建,启停容器等
  • ImageService 对镜像操作的接口,包括镜像的增删改查等
  • 可以通过kubelet中--container-runtime-endpoint和--image-service-endpoint来手动配置 官方文档:https://kubernetes.io/zh/docs/concepts/architecture/cri/https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/ CRI大概通过了下面的几个项目构成了Kubernetes的Runtime生态

  • OCI Compatible: runC
  • CRI Compatible: Docker (借助dockershim),containerd (借助CRI-containerd)
  • 由于早期Kubernetes在市场没有主导地位,有一些容器运行时可能不会自身实现CRI接口,于是就有了shim,一个shim的职责就是作为适配器,将各种容器运行时的本身的接口适配到Kubernetes的CRI接口上

    1652383957048.png

    cri-runtime主要为了取消docker

    cri-runtime和oci-runtime 容器运行时实际上调用步骤如下

    Orchestration API -> Container API(cri-runtime) -> Kernel API(oci-runtime)

    Kubelet通过gRPC 框架与容器运行时或shim进行通信,其中 kubelet 作为客户端,CRI shim(也可能是容器运行时本身)

    Containerd 发展史

    在Containerd 1.0中,对CRI的适配通过了一个单独的进程CRI-containerd来完成

    1651132339322.png

    containerd 1.1中,砍掉了CRI-containerd这个进程,直接把适配逻辑作为插件放进了containerd主进程中1651132383683.png containerd 1.1中做的事情,实际上Kubernetes社区做了一个更漂亮的cri-o,兼容CRI和OCI1652385959558.png Containerd与Docker区别?

    实际上containerd只是一个精简版docker,为了更好的支持Kubernetes而已

    1651115028474.png

    哪些容器运行时引擎支持CRI?

    容器运行时 Kubernetes 平台中的支持 优点 缺点
    Containerd 谷歌 Kubernetes 引擎、IBM Kubernetes 服务、阿里巴巴 经过大规模测试,用于所有 Docker 容器。比 Docker 使用更少的内存和 CPU。支持 Linux 和 Windows 没有 Docker API 套接字。缺少 Docker 方便的 CLI 工具。
    CRI-O 红帽 OpenShift,SUSE 容器即服务 轻量级,Kubernetes 所需的所有功能,仅此而已。类似 UNIX 的关注点分离(客户端、注册表、构建) 主要在RedHat平台内使用不易安装在非RedHat操作系统上仅在Windows Server2019及更高版本中支持
    Kata Containers 开放堆栈 提供基于 QEMUI 的完全虚拟化改进的安全性与 Docker、CRI-O、containerd 和 Firecracker 集成支持 ARM、x86_64、AMD64 更高的资源利用率不适合轻量级容器用例
    AWS Firecracker 所有 AWS 服务 可通过直接 API 或使用 seccomp jailer 的 containerdTight 内核访问来访问 新项目,不如其他运行时成熟需要更多手动步骤,开发人员体验仍在不断变化