一直想搞清楚关于“k8s 弃用 docker 这件事情”,所以才有了这篇学习记录

官方有关这类话题的文章链接:

https://kubernetes.io/zh-cn/blog/2020/12/02/dont-panic-kubernetes-and-docker/

https://kubernetes.io/zh-cn/blog/2020/12/02/dockershim-faq/

Docker Engine 架构

我们需要先看以下当前 docker 引擎的各个组件,我们从最新的二进制安装包提取到相关组件

image-20230221144606213

image-20230221152614730

  1. Docker 相关的组件
    • docker:docker 客户端的一个完整实现,就是docker 命令
    • dockerd:docker 服务端的后台常驻进程,接收客户端发来的请求,执行和转发具体的处理任务,处理完成后将结果返回给客户端
    • docker-init:docker 会使用 docker-init 作为1号进程,帮助管理容器内子进程
    • docker-proxy:用来做端口映射,底层依赖iptables实现
  2. containerd 相关的组件
    • containerd:从 docker 1.11 版本正式从 dockerd 剥离出来,独立存在,完全遵循 OCI 标准,是容器标准化的产物
      • 负责容器生命周期管理
      • 镜像管理
      • 接收dockerd的请求,通过适当的参数调用runc启动容器
      • 管理存储相关资源
      • 管理网络相关资源
      • 可以不通过dockerd管理容器,可以直接使用containerd来管理
    • containerd-shim:垫片的意思,将containerd与真正的容器进程进行解耦,使用containerd-shim作为容器进程的父进程,从而实现重启containerd不影响已经启动的容器进程
    • ctr:是containerd的客户端,主要用来开发和调试,没有dockerd的环境,这个东西可以用来充当客户端的部分角色
  3. 容器运行时相关的组件
    • runc:是一个标准的 OCI 容器运行时的实现,是一个命令行工具,可以直接用来创建和运行容器

容器运行时 containerd

在上面docker的架构中,可以看出:

  • Docker 引擎包含了containerd
  • containerd 专注于运行时的容器管理
  • Docker 除了容器管理之外,还可以完成镜像构建之类的功能
  • containerd 并不适合直接面向用户使用,适用于集成到更上层的系统里,比如:k8s、docker等容器编排系统

k8s 中的 kubelet 架构

通过之前的学习过程,知道在 k8s 中

  • kubelet 负责维护容器的生命周期,同时也负责 Volume(CSI)和网络(CNI)的管理;

Kuberentes 架构(图片来自于网络)

从上面这个图可以看出来

  • 在 k8s 架构中,是通过kubelet这个组件,使用CRI接口与容器运行时进行一个交互,

什么是 CRI

CRI 是一个插件接口,它使 kubelet 能够使用各种容器运行时,你需要在集群中的每个节点上都有一个可以正常工作的容器运行时, 这样 kubelet 能启动 Pod 及其容器。容器运行时接口(CRI)是kubelet 和容器运行时之间通信的主要协议

为何放弃使用 Docker Engine

这里的放弃使用Docker Engine,指的是使用Docker Engine作为容器运行时

容器运行时

不管什么工具,Docker、k8s 在运行一个容器的时候都会调用容器运行时(CRI),通过容器运行时来完成容器的生命周期管理

  • Docker Engine使用的就是containerd

  • k8s 在1.24版本之前支持Docker Engine

  • k8s 支持containerdCRI-O等多种容器运行时,这些容器运行时都遵循了 OCI 规范,并通过runc来实现于操作系统内核交互完成容器的生命周期管理

  • 但是Docker Engine不遵循 OCI 规范,因为他最终也还是通过containerd去操作的

k8s 调用链

  1. 在 k8s 早期,那个时候的容器运行时没有太大选择,Docker Engine就是使用容器的主要工具,k8s 早期也仅支持这一种形式

  2. 经过发展,k8s 需要添加更多的容器运行时,来让用户自己选择自己的运行时,比如:rkthypernetes等,CRI 的引入对 k8s 项目和用户来说都很棒,但是Docker Engine 作为容器运行时的使用早于 CRI,并且 Docker Engine 不兼容 CRI,为了解决这个问题,k8s 的核心组件kubelet就引入了一个小型软件dockershim,专门用于填补 Docker EngineCRI 之间的空白,允许集群操作员继续使用Docker Engine 作为他们的容器运行时基本上不间断,这个时候kubelet的调用链将会是:

    kubelet --> dockershim (在 kubelet 进程中) --> dockerd --> containerd

  3. 然而这个东西给kubelet本身带来了许多不必要的复杂性,由于这个shimDocker 的一些集成实现不一致,导致维护人员的负担增加,并且维护特定于供应商的代码不符合 k8s 的开源理念

  4. 这个事情一度的发酵和提起,迎来了最终的一个结果:

    k8s 在1.24版本之后不在支持Docker Engine运行时,而是采用containerd

  5. containerd 作为 k8s 容器运行时,调用链将会变成:

    kubelet --> cri plugin(在 containerd 进程中) --> containerd

  6. 如果使用 containerd 作为 k8s 容器运行时的话, kubelet 可以直接调用 containerd

    • 性能提高了(调用链变短了)
    • 资源占用也变小了

image-20230221163530664

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐