重磅!Kubernetes决定弃用Docker

2020年12月2日 257点热度 0人点赞 0条评论
图片
作者 | Kohei Ota
译者 | 核子可乐
策划 | 万佳
什么?Kubernetes 决定弃用 Docker?

这是真的。Kubernetes 现已弃用 Docker。

https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md

目前,kubelet 中的 Docker 支持功能现已弃用,并将在之后的版本中被删除。Kubelet 之前使用的是一个名为 dockershim 的模块,用以实现对 Docker 的 CRI 支持。但 Kubernetes 社区发现了与之相关的维护问题,因此建议大家考虑使用包含 CRI 完整实现(兼容 v1alpha1 或 v1)的可用容器运行时。

简而言之,Docker 并不支持 CRI(容器运行时接口)这一 Kubernetes 运行时 API,而 Kubernetes 用户一直以来所使用的其实是名为“dockershim”的桥接服务。Dockershim 能够转换 Docker API 与 CRI,但在后续版本当中,Kubernetes 将不再提供这项桥接服务。

当然,Docker 本身也是一款非常强大的工具,可用于创建开发环境。但为了了解造成当前状况的原因,我们需要全面分析 Docker 在现有 Kubernetes 架构中的作用。

Kubernetes 是一款基础设施工具,可对多种不同计算资源(例如虚拟 / 物理机)进行分组,使其呈现为统一的巨量计算资源,从而供应用程序使用或与其他人共享。在这样的架构中,Docker(或者容器运行时)仅用于通过 Kubernetes 控制平面进行调度,从而在实际主机内运行应用程序。

图片

通过以上架构图,可以看到每个 Kubernetes 节点都与控制平面彼此通信。各个节点上的 kubelet 获取元数据,并执行 CRI 以在该节点上创建 / 删除容器。

1 但 Docker 为什么会被弃用?

如前所述,Kubernetes 只能与 CRI 通信,因此要与 Docker 通信,就必须使用桥接服务。这就是弃用 Docker 的第一点原因。

要解释下一个原因,我们必须稍微聊聊 Docker 架构。首先参考以下示意图。

图片

没错,Kubernetes 实际上需要保持在红框之内。Docker 网络与存储卷都被排除在外。

而这些用不到的功能本身就可能带来安全隐患。事实上,您拥有的功能越少,攻击面也就越小。

因此,我们需要考虑使用替代方案,即 CRI 运行时。

2 CRI 运行时

CRI 运行时的实现方案主要有两种。


containerd

如果大家只是想从 Docker 迁移出来,那么 containerd 就是最好的选择。因为它实际上就是在 Docker 之内起效,可以完成所有“运行时”工作,如上图所示。更重要的是,它提供的 CRI 其实 100% 就是由 Docker 所提供。

containerd 还属于全开源软件,因此您可以在 GitHub 上查看说明文档甚至参与项目贡献。

https://github.com/containerd/containerd/


CRI-O

CRI-O 是主要由 Red Hat 员工开发的 CRI 运行时。它的最大区别在于并不依赖于 Docker,而且目前已经在 Red Hat OpenShift 中得到使用。

有趣的是,RHEL 7 同样不官方支持 Docker。相反,其只为容器环境提供 Podman、Buildah 以及 CRI-O。

https://github.com/cri-o/cri-o

CRI-O 的优势在于其采用极简风格,或者说它的设计本身就是作为“纯 CRI”运行时存在。不同于作为 Docker 组成部分的 containerd,CRI-O 在本质上属于纯 CRI 运行时、因此不包含除 CRI 之外的任何其他内容。

从 Docker 迁移至 CRI-O 往往更为困难,但无论如何,CRI-O 至少可以支持 Docker 容器在 Kubernetes 上的正常运行。

3 还有一点……

当我们谈论容器运行时时,请注意我们到底是在谈论哪种类型的运行时。运行时分为两种:CRI 运行时与 OCI 运行时。


CRI 运行时

正如之前所提到,CRI 是 Kubernetes 提供的 API,用于同容器运行时进行通信以创建 / 删除容器化应用程序。

各容器化应用程序作为 kubelet 通过 IPC 在 gRPC 内通信,而且运行时也运行在同一主机之上;CRI 运行时负责从 kubelet 获取请求并执行 OCI 容器运行时以运行容器。稍微有点复杂,接下来我们会用图表来解释。

图片

因此,CRI 运行时将执行以下操作:

  1. 从 kubelet 获取 gRPC 请求。

  2. 根据规范创建 OCIjson 配置。


OCI 运行时

OCI 运行时负责使用 Linux 内核系统调用(例如 cgroups 与命名空间)生成容器。您可能听说过 runc 或者 gVisor,这就是了。


附录 1:runC 的工作原理

图片

CRI 会通过 Linux 系统调用以执行二进制文件,而后 runC 生成容器。这表明 runC 依赖于 Linux 计算机上运行的内核。

这也意味着,如果您发现 runC 中的漏洞会使您获得主机 root 权限,那么容器化应用程序同样会造成 root 权限外泄。很明显,恶意黑客会抓住机会入侵主机,引发灾难性的后果。正因为如此,大家才需要不断更新 Docker(或者其他容器运行时),而不仅仅是更新容器化应用程序本身。


附录 2:gVisor 工作原理

图片

gVisor 是最初由谷歌员工创建的 OCI 运行时。它实际上运行在承载各类谷歌云服务(包括 Google Cloud Run、Google App Engine 以及 Google Cloud Functions)的同一套基础设施之上。

有趣的是,gVisor 中包含一个“访客内核”层,意味着容器化应用程序无法直接接触到主机内核层。即使是应用程序“认为”自己接触到了,实际接触到的也只是 gVisor 的访客内核。

gVisor 的安全模式非常有趣,这里建议大家参阅官方说明文档。

https://gvisor.dev/docs/

gVisor 与 runC 的显著差别如下:

  • 性能更差

  • Linux 内核层并非 100% 兼容:参见官方文档中的兼容性部分

  • 不受默认支持

https://gvisor.dev/docs/user_guide/compatibility/

4 总结

1.Docker 确被弃用,大家应该开始考虑使用 CRI 运行时,例如 containerd 与 CRI-O。

a.containerd 与 Docker 相兼容,二者共享相同的核心组件。

b. 如果您主要使用 Kubernetes 的最低功能选项,CRI-O 可能更为适合。

2.明确理解 CRI 运行时与 OCI 运行时之间的功能与作用范围差异。

根据您的实际工作负载与业务需求,runC 可能并不总是最好的选择,请酌情做出考量!

原文链接:

https://dev.to/inductor/wait-docker-is-deprecated-in-kubernetes-now-what-do-i-do-e4m


今日文章推荐:

使用 Prometheus 与 Grafana 为 Kubernetes 集群建立监控与警报机制

点个在看少个 bug ?

65550重磅!Kubernetes决定弃用Docker

这个人很懒,什么都没留下

文章评论