写点什么

云原生:详解|K8s 技术栈解析, 一文读懂 K8s 工作原理

用户头像
息之
关注
发布于: 2 小时前
云原生:详解|K8s技术栈解析, 一文读懂K8s工作原理

原创 谭一笑,左太冲 云世公众号  10 月 19 日

收录于话题

#云原生 161 个内容

#K8s 架构 36 个内容

文章比较长,但通俗易懂的工作原理解析:

K8s 学习办法、K8s 标准对象、K8s 核心组件、K8s 分层架构、K8s 架构原则


上一节我们详解了容器的核心技术:详解|容器核心技术解析


回顾容器主要技术

有 name space 做隔离,有 Cgroup 的资源控制,可以很安全地把一个应用丢到某个隔离环境中去运行,并且不对整个主机产生影响。这个应用要跑起来,需要所支撑的文件系统是 overlayFS。上一节主要解析了这些技术。

容器技术,从原理上了解,它是用什么样的方式让容器运行起来的。

K8s 学习办法

了解了容器技术基础上,看一下 K8s 做了哪些事情,为什么变成了业界的标准,K8s 的主要架构是什么,它的控制面组件是什么样的。


与本节相关的理论概念,参见:K8s架构概念


当我们去学习任何技术的时候,都要去研究一下这个技术的来龙去脉是什么,它的前身是什么,前身在解决什么问题,然后很自然地就知道这个新系统是为了解决哪些问题的。往回看,在没有这个技术的时候,这个世界怎么样,它在追求解决什么问题,上一代的平台是怎么样的,这有助于我们去理解这项技术的更深层次。


学习 K8s 也一样。


K8s 在谷歌的前身,是一套集群管理的系统叫 Borg。Google Borg 有篇 paper,建议大家去读一下,有助于了解云原生。


1、找到价值

对于任何平台,一个问题是,其核心价值是什么?应用的高可用、灵活、高性能。


容器是一个个的独立个体,要跑一个容器应用,一定要有一个东西来做 housekeeper,来管控它。如果应用出现故障,应该有一种方法来做资源管控,做整个应用的生命周期管理,如果失败了,要重启等等这些机能,这就是 Borg 需要去解决的问题。

Borg 本身是一个集群管理加一个作业调度的平台,它要支持很多灵活调度的策略。有了 Borg 系统,能实现应用的高可用和高可靠。它把很多基础架构层面的东西隐藏起来了,这也是云的价值。


  • 云的理解,把它简单理解为把计算资源抽象出来,对应用开发人员或者应用这个云平台的使用者,只要去描述要跑哪个作业即可。


  • 云上运行业务,可以通过 Docker 把业务 build 成一个个容器镜像,容器镜像里面,第一,可以定义运行时要跑哪些应用,第二,定义资源需求。然后把这个请求发给某一个云平台,剩下的事情交给云平台,云平台帮你去做调度。


  • 云的优势,就是它把所有硬件的底层相关的资源都抽象出来了,对用户来讲,只需要告诉它你要跑什么作业,需要多少资源,它帮你去处理所有的东西。这也是 Borg 追求的目标和它的优势。


2、理解原理和机能

Borg 管理谷歌的整个数据中心。

谷歌有两类大的应用,一类叫做 Product workload; 一类叫做 non product workload。 

  • Product workload 就是我们日常所熟知的在线的服务,比如 web search。它的特性是这些应用永远在线。提供任何在线业务所追求的终极目标就是它的可用性,即任何用户来访问,它都在提供服务。这是一个最基本的需求。

  • Non- Product workload 是批处理应用。比如电信银行要做对账,账单的处理是批处理行为,比如要对一些用户的日志做行为分析等等,都是批处理业务。它的特性是实时性要求不高,但是很耗资源,所以这种作业就是有资源就跑一跑。如果 Product workload 需要资源了,就可以把我的资源先临时让给你,等你空闲了以后我再继续跑。


i、资源利用率

通过在线应用和离线应用混布的手段,保证整个集群资源利用率很高。


在 Borg 里面有一个 Cell 的概念, Cell 就是一个集群,一个数据中心可能有 10 万台机器,需要把这些机器化成一个个的逻辑单元,可能是 5000 台或者 1 万台。


为什么这么划分?

第一,因为集群规模支撑的上限是有限的,集群规模越大,越意味着集群控制面所做的计算越大。要提升性能,要做一定的切分

第二,因为故障率的控制。要把集群分成一个小的逻辑单元,带来的好处就是控制面 Down 的话,只有一部分机器死了。


ii、自动化运维

K8s 和 Borg 被应用的原因一样,相对于虚拟机的一些问题,而启用的云机能,比如虚拟机缺少全自动化,如果一个 instance 虚机坏了,需要把这个虚拟机下架,要起一个新的虚拟机,要把应用部署到这台虚机上,让应用起好,然后一点点去测新应用没有问题,再把它跟之前的那台整个替换才完成。这样就会涉及到大量人工操作,使得整个应用的维护成本非常高。


自己维护平台,所有这些维护工作加业务逻辑都得写,成本是很大的。


Borg 这样的系统,它跟 OpenStack 的区别是什么?

最核心就是调度的不是虚机,是目标实体,就是你的作业,是某一个应用。


通过模型抽象,就使得从开发到基础架构能知道这台机器上跑了哪些应用,就可以做很多自动化的功能。


自动化运维就是云的最大特征。


iii、应用高可用

怎么确保应用高可用?最常见的手段就是冗余部署。


这时要考虑故障率。无论在 Borg,在 K8s 里面都有多种范围,比如主机、机架、可用区、数据中心等等。

要控制故障率,就要考虑清楚哪一个是控制面,哪一个是数据面。


控制面要控制的是什么?要保证平台上面跑的应用的高可用。比如跑了一个 web server,Borg 是可以死的,但是 web server 不能死,所以是确保应用的高可用,就是数据面所运行的应用是非常非常重要。作为一个平台,平台出现故障,平台可以维护,但是上面跑的应用不能维护,所以第一目标是保证这些应用的高可用。作为一个云平台,永远要追求自己应用平台的高可用。


当然,万一 Borg 死了,所有请求、所有的变更都不能做了,很可能同时引发数据面的问题,所以同时要追求自身的高可用。


iv、资源调整

Borg 还会做对于每个应用的资源调整。它允许定资源,比如要了 10 个 CPU,但是应用是单线程的,Borg 会做监控,在这个应用启动后,它监控发现实际的资源没有用到你设定的那么多资源,就会给你压缩,这样就提升整个资源利用率。压缩以后,会一直扫描计算,确保把剩下的资源空出去,再给别的应用使用。

K8s 也遵循了以上这些机能。

K8s 在解决哪些问题?

第一个,应用的部署维护和滚动升级


随时随地都可以做升级,怎么做升级?发布滚动升级,相当于一个应用先跑三个版本,三个实例。在做升级的时候,一个个滚动着升级,这样对用户来说是无感知的,悄悄地就把版本换掉了,用户是不知道的。


第二个,负载均衡、服务发现、自动伸缩等自动化能力


在任何一个云平台发布服务,别人要访问你,你要访问别人。为高可用用了冗余部署以后要去做负载均衡。当一个请求过来,把请求丢给一个真实的后端,跨故障域的集群调度,跨机器、跨地区,两地三中心完成生产应用的部署,自动伸缩等。以前都是手工操作,在 K8s,很简单一条命令就行了。会去监控应用的 CPU、 memory、 qps 等等 metrics,如果超过你设置的阈值,会自动做个伸缩,可以做横向扩展,可以做纵向扩展。

把从前非常多花费运维成本的工作,现在都通过 K8s 自动化了。

K8s 和 OpenStack 的最大区别

最重要的一点差异就是:K8s 是一个声明式系统。


怎么理解声明式?它可以基于设定的要求和上一次的实施反应来决定下一步应该怎么操作。是一个互动式的 interactive 方式。


所谓申明式系统,是把你的请求提交给平台,平台记录下来,在后台慢慢的调整这个系统的真实状态到跟你的请求期望状态一致。

对于平台来说,与命令式系统相比,声明式系统有什么样的好处?


第一,命令式系统是有顺序的。

第二,命令式系统前后是有依赖的。

很少人会把所有参数每一步骤都记下来,所以命令式系统比较大的困难是到后期,想追溯历史状态是很难的。


比如数据中心,我们知道一个机器变成这个样,或者一个应用现在长得这样,但是他怎么变成这样,没人能说得清楚。然后能不能动不知道,因为也不知道它为什么变成今天这样了,到最后是这个东西放在那跑着,ok 的,谁敢动吗?没人敢动。这就是以前系统的弊端。


对于 K8s 声明式系统的解决之道:


第一点,提供 API 方式接受和存储声明,

这些 API 接受的是你的声明,可以把你的期望状态告诉它,它把期望状态存到它的数据库里面,相当于做了持久化,就可以追溯历史。任何时候看最终的系统,能知道它是怎么来的,能知道在任何时间点系统是长什么样的,可以追溯的。


第二点,声明交由系统自动异步执行,应用无需等待,

告诉系统期望值,系统会一直去尝试,直到满足用户的需求。同时系统只要告诉用户,接收到这个请求就好了。对于客户端,是一个非阻塞的运行过程,应用就可以做别的事情了。

这样方式有助于提高整个平台或者整个生态系统的效率。


K8s 除了有一个声明式系统,同时它跟业界的各个公司一起定规范,形成了一个统一的 API,这套 API 就是云原生的统一 API。


K8s 通过声明式 API 把云计算的整个领域所有对象都定义好了,要管控的资源都定义好了。相当于定义好了一些约定,这些约定意味着大家都适配,那么将来要改造,成本巨大,不会有人有驱动力再去把它推掉重建的,一定是在这个基础之上不断的去更新。

K8s 标准对象

第一个,Node,计算节点


它是资源抽象,描述资源的 capacity 是多少,有多少计算能力,比如最多有多少 CPU,多少 memory,有多少可以再分配的资源,健康状况是 ready 还是 military 等等健康状况。用来代表计算节点的实体。


第二个,Namespace,其实是个文件目录,

把它理解为文件系统中的目录结构。对于不同的用户,可以通过权限控制来决定 a 用户只能访问 namespace A,b 用户只能访问 namespace B。相当于做资源隔离,通过权限控制,可以把 namespace 分离,不同的用户可以在自己的 namespace 里操作有权限一些资源。


第三个,Pod,作业的基本调度单位

理解 K8s 可以从几个层面去理解,第一个是集群管理,就是它对计算节点的管理,所以通过 node 把这些节点都抽象出来,相当于把这些 node 变成一个集群。第二个是功能层面的作业调度,就是要跑一个应用,这个应用要跑什么进容器镜像,需要多少资源,这种实力用 Pod 来描述。


Pod 是一个调度的基本单位。用来满足云平台的作业调度。

pod 还有丰富的状态控制。可以控制 pod 的状态,能不能 take traffic,能不能提供服务,通过 Pod 这种对象的应用,就可以把应用和基础架构两个层面的角色打通了。

K8s 最厉害的地方是什么?基础架构和应用是互相能够感知的。

通过什么资源或者 API 去感知?就是通过 Pod。


第四个,Service,服务发现

通过 service 对象来定义跑一个应用。定义了一堆 Pod 跑应用,别人应该怎么来访问,就是通过 service 方式去访问。


service 本质上是去配负载均衡和提供域名服务。

K8s 架构



对于集群,会把一部分节点作为 master 节点,作为管理界面,剩下的所有节点作为 workload。


在 master 节点上面有几个重要的组件:


第一个,API server,API server 是什么?



它是整个云平台的 API 网关,API server 就是集群的入口。它做什么呢?用来接受用户的请求,并且支持所有控制做交互。是整个集群的核心组件,大家都跟他通信。


在 API server 后端接收到请求以后做什么呢?它把用户请求保存下来,存在分布式数据库 ETCD。这两个组件是静态的,没有任何行为触发。


第二个,Scheduler,调度器。有任何用户建了 Pod 发到 API server 里边, Scheduler 会看到有一个新的 Pod 创新了,会去看这个 Pod 有没有做过调度,如果没有,就要去帮它调度;调度完后,数据也存到 etcd 里面。


第三个,Controller,控制器。每一个控制器都会去做一些特定的动作,比如 node controller 会监控 node 的健康状况来决定是不是要做一些动作。比如 service controller,建好了一个 service 后,是不是要分配负载均衡。比如 namespace controller,当你删 namespace 的时候,会看你的 namespace 里面还有没有数据,如果有数据的话,应该先把内容清掉,再去清目录。


控制器里面是一堆控制器整合在一起,每一个控制器监控不同的对象,使得整个集群动起来。


第四个,Kubelet,把 Node 上面的资源信息和健康状况上报到 API server,调度器完成调度以后,用户的 Pod 跟某个节点绑定好了,Pod 里的容器应用要在机器上起,看本地是不是起了。


调度器,控制器,Kubelet,都是控制器的模式,来监控 API server 里面对象的变更,并完成相应的配置。

第五个,ETCD,分布式存储,是一个分布式的配置管理,是 key-value pair 的存储,基于 RAFT 协议实现。



1,分布式的存储,怎么理解呢?


如:选三台机器冗余部署,这三台机器都是 master,在上面都去布 etcd 的 instance,这三个 instance 组成一个 etcd 的集群。


有了这个集群要解决就是分布式的存储,要解决什么样的问题呢?

数据一致性的问题。 


ETCD 工作机制

etcd 启动的时候,每一个 member 会有三种身份,第一种身份叫做 follower,跟随者,就是我要听别人的话;第二种角色叫做 leader 我是发指令的那个;第三种角色叫做 candidate,就是我这个时候又不是 leader,又不是 follower,作为 candidate 是要去投票,去拉票。为了通过这种协议,从里面选出一个主来,之后所有的写操作从主去写,其他要变成 follower 的角色听从主的吩咐。这就是 etcd 的工作机制。


确定了一个 leader,数据就可以写入了。如果从接受了一个请求,它会把这个请求转到主,有任何写请求,到了主以后,主会把请求跟下次心跳一起发给从,然后从这边接收到请求以后,要存下这个 log,并且回给主,得到多数确认以后,多数人都已经确认了,主认为好了,这个数据写入完成,它再告诉 client 这次数据写入完成。

2,ETCD 支持 watch 机制,怎么理解呢?

比如有一个 watch 操作,发给 etcd 的时候它会有两个行为,第一个行为是根据你的请求条件,返回当前的结果,并且不会断开 client 请求,保持长连接。接下来你的查询条件里面有任何数据变更,它会用 event 的方式推送给你,这个是 etcp 消息机制的一个非常非常重要的,用来确保整个集群的机制,确保集群大规模访问情况下,DB 不垮,应用不垮。要查任何东西,查任何对象的状态变更,不需要一直轮循,只需要注册一下 watch,然后它返回给你就好了。

K8s 核心组件

API server

是整个集群的核心,这个核心就接收了所有的请求,并且所有的数据库读写都是从 API server 经过的。



Api 网关除了提供基本的服务,还要做自我保护。


第一个认证,得知道这个请求从哪来,请求用户是谁。第二个授权,得知道他有没有某个操作权限。第三个准入,准入分为两个行为,一个叫做变形,一个叫做校验。

怎么理解变形和校验呢?用户发了一个请求过来,作为集群的运营方,或者作为一个自动化平台,需要在原来的请求上加一些东西,这个时候希望在原始请求被被存到 etcd 之前,要在原始的请求上面更改一些属性或者添加一些属性,这个就是变形。在存之前我要知道这个新的请求生成的请求是不是有效,要做校验。


怎么理解准入呢?准入必须放在 API server,因为只有 API server 能访问 etcd。API server 在访问 etce 的时候,构建了一个在 API server 这边的缓存,对于客户端,访问 API server 的时候,默认行为数据是不穿透 API server 的, API server 会把它这边数据的缓存直接返回给你,这个请求不会到 etcd。

然后 etcd 这边有什么变化?会以通知的形式告诉 API server,理论上 API server 里面的所有数据都应该是最新的,作为客户端访问 API server,基本上能拿到最新的数据。


Controller manager,是这个整个集群的大脑,是让集群动起来的关键。为什么呢?


前面提到,etcd 就是个数据库,你发给发它什么它存什么。API server 里面是没有逻辑的,其实就做完了一些检查以后,只要检查结束了,它就把数据存到 etcd 里面,这些都是静态的。


K8s 作为声明式系统,意味着你告诉这个系统要建一个对象,一个期望的状态,desire state。这个系统一定要持续一直不停的工作,使得它的真实状态和期望状态一致。如何保持一致就是后面的 Controller 在干活。

Controller manager 就是一堆控制器的集合。它会去监控 API server,监控 kubelet 里面组件所创建的对象的变更,如果一个对象发生了变更,这个控制器就会去做相应的配置。


Scheduler,调度器比如你建了一个 Pod,调度器要去看你的 Pod 有没有做过调度,没有,就会去选择一个适合的节点,并且把你 Pod 里面的 noble name 的属性填上,这个就是调度器所完成的一个职责;Controller 是类似的,比如你建一个 service,service controller,发现你的 service 是用来描述负载均衡配置的,它就会去配负载均衡,这样你的服务就可以被访问了。

Kubelet,节点代理用来管理节点上 Pod 的整个生命周。调度器把建好的 Pod 调到某个 Node 节点上,这个时候 Kubelet 就要去工作了,起这个 Pod,去看当前的节点,这个容器起来了没有,如果没起,它就会起起来。


Kubelet 用 Docker 运行时去起:

  1. 理论上就是把用户进程拉起来,

  2. 放到某个 Namespace,

  3. 通过 Cgroup 把资源控制起来,

  4. 通过 reply,这个 docker image 把 OverlayFS 拉起来,

  5. 通过网络的插件把网络配起来, 


Kubelet 为了实现标准化,把这些配置都抽象成了一个个的接口,CRI,CNI,CSI,(container runtime  interface,container network interface,container storage interface)

任何一个系统都有一个初始化进程,Linux 的初始进程是 systemD,kubelet 是 systemD 的一个 service,systemD 起来,Kubelet 就先起来了。同时 Kubelet 作为 K8s 系统的初始进程,它启动后,一种拉起集群的方式是它去扫描本地目录来加载 Pod 等。通过这种方式,就把架构中以上这些控制器,调度器,API server,ETCD 都拉起来了。这些组件无需再去 systemD 里面配置启动,用 kubelet 拉起来就 OK 了。


所以通过这种方式我们就简化了集群的部署,并且依赖于 kubelet 本身或者 K8s 本身的特性,来保证 K8s 控制面的高可用。


Kubeproxy

建好的服务要发布出去,Kubeproxy 去监控这个 service 对象完成负载均衡的配置



插件 KubeDNS(必须)是集群里面的域名服务,发布一个服务要提供域名的,这个域名是通过 KubeDNS 来提供的。

集群自带域名服务,建的 service,其他的程序就可以通过服务名来查找了。


除了 KubeDNS 这个插件,其他插件依据业务需要可选。

K8s 工作模式



  • 作为应用开发人员,应用开发、分级部署以及数据平面对象,都跟应用开发人员有关系。容器技术其实也有一定的关系,要对你的应用的资源消耗负责,怎么去做监控,这些都跟容器技术相关。

  • 作为集群管理员,面向的更多的是基础架构、集群管理、控制平面组件,以及维护在 K8s 上面的一些公共服务。


理论上看不到明显的边界,集群管理员同时也是应用开发者,而且二者之间经常要做一些约定来确保在基础架构上的方案,比如集群做升级的时候不影响业务,所以这条路是打通的。

K8s 的设计理念

为了保证应用的高可用,为了保证系统的安全,为了保证和扩展性可一致性,K8s 提供了各种各样的对象来描述不同的业务场景,它能够很稳的成为业界的标准,跟它的分层架构很相关。



分层架构


它定义好了 API,定义好了执行策略。


  • 向下,K8s 为了跟不同的云平台供不同的基础架构去做整合,它实现的部分都抽象成了一个个的接口(CRI、CNI、CSI)。这样,作为存储厂商,作为网络提供商,作为运营实体厂商,需要做的事情就是实现一个个的插件 plug-in,剩下的事情就是跟 K8s framework 对接。所以 K8s 把自己抽象化了,它作为一个 framework,这样在业界任何地方都是有一席之地的。

  • 向上,除了基本的 API,K8s 还提供灵活的扩展,允许定义任何 API。比如作为业界的方案提供商,就可以基于 K8s 构建很多更复杂的方案。这样一个生态系统就能形成了。


其中提到的 API 的设计原则如下:


  1. 第一点,所有 API 都需要是声明式的。

  2. 第二点,对象和对象之间应该是可互补和可组合的。聚合可能优先于继承,对于 K8s 来说,这些对象之间没有继承关系,它希望通过对象的组合完成业务的支撑。

  3. 第三点,控制器的行为必须是可承诺和密等的。怎么理解?就是一个对象如果配到一半,Controller crash 了,或者做升级节点坏了,当 Controller 重新启动,重新去配对象的时候,它所得到的结果应该是一致而稳定的,这样集群才能有一个稳定态。


进一步看 K8s 如何通过对象的组合完成业务流:



1,确保一个应用的高可用:

要去定义副本级,定义这个应用需要多少个副本,如果一个 Pod 出现了故障,没了,应用实例就没了。对于申明式系统来说,你的期望值和真实值必须是一致的,你期望一个副本,但是现在一个副本都没有,K8s 没有满足你的期望,就会去继续干活,把这个副本建出来,永远都按照期望的值来运行应用的实例。


2,当中间要做版本升级:

原来 V1 现在 V2,应用的升级是通过滚动升级,滚动升级有一定的策略,比如一次做 10%,还是一次做一个,什么样的情况下要停下来,这些策略就描述在 deployment 对象里,通过 deployment,raplicaset 和 Pod 的来完成整个业务发布的流程描述。

3,定义和发布一个服务:

应用实例运行了以后,要发布一个服务,希望别人来访问服务。就要定义一个 service。包括服务在哪个端口上面,用哪个协议去提供服务。如果要整个网站提供一个入口的网关,那么就要通过 Ingress 对象去定义。


总结


K8s 架构原则:


1,只有 API server 能访问 ETCD,其他组件必须跟 API server 通信,而且其他组件之间不直接通信,其他组件都是要跟 API server 来交互。

2,密等性的控制器,在处理到一半的情况下,如果出现了故障,比如 crash 了,那么在恢复的时候要继续去处理上一次没处理完的请求,已处理完的请求,即使再处理也得到同样的结果,就是密等性。


3,要基于监听,而不是轮巡。为什么?因为轮巡会把 API server 或者 etcd OverLoad 掉,会给它很大的查询压力,会让它过载掉。要减少主动查询,不要把集群弄死。


4,集群引导原则 self hosting,就是 kubelet 本身是用来起 Pod 的,它能确保 POd 里面有一些 policy,比如如果应用出现故障,Kubelet 会重新把它拉起来。K8s 的控制面也是希望达到的一样的目标,希望保证应用的高可用。

所以 Kubelet 可以把 K8s 的整个控制面拉起来,因为 Kubelet 可以从本地的目录去加载 Pod 清单,通过这种方式 Kubelet 管控 K8s 的控制面。


下一节,分享 K8s 核心对象间工作模式原理(Pod、Deployment、Service 等),记得来读。

往期推荐

关注 云世 微信公众号。

最全云厂商及云方案能力报告【建议收藏】

最新Serverless服务研究报告【收藏参考】

云原生:一文读懂K8s架构

云原生:一文读懂Docker核心技术

云原生:一文读懂K8s架构原则和对象设计》

云原生:一文读懂DevOps工具链


如果你觉得这个系列有价值,也欢迎转发给有需要的朋友。


云世 【云世】专注职场人的硬实力和软技能提升。为产品上云,微服务和云原生前沿技术和落地实践布道,分享微服务架构、容器、K8s、Service Mesh 等云技术干货、案例、经验;持续发布职场做事方法论、团队管理、读书笔记,好书推荐等软技能。280 篇原创内容


往期推荐

关注 云世 微信公众号。

最全云厂商及云方案能力报告【建议收藏】

最新Serverless服务研究报告【收藏参考】

云原生:一文读懂K8s架构

云原生:一文读懂Docker核心技术

云原生:一文读懂K8s架构原则和对象设计》

云原生:一文读懂DevOps工具链


---END---

喜欢就|关注|转发|点赞|订阅专题吧

公号专题

云原生」「微服务」「Service Mesh

K8s」「Docker」「DDD

职场养分」「职场软实力」「认知跨越

架构师专题」「带团队专题



---END---

⚠️更新⚠️在公众号后台:

回复:DDD,领取 DDD 全系列解决方案;

回复:K8s,领取 K8s 架构全系列资料;

回复:微服务,领取微服务实践方案;

回复:容器,领取容器全系列学习资料;

回复:servicemesh,领取 servicemesh 全系列实践方案;

回复:go,领取 Go 语言学习全系列学习资料;

回复:职场软技能,领取职场软技能系列;

回复:管理实践,领取管理实践资料;

回复:面试技能,领取面试技能资料;

回复 2021 报告,领取 35 份最新行业分析报告;

回复:PPT,领取海量面试资料和简历模板;


发布于: 2 小时前阅读数: 6
用户头像

息之

关注

微信公众号【云世】,云厂商产品从业者 2021.08.06 加入

【云世】专注职场人的硬实力和软技能提升。为产品上云,微服务和云原生前沿技术和落地实践布道。

评论

发布
暂无评论
云原生:详解|K8s技术栈解析, 一文读懂K8s工作原理