Kubernetes容器运行时:Containerd vs Docke(kubernetes容器化)

Kubernetes容器运行时:Containerd vs Docke 容器化技术笔记 Kubernetes容器运行时:Containerd vs Docke –
文章信息 –
Author: 李俊才 (jcLee95)

容器化技术说明

Kubernetes 容器运行时:Containerd 和Docker

文章信息-

作者: 李俊才(jcLee95)

访问CSDN: https://jclee95.blog.csdn.net。

我的网站:http://thispage.tech/

邮箱: 291148484@163.com。

中国深圳

本文地址:https://blog.csdn.net/qq_28550263/article/details/139843224

华为:https://bbs.huaweicloud.com/blogs/429461

【简介】:本文介绍了Kubernetes 容器运行时的比较:Containerd 和Docker。

目录

1. 概述1.1 容器运行时在Kubernetes 中的作用1.2 主流容器运行时概述

2. Containerd 与Docker 的关系2.1 Containerd 的起源2.1.1 从Docker 子组件到独立项目2.1.2 Containerd 的定位和目标

2.2 **Containerd** 在**Docker** 架构中的地位2.2.1 Docker 组件架构2.2.2 Containerd 在架构中的作用

2.3 Kubernetes 为何放弃Dockershim 2.3.1 Docker 版本更新难以适应2.3.2 Kubernetes 对更轻量级运行时的需求

3. Kubernetes 中Containerd 与Docker 的区别3.1 架构及调用环节3.1.1 Docker 作为Kubernetes 容器运行3.1.2 Containerd 作为Kubernetes 容器运行3.1.3 架构对比及优缺点分析

3.2 容器创建和网络管理3.2.1 暂停容器创建3.2.2 CNI插件调用3.2.3 网络配置差异及影响

3.3 容器日志管理3.3.1 日志放置职责**Docker****Containerd**3.3.2 日志保留策略**Docker****Containerd**3.3.3 日志路径和格式**Docker** * *容器**

3.4 Container Exec 和Probe3.4.1 Container Exec **Docker** 的Exec 实现**Containerd** 的Exec 实现的行为和影响的差异

3.4.2 容器Probe**Docker** 的探针实现与**Containerd** 的探针实现之间的行为和影响差异

3.4.3 对启停操作的影响

4. **Containerd** 和**Docker** 之间如何选择4.1 **Kubernetes**的运行时要求4.2 **Containerd**的优点4.3 Docker4.4 的适用场景迁移到Containerd 的注意点

5. 结论F. 附录F.1 命令对照表F.2 参考资料

1. 概述

容器运行时是容器技术堆栈的关键组成部分,在Kubernetes 中发挥着关键作用。本节介绍容器运行时的基本概念及其在Kubernetes 集群中的主要作用。

1.1 容器运行时在Kubernetes中的作用

在Kubernetes 中,每个节点上运行一个称为Kubelet 的核心组件。 Kubelet负责管理节点上的pod和容器,这些管理操作必须通过特定的容器运行时来完成。作为Kubelet 和容器之间的桥梁,容器运行时为Kubernetes 提供了一组基本功能。

容器生命周期管理:容器运行时管理容器的整个生命周期,包括创建、启动、停止和删除容器。当Kubelet 需要创建或销毁pod 时,实际的容器管理操作由容器运行时执行。

镜像管理:容器运行时从镜像仓库中检索镜像并管理节点上的本地镜像存储。创建Pod 时,容器运行时会检查所需的镜像是否已存在,如果不存在,则从指定的镜像仓库中检索该镜像。

容器文件系统和网络管理:容器运行时为每个容器提供独立的文件系统和网络命名空间。负责准备容器的根文件系统、挂载卷、配置容器网络,并确保不同容器之间的文件系统和网络隔离。

资源限制和安全隔离:容器运行时负责设置容器的资源限制,例如CPU和内存使用的限制。同时,也保证了容器之间、容器与主机之间的安全隔离,防止恶意容器危害其他容器或主机。

简而言之,容器运行时是连接Kubernetes 和底层容器实现的主要组件,提供容器生命周期管理、镜像管理、存储和网络管理、资源隔离等多方面的支持。这是Kubernetes 的关键。 “管理和编排大型容器集群的能力是关键基础。

1.2 主流容器运行时介绍

在Kubernetes的发展过程中,出现了多种容器运行时解决方案,每种解决方案在功能、性能、生态等方面都有独特的特点。两个最流行的容器运行时是:

Docker:Docker是最早普及容器技术的引擎,曾在早期版本的Kubernetes中被用作默认的容器运行时。 Docker 提供强大的镜像构建、容器管理功能和丰富的工具生态系统,以快速推进容器技术。然而,Docker作为一个完整的平台,在功能和规模上都比较臃肿,占用系统资源较多。同时,Docker的发展路线图与Kubernetes并不完全契合,给Kubernetes版本的迭代和适配带来了一定的挑战。

Containerd:Containerd 是一个更轻量级、标准化的容器运行时,源自Docker 项目,后来又从Docker 项目中分离出来。

成为一个独立的开源项目。 Containerd 专注于提供简单、可靠、高性能的容器执行引擎,遵循OCI(开放容器倡议)等行业标准,提供更加可控和可移植的容器编排系统,提供广泛的运行时选项。 Containerd 删除了Docker 的许多面向最终用户的功能,例如Docker 构建和Docker Push,而是专注于运行和管理容器等核心功能。这种关注使得Containerd 显着提高了资源利用率和稳定性,并逐渐成为Kubernetes 社区首选的容器运行时实现。

从Kubernetes 1.20 版本开始,Containerd 是默认的容器运行时。许多Kubernetes 发行版和托管服务也开始使用Containerd 作为首选运行时。 Containerd 简单、专注的设计以及对OCI 标准的原生支持使其成为Kubernetes 等大规模容器编排平台的理想选择。

总之,容器运行时作为Kubernetes 和实际容器实现之间的桥梁发挥着至关重要的作用。 Docker和Containerd代表了两种不同的技术路线。 Docker功能丰富,拥有完整的生态系统,但有点臃肿。 Containerd专注于容器的核心功能,使其更加轻量、可控。随着Kubernetes的不断发展,Containerd等轻量级容器运行时正在成为主流选择。但Docker由于其成熟的生态系统和强大的功能,在某些场景下仍然具有独特的价值。

选择容器运行时时,应综合考虑稳定性、性能、资源利用率等因素,权衡不同方案的优缺点。在某些情况下,您甚至可以混合使用它们以充分发挥各自的优势。无论您选择哪种容器运行时,做出正确的选择都很重要,因为它的可靠性和性能直接影响Kubernetes 集群的整体运行状况。

2. Containerd 与 Docker的关系

要了解Containerd和Docker的关系,首先要了解Containerd的起源和发展历史以及它在Docker架构中的地位。本节详细介绍Containerd 和Docker 的起源和演变。

2.1 Containerd的由来

Containerd 最初是作为Docker 的子组件诞生的。在Docker的早期版本中,Containerd已经存在,负责管理容器的生命周期。但随着Docker功能的不断增强和版本迭代,Containerd已经逐渐演变成一个相对独立的组件。

2.1.1 从Docker的子组件到独立项目

2016年,Docker决定将Containerd从Docker中分离出来,使其成为一个独立的开源项目。这一决定的主要目的是让Containerd专注于提供标准化的容器运行时和管理能力,而不是将它们与Docker的其他功能结合起来。

2.1.2 Containerd的定位和目标

作为一个独立项目,Containerd 的目标是提供一个简单、可靠、可移植的容器运行时,可以与更高级别的容器编排系统一起使用。 Containerd 遵循开放容器计划(OCI) 等行业标准,并致力于成为Kubernetes 等编排引擎的首选运行时。

2.2 Containerd在Docker架构中的位置

尽管Containerd现在是一个独立的项目,但它仍然是Docker架构中不可或缺的一部分。了解Containerd在Docker中的地位有助于理解两者之间的关系以及各自的职责。

2.2.1 Docker的组件架构

Docker 由多个组件组成,包括:

Docker-client:用户与Docker交互的命令行工具。 Dockerd:Docker 的核心守护进程。与Docker 客户端交互并管理图像和网络等资源。 Containerd:负责管理容器的生命周期,包括创建、启动和停止容器。 runc:用于实际启动和运行容器的轻量级容器运行时。

2.2.2 Containerd在架构中的作用

在Docker 架构中,Containerd 位于Dockerd 和runc 之间,充当过去和未来的纽带。

相反,Containerd 向Dockerd 提供API 来管理容器生命周期。相比之下,Containerd 通过shim(例如Containerd-shim)调用runc 来实际创建和运行容器。

因此,Containerd 是Docker 的高层组件和底层容器运行时之间的关键链接。

2.3 Kubernetes弃用Dockershim的原因

Kubernetes 最初是使用Dockershim 适配器与Docker 集成的。然而,随着Kubernetes 的发展,社区决定放弃Dockershim,转而直接与更轻量级、标准化的容器运行时(例如Containerd)集成。

2.3.1 Docker版本更新带来的适配困难

Docker作为一个完整的容器平台,更新频繁,功能变化很快。这对Kubernetes 的适配工作提出了挑战。每次Docker 发布新版本时,Kubernetes 都必须更新Dockershim 以确保兼容性。

2.3.2 Kubernetes对更轻量级运行时的需求

作为容器编排平台,Kubernetes 实际上并不需要Docker 提供的所有功能。 Kubernetes还需要一个简单、可靠、易于集成的容器运行时。 Containerd 正好满足了这个需求。它专注于容器的核心功能,并删除了许多不必要的功能,使其更加轻量级和高效。

因此,Kubernetes 社区决定逐步淘汰Dockershim,转而直接与更轻量级的容器运行时集成,例如Containerd。这一决定不仅简化了Kubernetes 架构,还提高了性能和稳定性。

综上所述,Containerd 和Docker 有着密不可分的关系。 Containerd 最初是Docker 的一个子组件,后来发展成为一个独立的项目。尽管如此,它仍然是Docker架构的重要组成部分,负责管理容器生命周期。同时,Containerd 轻量级、标准化,因此逐渐成为Kubernetes 等容器编排平台的首选运行时。基于这样的考虑,Kubernetes社区决定放弃Dockershim,转而直接与Containerd集成。

3. Kubernetes 中 Containerd 与 Docker 的区别

3.1 架构和调用链路

当使用Containerd和Docker作为Kubernetes的容器运行时时,它们的内部架构和调用链路是不同的。本节详细分析这两个运行时如何工作以及Kubernetes 如何处理。

3.1.1 Docker作为Kubernetes容器运行时

当Docker作为Kubernetes容器运行时,其调用链接如下所示:

Kubelet – Dockershim – Dockerd – Containerd

Kubelet:Kubelet是每个Kubernetes节点的核心组件,负责管理节点上的pod和容器。

Dockershim:Dockershim 是Kubernetes 的适配器组件,驻留在Kubelet 中。 Dockershim 的作用是将Kubelet 容器管理请求转换为Docker 守护进程(Dockerd)可以理解的API 调用。

Dockerd:Dockerd 是Docker 的核心守护进程,负责处理Dockershim 请求并管理Docker 镜像、网络和存储等资源。

Containerd:Containerd是一个独立的容器运行时,负责实际的容器生命周期管理,包括创建、启动、停止和删除容器。在这个架构中,Dockerd将容器管理任务委托给Containerd。

使用Docker作为Kubernetes的容器运行时时,请求必须经过多个组件的转发和处理,导致调用链路相对较长。这种架构与之前的Docker 版本兼容,但也引入了额外的复杂性和性能开销。

3.1.2 Containerd作为Kubernetes容器运行时

当Containerd作为Kubernetes容器运行时,其调用链接如下所示:

Kubelet-cri插件-Containerd

Kubelet:与使用Docker 类似,Kubelet 管理节点上的Pod 和容器。

CRI插件:CRI(Container Runtime Interface)是Kubernetes定义的一组用于与容器运行时交互的标准接口。使用Containerd 时,Kubelet 通过内置的CRI 插件直接与Containerd 通信。 CRI 插件将Kubelet 请求转换为Containerd 可以理解的gRPC 调用。

Containerd:Containerd直接处理来自CRI插件的请求,管理容器生命周期,并通过shims(例如Containerd-shim)启动和管理容器。

相比于使用Docker,Containerd 是Kubernetes 容器运行时更加简洁、直接的调用环节。 Kubelet通过CRI插件直接与Containerd通信,减少了中间组件的开销。这种架构更轻,组件之间的耦合更低,提高了整体稳定性和性能。

3.1.3 架构对比和优劣分析

对比Containerd和Docker for Kubernetes的架构和调用链路,可以发现以下差异:

调用链路长度:使用Docker时,请求需要经过Dockershim、Dockerd等多个组件转发,导致调用链路较长。使用Containerd时,Kubelet通过CRI插件直接与Containerd通信,使得调用链接更加简洁。

组件复杂性:作为一个完整的容器平台,Docker 包含了许多Kubernetes 不需要的功能,这增加了复杂性。 Containerd 专注于容器运行时的核心功能,其组件更加精简。

资源占用:Docker包含的组件和功能较多,因此资源占用相对较高。当Containerd 作为轻量级容器运行时,它使用的资源更少,对系统的影响也更小。

稳定性:使用Docker时,由于调用环节较长,涉及的组件较多,出现问题的可能性比较大。 Containerd 的架构更简单,组件之间的耦合更少,因此通常更稳定。升级和维护:Docker版本更新频繁,每次更新都会引入新的功能和变化,给Kubernetes的适配和维护带来挑战。 Containerd 由于其更稳定的功能和接口,相对容易升级和维护。 总的来说,Containerd是专门为容器编排设计的运行时,架构简单、调用链路短、资源占用低、稳定性好。这些优势使Containerd 成为Kubernetes 社区首选的容器运行时选择。

然而,这并不意味着Docker 对Kubernetes 毫无用处。在某些场景下使用Docker 作为容器运行时,例如当您需要使用Docker 提供的独特功能(例如docker build、docker push 等)或需要与现有Docker 工作流程集成时。这仍然是一个可行的选择。

此外,对于已经大规模使用Docker 的Kubernetes 集群,直接切换到Containerd 可能会产生一定的迁移成本和风险。这种情况下,可以考虑采用分阶段的迁移策略,比如在现有节点上继续使用Docker,在新的节点或集群上使用Containerd,直到迁移到Containerd完成。

3.2 容器创建和网络管理

在Kubernetes 中,容器创建和网络管理是通过Pause 容器和CNI 插件来实现的。 Pause容器为业务容器提供网络命名空间,CNI插件负责配置容器网络。 Containerd 和Docker 在这两方面存在细微的差别。

3.2.1 Pause容器的创建

在创建业务容器之前,Kubernetes 首先创建一个名为Pause 的特殊容器。 Pause容器的主要功能是为业务容器提供网络命名空间,以便同一pod内的容器可以共享网络堆栈。 Containerd 和Docker 在创建Pause 容器时存在一些差异。

Docker:当您使用Docker 作为容器运行时时,Docker 在暂停容器创建过程中会自动关闭容器内的IPv6 支持。具体来说,Docker 在容器的网络命名空间中将内核参数net.ipv6.conf.all.disable_ipv6 设置为1。这意味着默认情况下,使用Docker 创建的容器只能使用IPv4。

Containerd:如果您使用Containerd 作为容器运行时,暂停容器创建过程不需要关闭IPv6。默认情况下,Containerd 创建的挂起容器同时启用IPv4 和IPv6。

这种差异可能会导致网络行为的一些差异。例如,使用Containerd 时,如果集群上启用了IPv6,则Pod 中的容器可以直接使用IPv6 进行通信。使用Docker 时,即使集群中启用了IPv6,Pod 中的容器默认也只能使用IPv4 通信。

3.2.2 CNI插件的调用

在Kubernetes 中,容器网络配置是通过CNI(Container Network Interface)插件实现的。 CNI定义了一组用于配置和管理容器网络的标准接口。当Kubernetes 创建pod 时,它会调用CNI 插件来配置pod 的网络。 Containerd 和Docker 调用CNI 插件的方式略有不同。

Docker:当使用Docker作为容器运行时时,CNI插件的调用是由Kubelet内的Dockershim完成的。具体来说,Dockershim根据Kubelet配置(如–cni-bin-dir和–cni-conf-dir参数)调用相应的CNI插件来配置容器的网络。

Containerd:使用Containerd作为容器运行时时,CNI插件的调用是通过Containerd内置的CRI插件完成的。 Containerd CRI 插件调用指定的CNI 插件,根据配置文件(config.toml) 的cni 部分为容器配置网络。

虽然Containerd和Docker在CNI插件调用的实现细节上有所不同,但最终达到的效果是相同的。也就是说,为Pod 内的容器配置适当的网络。

3.2.3 网络配置的差异和影响

Containerd 和Docker 在暂停容器创建和调用CNI 插件方面存在一些差异,这可能会导致网络配置和行为上的一些差异。主要区别和影响是:

IPv6 支持:如前所述,使用Docker 创建的容器默认仅启用IPv4,而使用Containerd 创建的容器默认启用IPv4 和IPv6。这意味着对于支持IPv6 的集群,Containerd 允许您直接利用IPv6 进行Pod 内和Pod 间通信,但Docker 需要额外的配置。

DNS 解析:在某些情况下,Pod 内的DNS 解析行为可能会因IPv6 启用状态不同而有所不同。例如,如果您的应用程序在进行DNS 解析时更喜欢使用IPv6 地址,则在使用Docker 时可能会遇到问题,因为Docker 默认情况下禁用IPv6。

网络性能:Containerd 和Docker 之间的网络性能可能存在细微差异。这主要取决于各自网络堆栈的实现和优化。总的来说,Containerd是为Kubernetes设计的,所以网络性能可能会更好。然而,具体的性能差异必须通过基准测试来评估。

网络插件兼容性:Containerd 和Docker 都支持CNI 标准,但与特定CNI 插件的兼容性可能会有所不同。选择网络插件时,您应该确保它与您使用的容器运行时兼容并且已经过适当的测试。

3.3 容器日志管理

容器日志是了解容器内应用程序执行状态的重要方式。在Kubernetes 中,容器日志的管理方式取决于所使用的容器运行时。本节重点介绍Containerd和Docker在容器日志管理方面的异同。

3.3.1 日志落盘责任

将容器日志写入磁盘或将日志写入磁盘的过程对于Containerd 和Docker 来说是不同的。

Docker

当使用Docker 作为容器运行时时,Docker 守护进程(Dockerd)负责存储容器日志。尤其:

容器内的应用程序将日志打印到stdout 和stderr。 Dockerd 捕获这些日志并将它们写入主机的文件系统。日志文件路径通常为/var/lib/Docker/containers/container-id/container-id-json.log。

Dockerd 管理日志文件的生命周期,包括日志轮换和清理。

Containerd

当使用Containerd作为容器运行时时,Kubelet负责存储容器日志。具体流程如下。

与Docker 类似,容器内的应用程序将日志打印到stdout 和stderr。 Containerd 捕获这些日志并通过CRI 接口将其传递给Kubelet。 Kubelet将日志写入主机

的文件系统,日志文件的路径通常为/var/log/Pods/<namespace>_<Pod-name>_<Pod-uid>/<container-name>/0.log。
在这种情况下,Kubelet负责管理日志文件的生命周期,包括日志的轮转和清理等。

3.3.2 日志保留策略

日志保留策略决定了容器日志在宿主机上的存储时间和占用空间。Containerd和Docker对日志保留策略的默认配置有所不同。

Docker

在Docker中,日志保留策略由Docker Daemon的配置参数控制:

–log-driver:指定日志驱动,默认为json-file。–log-opts:指定日志驱动的选项,如max-size和max-file等。
默认情况下,Docker会为每个容器保留1GB的日志,并在达到这个限制时进行轮转。可以通过调整–log-opts参数来更改这个默认行为。

Containerd

在Containerd中,日志保留策略由Kubelet的配置参数控制:

–container-log-max-size:指定单个容器日志文件的最大大小,默认为10MB。–container-log-max-files:指定单个容器最多保留的日志文件数量,默认为5个。
这意味着,在默认配置下,Kubelet为每个容器最多保留50MB的日志(10MB * 5个文件)。当日志文件达到–container-log-max-size指定的大小时,Kubelet会对其进行轮转。

需要注意的是,这些默认值可能因Kubernetes版本和发行版而有所不同。用户可以根据实际需求调整这些参数,以平衡日志保留时间和磁盘空间的占用。

3.3.3 日志路径和格式

除了日志落盘责任和保留策略外,Containerd和Docker在日志路径和格式方面也有一些差异。

Docker

在Docker中,容器日志的路径和命名格式如下:

路径:/var/lib/**Docker**/containers/<container-id>/<container-id>-json.log格式:JSON格式,每行代表一条日志记录。
Docker使用JSON格式记录日志,便于日志的解析和检索。每条日志记录包含了诸如时间戳、日志级别、容器ID等元数据信息。

Containerd

在Containerd中,容器日志的路径和命名格式如下:

路径:/var/log/**Pod**s/<namespace>_<**Pod**-name>_<**Pod**-uid>/<container-name>/0.log格式:纯文本格式,不包含额外的元数据。
与Docker不同,Containerd采用纯文本格式记录日志,每行代表一条日志记录,不包含额外的JSON元数据。这种格式更加简洁,但在某些情况下可能不如JSON格式灵活。

需要注意的是,在Kubernetes中,可以通过配置日志代理(如Fluentd、Filebeat等)来收集和转发容器日志,并对其进行结构化处理和分析。这样可以弥补Containerd日志格式简洁的不足,提供更强大的日志管理功能。

3.4 容器Exec和Probe

在Kubernetes中,容器的Exec(执行命令)和Probe(健康检查)是两个常用的功能。Containerd和Docker在实现这两个功能时略有不同,这可能会导致某些场景下的行为差异。本节将重点分析这两种容器运行时在Exec和Probe方面的区别。

3.4.1 容器Exec

容器Exec是指在容器运行时执行一个命令,通常用于调试、故障排查或一些特定的操作。在Kubernetes中,可以通过kubectl exec命令在容器内执行命令。

Docker的Exec实现

在Docker中,当执行**Docker** exec命令时,Docker会在容器内创建一个新的进程来执行指定的命令。这个新进程与容器的主进程(PID 1)是独立的。Docker的Exec实现有以下特点:

独立进程:Exec命令会在容器内创建一个独立的进程,该进程与容器的主进程是分离的。退出状态:Docker的Exec命令的退出状态取决于所执行命令的退出状态。即使容器的主进程仍在运行,只要Exec命令执行完毕并退出,Docker就认为本次Exec操作已经结束。

Containerd的Exec实现

Containerd的Exec实现与Docker略有不同。在Containerd中,Exec命令的行为更加严格,更加符合Kubernetes的预期。Containerd的Exec实现有以下特点:

进程组:Containerd的Exec命令会在容器内创建一个新的进程组,该进程组与容器的主进程组是同级的。退出状态:Containerd的Exec命令的退出状态取决于整个进程组的退出状态。只有当Exec命令创建的所有进程都退出后,Containerd才认为本次Exec操作结束。

行为差异和影响

由于Docker和Containerd在Exec实现上的差异,在某些场景下可能会导致不同的行为:

长时运行的Exec命令:如果在容器内执行一个长时运行的命令(如sleep 1000),在Docker中,由于Exec命令是独立进程,所以kubectl exec会立即返回,而容器内的sleep进程会继续运行。但在Containerd中,kubectl exec会一直等待,直到sleep进程结束。
Exec命令的退出状态:在Docker中,Exec命令的退出状态只取决于该命令本身的执行结果。而在Containerd中,只有当Exec命令创建的所有进程都退出后,才会返回最终的退出状态。

3.4.2 容器Probe

容器Probe是Kubernetes用于检查容器健康状态的机制,包括livenessProbe(存活探针)和readinessProbe(就绪探针)。这些探针可以通过执行命令、发送HTTP请求或检查TCP端口来判断容器的健康状态。

Docker的Probe实现

在Docker中,当Kubelet执行容器的Probe时,它会在容器内创建一个新的进程来执行指定的探测操作(如执行命令或发送请求)。Docker的Probe实现有以下特点:

独立进程:与Exec类似,Probe操作会在容器内创建一个独立的进程,该进程与容器的主进程是分离的。退出状态:Docker的Probe进程的退出状态决定了本次探测的结果。如果进程以0状态码退出,则认为探测成功;否则认为探测失败。

Containerd的Probe实现

Containerd的Probe实现与Exec类似,也是通过创建进程组的方式来执行探测操作。Containerd的Probe实现有以下特点:

进程组:Containerd的Probe操作会在容器内创建一个新的进程组,该进程组与容器的主进程组是同级的。退出状态:Containerd的Probe进程组的退出状态决定了本次探测的结果。只有当Probe操作创建的所有进程都退出后,才会根据最终的退出状态判断探测结果。

行为差异和影响

Docker和Containerd在Probe实现上的差异可能会导致以下行为差异:

Probe超时:如果容器的Probe操作设置了超时时间,在Docker中,一旦超时,Probe进程就会被强制终止,并认为本次探测失败。但在Containerd中,即使超时,Probe进程组也不会被立即终止,而是等待所有进程自然退出。这可能导致实际的探测时间超过设定的超时时间。
Probe退出状态:与Exec类似,在Docker中,Probe进程的退出状态只取
决于该进程本身的执行结果。而在Containerd中,只有当Probe操作创建的所有进程都退出后,才会根据最终的退出状态判断探测结果。

3.4.3 对启动和停止操作的影响

容器的启动(postStart)和停止(preStop)操作是通过Kubernetes的生命周期钩子(Lifecycle Hooks)来实现的。这些钩子可以在容器启动后或停止前执行一些自定义的操作,如数据初始化、资源清理等。

由于Docker和Containerd在Exec和Probe实现上的差异,可能会导致postStart和preStop操作的行为有所不同:

postStart操作:在Docker中,如果postStart操作执行完毕并退出,即使容器的主进程还没有启动,Kubernetes也会认为容器已经启动成功。但在Containerd中,只有当postStart操作创建的所有进程都退出后,Kubernetes才会继续启动容器的主进程。
preStop操作:在Docker中,如果preStop操作执行完毕并退出,即使容器的主进程还在运行,Kubernetes也会认为容器已经停止。但在Containerd中,只有当preStop操作创建的所有进程都退出后,Kubernetes才会继续停止容器的主进程。
这些差异可能会导致容器启动或停止时的行为不一致,特别是当postStart或preStop操作中包含长时运行的命令时。

4. 如何选择Containerd和Docker

在Kubernetes集群中选择使用Containerd还是Docker作为容器运行时,需要综合考虑多方面因素。本节将从Kubernetes对运行时的要求出发,分析Containerd和Docker各自的优势和适用场景,并给出迁移到Containerd的一些注意事项。

4.1 Kubernetes对运行时的要求

Kubernetes作为一个大规模容器编排平台,对容器运行时有一些特定的要求:

稳定性和性能:运行时需要能够稳定、高效地管理大量容器,及时响应Kubernetes的调度和管理请求。频繁的故障或性能瓶颈会直接影响整个集群的可用性。
对OCI标准的支持:为了保证容器的可移植性和互操作性,Kubernetes希望运行时能够支持OCI(Open Container Initiative)标准。符合OCI标准的容器运行时可以无缝地与Kubernetes集成,降低了兼容性风险。
尽量简洁,不需要过多特有功能:Kubernetes主要依赖运行时提供标准化的容器管理能力,并不需要运行时提供过多的特有功能。过于复杂的运行时反而可能带来更多的维护成本和不稳定因素。

4.2 Containerd的优势

相比于Docker,Containerd在满足Kubernetes需求方面有一些明显的优势:

调用链更短,资源占用少,更稳定:如前文所述,使用Containerd时,Kubelet可以通过内置的CRI插件直接与Containerd通信。这种简洁的架构降低了系统复杂度,减少了潜在的故障点。同时Containerd作为一个轻量级运行时,其资源占用也更低,有利于提高节点的可用资源和稳定性。
支持OCI标准,面向Kubernetes设计:Containerd从一开始就致力于成为一个标准化的容器运行时。它完全支持OCI标准,并提供了兼容CRI的接口。这种与Kubernetes的契合,使得Containerd成为Kubernetes社区的优先选择。

总的来说,Containerd专注于提供Kubernetes所需的核心功能,摒弃了Docker中许多不必要的特性。这种专注使其更加轻量、稳定,并且与Kubernetes的集成更加无缝。对于大多数Kubernetes用户来说,Containerd是一个更加合适的选择。

4.3 Docker的适用场景

尽管Kubernetes社区推荐使用Containerd,但这并不意味着Docker就完全没有用武之地。在某些特定场景下,Docker仍然具有独特的价值:

需要使用Docker API、docker build等功能:如果你的工作流严重依赖Docker提供的一些特有功能,如docker build、docker push等,那么继续使用Docker可能是更好的选择。这些功能虽然对Kubernetes来说不是必需的,但在某些开发和CI/CD场景下还是非常有用的。
需要使用Docker Compose或Swarm:如果你的部分工作负载还在使用Docker Compose或Swarm,出于一致性和兼容性考虑,这部分节点可能需要继续使用Docker作为运行时。

需要注意的是,即使你决定在某些节点上继续使用Docker,也可以在其他节点上使用Containerd。Kubernetes支持混合使用多种容器运行时,你可以根据实际需求选择最合适的运行时。

4.4 迁移到 Containerd 的注意事项

如果你决定将现有的Kubernetes集群从Docker迁移到Containerd,有以下几点需要注意:

Kubernetes版本支持:从Kubernetes 1.20版本开始,Dockershim已经被弃用,而在1.24版本中,Kubernetes已经彻底移除了对Dockershim的支持。因此,对于1.24及更高版本的集群,你必须使用其他运行时如Containerd。新建的集群建议直接使用Containerd。
镜像兼容性:Containerd完全兼容Docker镜像格式。这意味着你之前通过Docker构建的所有镜像,在迁移到Containerd后仍然可以继续使用,无需任何修改。
容器网络和日志:由于Containerd和Docker在容器网络和日志管理方面有一些细微差异,迁移后可能会遇到一些问题。例如,容器的IPv6支持状态可能会发生变化,日志的格式和路径也可能不同。你需要仔细测试并排查这些潜在问题。

5. 结论

Containerd和Docker作为Kubernetes的两大容器运行时选择,各有其优势和适用场景。Containerd作为一个为容器编排而生的轻量级运行时,以其简洁的架构、对标准的支持以及与Kubernetes的契合,逐渐成为社区的主推选择。Kubernetes社区持续加大对Containerd的投入,使其成为默认的容器运行时。这一趋势反映了Kubernetes对标准化、可移植性和稳定性的追求。

然而,这并不意味着Docker就失去了其价值。作为容器技术的先驱,Docker凭借其功能的丰富性和生态的成熟度,在某些特定场景下仍然不可或缺。特别是对于那些严重依赖Docker特有功能(如docker build、docker push等)或需要与现有Docker工作流集成的用户来说,继续使用Docker可能是更优的选择。

因此,在选择容器运行时时,我们需要全面权衡各种因素,如稳定性、性能、资源占用等。要充分评估自己的实际需求,考虑是否需要Docker提供的特殊功能。在某些情况下,混合使用Containerd和Docker,发挥各自的优势,可能是一个不错的折中方案。

展望未来,随着Kubernetes的不断发展和成熟,以Containerd为代表的标准化容器运行时将成为主流选择。但这并不意味着Docker会完全退出舞台,其在容器技术发展历程中的重要地位和贡献是不可磨灭的。Docker丰富的功能和强大的社区生态,在特定场景下仍将发挥重要作用。

总之,Containerd和Docker之争,反映了Kubernetes社区在追求标准化和兼顾灵活性之间的平衡。作为Kubernetes用户,我们需要根据自身的实际情况,权衡利弊,做出最适合自己的选择。无论选择何种容器运行时,最终目的都是为了更好地支撑Kubernetes,提供稳定、高效、灵活的容器编排服务。

F. 附录

F.1 命令对照表

下表列出了Docker、Containerd(ctr)和Kubernetes(crictl 和 kubectl)中常用操作的对应命令:

操作DockerContainerd (ctr)Kubernetes (crictl)Kubernetes (kubectl)查看运行的容器docker psctr task ls / ctr container lscrictl pskubectl get pods查看镜像docker imagesctr image lscrictl images-查看容器日志docker logs-crictl logskubectl logs查看容器详情docker inspectctr container infocrictl inspectkubectl describe pod查看容器资源使用情况docker stats-crictl statskubectl top pod启动已有的容器docker startctr task startcrictl start-停止运行的容器docker stopctr task killcrictl stopkubectl delete pod运行一个新的容器docker runctr run-kubectl run创建一个新的容器docker createctr container createcrictl createkubectl create -f <pod-spec>.yaml删除容器docker rmctr container rmcrictl rmkubectl delete pod拉取镜像docker pullctr image pullcrictl pull-推送镜像到仓库docker pushctr image push–删除本地镜像docker rmictr image rmcrictl rmi-给镜像打标签docker tagctr image tag–在容器中执行命令docker exec-crictl execkubectl exec导入镜像docker loadctr image import–导出镜像docker savectr image export–构建镜像docker build–kubectl apply -f <build-spec>.yaml查看容器进程信息docker top—
这个表格涵盖了更多的操作,并且列出了Docker、Containerd(ctr)、Kubernetes(crictl)和Kubernetes(kubectl)中的对应命令(如果有的话)。

需要注意的是,由于Kubernetes主要关注容器的编排和管理,而不是单个容器的操作,因此有些Docker和Containerd的命令在Kubernetes(kubectl)中并没有直接的对应。这些操作通常是在创建或管理Pod时通过配置文件(如YAML)来指定的。

另外,kubectl 和 crictl 都是与 Kubernetes 相关的命令行工具,但它们的目的和使用场景有所不同:

从目的和功能看:

kubectl:kubectl是Kubernetes的标准命令行工具,用于管理和操作Kubernetes集群中的各种资源,如Pod、Service、Deployment、Namespace等。它通过Kubernetes API服务器与集群进行交互,提供了一组丰富的子命令和选项,用于创建、查看、更新和删除Kubernetes对象。kubectl的主要目的是管理和编排容器,而不是直接与容器运行时交互。
crictl:crictl是CRI(Container Runtime Interface)的命令行工具,用于与兼容CRI的容器运行时(如Containerd)进行直接交互。它提供了一组标准化的命令,用于管理和操作容器和镜像,如创建容器、启动容器、查看容器状态等。crictl的主要目的是调试和排查与容器运行时相关的问题,而不是管理Kubernetes资源。

从使用场景看:

kubectl:kubectl是Kubernetes用户和管理员的主要工具。它用于日常的集群管理和应用部署任务,如创建和管理Pod、Service、Deployment等,查看集群状态,更新应用配置等。kubectl适用于所有需要与Kubernetes集群交互的场景。
crictl:crictl主要是为开发人员和管理员提供的一个调试和排查工具。当遇到与容器运行时相关的问题时,如容器无法启动、镜像拉取失败等,可以使用crictl来直接与容器运行时交互,以诊断和解决问题。crictl适用于需要直接访问和操作容器运行时的场景。

F.2 参考资料

序号文档名称文档链接1Kubernetes官方文档 – 容器运行时https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/2Kubernetes官方文档 – 使用Containerd作为容器运行时https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/#containerd3Kubernetes官方文档 – 从Docker迁移到Containerdhttps://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/#migrating-from-dockershim4Containerd官方文档 – Kubernetes集成https://github.com/containerd/containerd/blob/main/docs/getting-started.md#kubernetes-integration5Containerd官方文档 – 与Docker的差异https://github.com/containerd/containerd/blob/main/docs/getting-started.md#differences-with-docker6Docker官方文档 – Kubernetes集成https://docs.docker.com/get-started/kube-deploy/7Docker官方博客 – Kubernetes中的Docker和Containerdhttps://www.docker.com/blog/what-is-containerd-runtime/8Kubernetes弃用Dockershim的博客公告https://kubernetes.io/blog/2020/12/02/dockershim-faq/9Kubernetes官方文档 – 弃用Dockershim的FAQhttps://kubernetes.io/zh-cn/blog/2020/12/02/dockershim-faq/10CNCF官方博客 – Containerd毕业公告https://www.cncf.io/announcements/2019/02/28/cncf-announces-containerd-graduation/11Kubernetes官方文档 – 容器运行时接口(CRI)规范https://github.com/kubernetes/kubernetes/blob/242a97307b34076d5d8f5bbeb154fa4d97c9ef1d/docs/devel/container-runtime-interface.md12OCI(Open Container Initiative)官网https://opencontainers.org/13OCI运行时规范https://github.com/opencontainers/runtime-spec14OCI镜像规范https://github.com/opencontainers/image-spec

#以上关于Kubernetes容器运行时:Containerd vs Docke的相关内容来源网络仅供参考,相关信息请以官方公告为准!

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91330.html

Like (0)
CSDN的头像CSDN
Previous 2024年6月21日
Next 2024年6月21日

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注