查看原文
其他

Docker 在 Kubernetes 里弃用了,怎么办?

字符串拼接工程师 Go开发大全 2021-01-31

(给Go开发大全加星标)

英文:Kohei Ota,

翻译:Go开发大全 / 字符串拼接工程师

一、太长不看版

对开发者来说:

不慌,Docker 容器和镜像依然是要用的,并不是所有都变了。

以下两篇文章也推荐阅读:

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

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

对于 k8s 管理员来说:

认真读一下这篇文章、要开始找 docker 之外的解决方案了。

二、弃用是真的吗?

是真的。docker 被 kubernetes 废弃了。

参考这篇 changeLog:

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

kubelet 中对 docker的支持被废弃、将会在未来的版本中被移除。kubelet 用了一个叫 “dockershim” 的模块,这个模块实现了 Docker 的 CRI、一直都有针对这些实现的issue 提到 kubernetes 社区里。我们鼓励您评估向可用的 CRI(v1alpha1 或 v1 兼容)的完整实现的运行时容器的迁移。

简单来说,就是 Docker 不支持 Kubernetes 的叫做 CRI(Container Runtime Interface)的运行时 API,Kubernetes 开发者一直在使用名为“dockershim”的桥接服务。它转换了Docker API 和 CRI,一些版本后将不再从 Kubernetes 层面提供支持。

docker 在本地是一个很强大的创建开发环境的工具,但是要理解是什么引起了这些,就需要理解docker在当前的kubernetes架构下干了什么。

k8s是一个基础架构调度工具,它对很多不同计算资源进行分组(如虚拟机、物理机),让这些资源卡你来像是一整个巨大的计算资源,你可以在这个大计算资源里运行服务或和其他人共用。这个架构下,通过k8s平台的控制面进行调度,可以让docker或容器运行时在机器上运行应用程序。

看上面这个架构图,每个 k8s 节点和控制平面交互。每个节点的 kubelet 获取 metadata、并通过调度 CRI,在节点上创建或删除容器。

docker为何被弃用?

kubernetes只通过CRI调度容器运行时、和docker做交互需要一个桥接服务。这是理由1。

要解释下一个理由,还要看一下docker架构。这是架构图:

k8s实际上需要红色圈圈里的部分。docker网络和docker存储卷在k8s里没有用到。

拥有实际上从来不用的功能,这就是个安全隐患。功能越少、攻击平台越少。

这就是k8s开始把CRI运行时当作其他选项的原因。

CRI 运行时

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

containerd

如果只是从docker迁移掉,这是最好的选择,containerized实际上是在docker内部用的,可以完成所有“运行时”工作,如上面架构图所示。它们提供CRI,这也100%和docker提供的CRI相同。

containerd是100%开源,可以在GitHub上看文档,也可以给它贡献代码。

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

CRI-O

CRI-O是一个主要由红帽公司的人开发的CRI运行时。实际上,这个运行时被用在红帽OpenShift上。OpenShift已经不再依赖docker了。

有趣的是,RHEL 7也不再官方地支持docker了。反而为容器环境提供Podman,Buildah和CRI-O。

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

我认为CRI-O的长处是它很小,因为CRI-O就是作为CRI运行时开发的。不像containerd是docker的开源的一部分,CRI-O就是纯CRI运行时、没有CRI不需要的其他任何部分。

因为它的纯正、没有CRI之外的部分,让从docker迁移到CRI-O可能很有挑战性。当然CRI-O也提供了要在k8s上运行服务的所需功能。

还有一件事

当我们讨论容器运行时的时候,我们要非常小心我们在讨论什么类型的容器运行时。的确有两种运行时,即CRI运行时和OCI运行时。

CRI运行时

正如我描述的,CRI是Kubernetes提供的、与容器运行时进行通信来创建/删除容器化应用的API。

kubelet和运行时通过IPC、以gRpc的方式通信交互,CRI运行时负责从kubelet拿到请求结果后调度OCI容器运行时到一个容器里运行。看下图:

CRI运行时做了两件事:

  1. 从kubelet拿到grpc

  2. 根据这个json,创建OCI json配置:https://github.com/opencontainers/runtime-spec/blob/master/schema/config-schema.json

OCI运行时

OCI运行时负责使用Linux内核系统调用(例如cgroups和命名空间)生成容器。比如runc或gVisor。 

附录1:runC如何工作

CRI通过调用Linux系统调用执行二进制文件后,runC生成容器。这表明runC依赖Linux内核。

这也意味着,如果runC的漏洞获得了root权限,容器化的应用程序也可以获得root权限。黑客可以利用这个漏洞进行攻击。这就是为什么Docker或其他容器运行时也应该被不断更新的原因之一,而不仅仅是只更新容器化的应用程序。

附录2:gVisor如何工作

gVisor是最初由Google员工创建的OCI运行时。gVisor在Google基础架构上作为云服务运行,例如Google Cloud Run,第二代Google App Engine和Google Cloud Functions等。

这里有趣的是gVisor具有“guest内核”层,这意味着容器化的应用程序无法直接接触主机内核层。即使他们认为这样做,也只能接触gVisor的guest内核。

gVisor的安全模型实际上非常有趣,值得阅读官方文档。

gVisor与runC的显着区别如下:

  • 性能较差

  • Linux内核层不是100%兼容的

    • 查看官方文档关于兼容性的部分

  • 默认不支持

结论

  1. Docker已经确定要废弃了,但是只是在Kubernetes废弃。如果你是k8s管理员,就要开始考虑启用其他CRI运行时了,比如containerd和CRI-O

        a. containerd与Docker兼容,其中核心组件相同。

        b. 如果只要k8s所需的最少功能,CRI-O是个好选择

    2.了解CRI和OCI运行时职责和范围的区别

根据您的工作量,runC 可能不一定总是最佳选择。


 - EOF -


推荐阅读(点击标题可打开)

1、构建现代化的无服务 Go 应用

2、微服务去中心化架构下为何还要用API网关

3、微服务架构:是什么?何时用?如何用?

如果觉得本文不错,欢迎转发推荐给更多人。



分享、点赞和在看

支持我们分享更多好文章,谢谢!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存