如何基于 OpenKruise 打破原生 Kubernetes 中的容器运行时操作局限?

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
函数计算FC,每月15万CU 3个月
性能测试 PTS,5000VUM额度
简介: 本文分享了 OpenKruise 中一些功能的用法,以及它如何与 Kubelet 和 CRI 合作。如何基于 OpenKruise 打破原生 Kubernetes 中的容器运行时操作局限。

作者:王思宇,阿里云技术专家,OpenKruise 社区负责人


通常情况下,人们只能使用普通旧数据作为 Kubernetes 中最小的操作单元。一些公司在他们的集群中入侵了 Kubelet 的代码,以便他们可以对容器做更多的事情。然而,为运行时扩展操作确实是一种错误的方法,因为它不利于开源和社区的合作。现在,云原生计算基金会沙箱项目之一 OpenKruise 提供了高级功能,可以在每个原始 Kubernetes 集群中操作容器运行时。在本次演讲中,我们将介绍 OpenKruise 中一些功能的用法,以及它如何与 Kubelet 和 CRI 合作。


本次分享主要分为以下几个部分,首先我们介绍在 Kubernetes 中,针对于对容器 runtime 的操作限制有哪些,也就是说我们在 Kubernetes 中,它的机制限制了我们哪些操作,其实是对 controller runtime 是做不到的;第二点是 OpenKruise 是怎样拓展对 controller runtime 的这些操作;第三点是我们简单做一个 demo,我们如何通过 OpenKruise 来实现这些操作的;第四点是简单介绍一下我们后续的一些规划。


Kubernetes 中针对容器运行时的操作有哪些限制?


Kubernetes 中的容器运行时


图片1.png


如上图所示,这是一个 Kubernetes 的基本结构,它的结构在每个节点( Node)上,其实是 Kubelet 在 API server 里面收到它的。比如 Pod 的变化,当 Kubelet 收到一个 Pod 创建之后,通过 CRI(Container Runtime Interface) , CNI 以及类似的公共接口(例如 CSI)来调用底层真正的接口实现者去完成操作。对于容器运行时来说,是通过 CRI 接口调用底层真正的 Runtime 运行时来完成对容器的创建和启动镜像拉取这些操作。


其中 CRI 是 Kubernetes1.5 之后加入的一个新功能,由协议缓冲区和 gRPC API 组成,提供了一个明确定义的抽象层,它的目的是对于 Kubelet 能屏蔽底下 Runtime 实现的细节而只显示所需的接口。(https://github.com/kubernetes/cri-api


在 Kubernetes1.5 之前,Kubelet 与 Docker 是相耦合的,Kubelet 其实是引入了 Docker 的 client,由它们直接对 Docker 操作。有了 CRI ,对于 Kubelet 来说就不用关心底层真正的 Runtime 实现是什么,而只需要调用这层接口,接口背后的实现可能是 Containerd-d ,可能是 CRI-O,也可能是 Docker。


CRI 的职责是对容器运行时以及对镜像做相关的管理,包括对容器的启停操作,对 Sandbox 容器的操作,容器 States 的数据采集,以及镜像的拉取和查询等操作。因此,CRI 提供了比较完善的容器接口,如下图。


2.png


Kubernetes 中容器运行时的操作限制


Kubernetes API 并没有提供对容器运行时的接口操作,它唯一提供的是对 v1 版本的 Pod 操作(Pod API CRUD,Pod Subresources API)。除了 Pod 创建和更新之外,唯一能跟 Runtime 做比较相对应操作的是 Exec subresource 和 Log subresource。


Kubernetes 的 API 层面限制了用户只能创建或删除 Pod ,除此之外,里面的容器只能做 Exec, Log 这样的操作。在 Kubernetes 接口层面,用户无法进行比如拉取镜像、重启容器等操作。image.gif


3.png


那有没有可能去拓展这个 API 呢?


我们发现 Kubelet 目前没有提供任何 hook 解决 plugin 的这个操作,来让外层能去动态拓展 Kubelet 所做的事情。( Kubelet 的接口是不提供这样的插件机制的)那是否可以加入一个与 Kubelet 类似的新组件,可以连接到 CRI API,来拓展 Kubernetes 容器进行时的操作呢?


我们同样会调用 CRI 这一层,比如它可以拉镜像,可以重启容器,它的上层也可以接收一个对于 Kubernetes API 上定义的一个 CRD 资源,这个 CRD 资源定义了让用户能够声明对 CRI 接口做一些操作。比如它可以定义指定用户去拉镜像,去重启容器,可以做更多的事情。


这种方式是我们能想到的,对于这个 Kubernetes 容器运行时 operations 的拓展思路。


4.png


OpenKruise 是什么?


OpenKruise 概念


Openkruise 是 Kubernetes 的一个拓展套件,它弥补了 Kubernetes 很多功能不足,例如对于应用工作负载(应用部署发布相关功能)的不足,对于 container runtime 操作的不足等。它可以配合原生 Kubernetes 使用,并为管理应用容器、sidecar、镜像分发等方面提供更加强大和高效的能力。


2020 年 11 月,OpenKruise 作为 Sandbox 项目加入 CNCF。


5.png


Openkruise 本身并不是一个 PasS 平台。但 PasS 平台可以通过利用 Openkruise 提供的拓展能力更好的管理,运维云原生的应用。感兴趣的朋友可以通过以下网址了解更多 OpenKruise 相关信息。


Github:

https://github.com/openkruise/kruise


WebSite:

https://openkruise.io


OpenKruise 的功能


OpenKruise 是基于 CRD 的拓展,其功能大致可分为五部分:


(1)应用工作负载:包括针对无状态应用,有状态应用的灰度发布、流量控制、它的原地升级等相关功能;

(2)Sidecar 容器管理:提供更多增强的独立定义以及独立部署;

(3)应用多分区管理(Multi-domain management):一个应用如果要部署在多个分区,会进行打散和分片的管理。

(4)应用可用性防护:保护云原生应用在 Kubernetes 上运行时的高可用性;

(5)拓展增强操作:通过这种方式来实现对 container runtime(运行时)增强的操作能力。其中拓展增强操作是本文主要介绍的功能,后续我们会详细展开。


6.png

OpenKruise 功能图


OpenKruise 的架构


7.png

如图所示,OpenKruise 主要分成中心端(Kruise-manager)和节点端(Node)两个组件。中心端的 Kruise-manager 包含 controllers 和 webhooks ,通过 Kruise-manager 中心端的角色和每个节点上 kruise-daemon 功能结合,可以完成很多 Kubernetes 本身不提供的能力。Kruise-daemon 是用来避免对 Kubelet 做改造,通过拓展的方式对 CRI runtime 进行操作。


Runtime 的拓展功能


Runtime 有三个核心拓展功能。


原地升级功能


原地升级是一种可以避免删除、新建 Pod 的升级镜像能力。


8.png


如上图所示:第一部分并不是直接通过 kruise-daemon 拓展,而是利用 Kubelet 的原生机制,叫做原地升级。


如何理解原地升级?我们举一个简单的例子:比如原来有一个 pod-a ,此时的 pod-a 是通过 deployment 的或者 Openkruise 的 cloneset 扩容出来的。如果我们想要升级 app容器的镜像版本,比如从 Fv1 升级到 Fv2,正常情况下大家使用 development 部署是采用 Recreatte Update 也就是重建 Pod 升级,重建完成后我们会看到 Pod 的名字,Pod UID, (镜像也会升级为 V2) 很大程度上都会发生改变。


再看后面两者,前者 Pod 的名字和 UID 一定会发生变化,因为它已经不是同一个 Pod 的对象了。相对于我们这次介绍的原地升级,Pod 的对象其实还是原来的对象,Pod 的名字,Pod UID 都不变。其次,Pod 所在节点的 IP 也都不变,唯一变化的是镜像从 v1 级到了 v2,由于 Pod 节点没有发生任何变化,Pod 对象就不需要经过调度器重新调度,IP 分配,volume 分配,挂载这些耗时也都消除掉了,因此一个很明显好处就是节省了调度的耗时。


大家都知道,当应用镜像从 v1 升到 v2 的过程中,可能只是最顶上的 layers 发生了变化,底下绝大部分的这个 base 镜像,公共 layers 是没有发生变化的。
当我们在同一个节点上面做原地升级的时候,可以复用原有 v1 镜像的大部分 layers ,只用下载小部分的 layers 镜像。


在升级 app 容器的过程中,Pod 中的其他容器。如  sidecar 容器,是一直正常运行的,没有受到影响。反过来说,当我们升级 sidecar 容器时,容器也是正常运行的。这样可以很大程度上避免在升级一个旁路(比如运维)容器的过程中,也要对业务能力造成影响。


1.1 优势

  • 节省操作耗时,包括:Pod 调度、IP 分配、volume 分配、挂载等;
  • 复用大部分镜像层;
  • 当一个容器进行升级时,不会对 Pod 中的其它容器造成影响;


1.2 工作原理
原地升级的原理可以简单理解为 Kubelet 在创建每个容器时,会为容器计算一个 hash 值,当上层修改了比如 app 容器的 image 之后,Kubelet 就认为容器的 hash 值发生了变化。当 Kubelet 发现 Pod spec 中 app 容器的 hash 值和实际的,如 container d 对应的 hash 值不一致时,就会把旧的 app 容器停掉,用新的镜像再重建新的 app 容器,从而实现容器的原地升级的能力。


9.png


容器重启功能image.gif


10.png


容器重启的功能是很多业务,包括运维平台都很依赖的功能。大家可能会问,在 Kubernetes 中,一个 Pod 既然是无状态的,那么想重启时就直接删除 Pod,再新建一个 Pod 不就可以了吗?


这是当然可以的,但对于业务来说可能还存在很多 debug 场景,并不只是重建一个新的 Pod 就可以,而是要从原地把容器进行重启,相当于把里面的业务进程重启。比如想保留一些 volume 中的数据,一些网络、堆栈信息等,这些场景都导致业务需要有 Kubernetes Pod 的容器原地重启能力。


Kubernetes 原生是不具备容器重启能力的,对于 Kubernetes 来说,如果想要重启容器,只能手动进入容器,把容器里的应用进程杀掉,这时当容器退出,Kubernetes 会再把它拉起。当然这种方式其实都比较 hack 的这么一种方式, Openkruise 所提供的容器重启能力对于 API 来说,只需要创建一个 CR。


CR 里写的东西很明确,name spacesl 只需定义跟 pod 在同一个 name spacesl 里,其中 name 是自定义的名字,通过指定需要重启的 Pod 是哪个,需要重启 pod 出来哪些 containers,当定义了这些信息之后,提交 CR,当 kruise 收到 CR ,kruise - manager 会先经过 webhooks,对它注入一些信息,接下来 kruise-daemon 拿到 CR 会根据 CR 中定义的信息(比如会找到对应 Pod 的容器)执行 preStop hook,再通过 CRI 接口,通过 EXTC 执行 preStop,当 preStop 执行完成之后再调用这个 CRI 的 stop 。


其实这个停止方式和本身 Kubelet 在删除 Pod 时对容器的停止方式是一致的。当 kruise-daemon 对旧容器,比如对零号的 app(app_0)容器停掉之后,Kubelet 感知到 app 容器停掉了,接着就会新建一个 F1 容器并把它拉起,通过这种方式来实现优雅的容器原地重启能力。
代码示例:


apiVersion: apps.kruise.io/v1alpha1
kind: ContainerRecreateRequest
metadata:
namespace: pod-namespace
name: xxx
spec:
podName: pod-name
containers:
- name: app
strategy:
# ...
activeDeadlineSeconds: 300
ttlSecondsAfterFinished: 1800
status:
containerRecreateStates:
- name: app
phase: Succeeded
phase: Completed
# ..


镜像预热功能


提前在节点上包括新建的 Node 上预热,就可以大幅度减少后续 Pod 扩容的耗时。


11.png


从上图我们可以看到,对于上层用户来说 Openkruise 提供了一个 CRD 叫 ImagePullJob,用户可以定义需要预热哪个镜像,也可以选择性的配置 selector(selector 可以是节点的标签选择器也可以根据 Pod 进行选择),以上都可以在 Pod 所在节点上进行预热。


当用户建立 ImagePullJob 后,对于 kruise 内部逻辑来说,kruise 会把 ImagePullJob 拆分到每个 node 对应 node image 的 CR 上,当同步上去后,节点上的 kruise-daemon 会拿到这个节点所对应node image 的 CR ,在节点上预热 CR 中定义的多个镜像。


换句话说,每个节点所对应的 node image 中的镜像列表,其实就表示了上层所有 ImagePullJob 指定在这个节点上要拉取镜像全集。kruise-daemon 底层拿到 node image 后,相当于也是调用 CRI 的 Pod image 接口来完成镜像的预热。
代码示例:


apiVersion: apps.kruise.io/v1alpha1
kind: ImagePullJob
metadata:
name: test-job
spec:
image: nginx:latest
parallelism: 10
selector:
# ...
podSelector:
# ...
completionPolicy:
# ...


未来项目规划


2021 年 12 月,OpenKruise 完成了首个正式版本 v1.0 的发布,使云原生应用自动化达到新的高峰。OpenKruise 从 2019 年发布 0.1 版本到现在已经有 2 年多的时间,已有超过 70 位贡献者参与贡献,star 数量已经超过 3000。2022,我们将推进  OpenKruise 成为 CNCF  Incubation 项目,推动云原生应用自动化领域进一步成熟。


使用用户:

  • 阿里巴巴集团, 蚂蚁集团, 斗鱼TV, 申通, Boss 直聘
  • 杭银消费, 万翼科技, 多点, Bringg, 佐疆科技
  • Lyft, 携程, 享住智慧, VIPKID, 掌门 1 对 1
  • 小红书, 比心, 永辉科技中心, 跟谁学, 哈啰出行
  • Spectro Cloud, 艾佳生活, Arkane Systems, 滴普科技, 火花思维
  • OPPO, 苏宁, 欢聚时代, 汇量科技, 深圳凤凰木网络有限公司
  • 小米, 网易,美团金融, Shopee, LinkedIn
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
存储 监控 对象存储
ACK 容器监控存储全面更新:让您的应用运行更稳定、更透明
针对本地存储和 PVC 这两种容器存储使用方式,我们对 ACK 的容器存储监控功能进行了全新升级。此次更新完善了对集群中不同存储类型的监控能力,不仅对之前已有的监控大盘进行了优化,还针对不同的云存储类型,上线了全新的监控大盘,确保用户能够更好地理解和管理容器业务应用的存储资源。
349 180
|
5天前
|
弹性计算 人工智能 资源调度
DeepSeek大解读系列公开课上新!阿里云专家主讲云上智能算力、Kubernetes容器服务、DeepSeek私有化部署
智猩猩「DeepSeek大解读」系列公开课第三期即将开讲,聚焦阿里云弹性计算助力大模型训练与部署。三位专家将分别讲解智能算力支撑、Kubernetes容器服务在AI场景的应用实践、以及DeepSeek一键部署和多渠道应用集成,分享云计算如何赋能大模型发展。欲观看直播,可关注【智猩猩GenAI视频号】预约。 (239字符)
|
17天前
|
PHP Docker 容器
如何在宿主主机运行容器中的php守护进程
在Docker容器中同时运行多个程序(如Nginx+PHP+Ftp)时,需用`docker exec`命令启动额外服务。首先通过`php -v`查看PHP版本,再用`which php-fpm7.4`确认PHP安装路径,通常返回`/usr/sbin/php-fpm7.4`。最后直接运行该路径启动PHP-FPM服务,确保其正常工作。
40 14
|
1月前
|
存储 运维 Kubernetes
正式开源,Doris Operator 支持高效 Kubernetes 容器化部署方案
飞轮科技推出了 Doris 的 Kubernetes Operator 开源项目(简称:Doris Operator),并捐赠给 Apache 基金会。该工具集成了原生 Kubernetes 资源的复杂管理能力,并融合了 Doris 组件间的分布式协同、用户集群形态的按需定制等经验,为用户提供了一个更简洁、高效、易用的容器化部署方案。
正式开源,Doris Operator 支持高效 Kubernetes 容器化部署方案
|
1月前
|
存储 监控 对象存储
ACK容器监控存储全面更新:让您的应用运行更稳定、更透明
介绍升级之后的ACK容器监控体系,包括各大盘界面展示和概要介绍。
|
2月前
|
存储 Kubernetes 开发者
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
Docker 是一种开源的应用容器引擎,允许开发者将应用程序及其依赖打包成可移植的镜像,并在任何支持 Docker 的平台上运行。其核心概念包括镜像、容器和仓库。镜像是只读的文件系统,容器是镜像的运行实例,仓库用于存储和分发镜像。Kubernetes(k8s)则是容器集群管理系统,提供自动化部署、扩展和维护等功能,支持服务发现、负载均衡、自动伸缩等特性。两者结合使用,可以实现高效的容器化应用管理和运维。Docker 主要用于单主机上的容器管理,而 Kubernetes 则专注于跨多主机的容器编排与调度。尽管 k8s 逐渐减少了对 Docker 作为容器运行时的支持,但 Doc
191 5
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
|
1月前
|
Kubernetes Linux 虚拟化
入门级容器技术解析:Docker和K8s的区别与关系
本文介绍了容器技术的发展历程及其重要组成部分Docker和Kubernetes。从传统物理机到虚拟机,再到容器化,每一步都旨在更高效地利用服务器资源并简化应用部署。容器技术通过隔离环境、减少依赖冲突和提高可移植性,解决了传统部署方式中的诸多问题。Docker作为容器化平台,专注于创建和管理容器;而Kubernetes则是一个强大的容器编排系统,用于自动化部署、扩展和管理容器化应用。两者相辅相成,共同推动了现代云原生应用的快速发展。
247 11
|
2月前
|
Prometheus Kubernetes 监控
OpenAI故障复盘 - 阿里云容器服务与可观测产品如何保障大规模K8s集群稳定性
聚焦近日OpenAI的大规模K8s集群故障,介绍阿里云容器服务与可观测团队在大规模K8s场景下我们的建设与沉淀。以及分享对类似故障问题的应对方案:包括在K8s和Prometheus的高可用架构设计方面、事前事后的稳定性保障体系方面。
|
1月前
|
人工智能 运维 监控
容器服务Kubernetes场景下可观测体系生产级最佳实践
阿里云容器服务团队在2024年继续蝉联Gartner亚洲唯一全球领导者象限,其可观测体系是运维的核心能力之一。该体系涵盖重保运维、大规模集群稳定性、业务异常诊断等场景,特别是在AI和GPU场景下提供了全面的观测解决方案。通过Tracing、Metric和Log等技术,阿里云增强了对容器网络、存储及多集群架构的监控能力,帮助客户实现高效运维和成本优化。未来,结合AI助手,将进一步提升问题定位和解决效率,缩短MTTR,助力构建智能运维体系。
|
1月前
|
缓存 容灾 网络协议
ACK One多集群网关:实现高效容灾方案
ACK One多集群网关可以帮助您快速构建同城跨AZ多活容灾系统、混合云同城跨AZ多活容灾系统,以及异地容灾系统。

相关产品

  • 容器服务Kubernetes版