K8S 1.8 后,你的所有疑问
作者:张磊
才云科技
2017-12-19 03:46


张 磊 / HyperHQ & CNCF Member
嘉宾介绍:
Hyper 项目成员,Kubernetes 项目官方 Project Manager 和 Feature Maintainer, CNCF Contributor Member。曾任浙江大学研究员和课程讲师。期间组建浙大云计算团队(现为 CNCF 正式学术会员)并出版《 Docker 容器与容器云》技术书籍,在 Docker 和 Kubernetes 开源社区均享有声誉。主要关注超大规模容器集群管理与数据中心相关技术,同时也是微软“云计算与数据中心领域”最有价值专家、以及 LinuxCon、KubeCon 等多个国际会议的讲师。

我自己就不多做介绍了,大家可能都认识我。今天的 Topic 是 Kubernetes 1.8 之后,我们认为作为一个社区参与者应该更新 Kubernetes 相关的哪些事情。
具体介绍的话,可能包括了这些内容:第一个会简单说一下 1.8 之后 Kubernetes 以及容器社区的情况;另外,我们的主题,我们作为一个社区的参与者,无论是一个厂商或者是一个贡献者,或者是一个使用者,应该关注Kubernetes的主线到底是什么。因为我们知道 1.8 之后所包含的 Feature 实在太多了,十几个 Sig,这些东西哪些是主线,哪些是需要投入资源做的事情;最后我会简单说一下主线特性的实现或者说 Design 遵循着怎样的理念,这是指导我们下一步工作的核心思想。


Kubernetes1.8 之后容器社区的现状

Kubernetes 渐成主流

来到我们的正题。首先对于 Kubernetes 这个社区来说,大家可能能感受到在今年这个项目逐渐成为了容器管理这些事情的主流,其中有一个非常标志性的事情,也是最近发生的。宣布它的下一个版本将会完全基于 Kubernetes 来做。
这是什么意思?因为 RANCHER 一直是可以支持三种编排引擎,并且把这个作为版本。实际上梁胜博士早在今年四、五月份就去北京给 RANCHER 站场,讲什么?讲 Kubernetes。为什么这么做?哪怕是 RANCHER 也好或者是谷歌也好,实际上要不偏不倚地运维三种编排引擎提供给自己的客户,大家应该感觉到这是很难做到的事情。
RANCHER 已经做出了一种选择,他认为他将来的客户都会使用 Kubernetes。这是第一个事情。其实,这可以理解为国外做容器 Startup 的一个风向标。所以现在可以认为国外做容器的 Startup 只有两种,第一种是做存储或者是网络周边的东西,第二种基本上都已经变成了 Kubernetes Company,比如说 CoreOS、新成立的 Heptio,这是国外 Startup 的现状。


而回到国内,有另外一个事值得提一下。就是工商银行在今年 4 月份的一个招标,这个招标的结果是一个 IBM,比较有意思的是这个标书上直接写清楚就要 Kubernetes。这个东西对国内的 Startup 影响就比较大。因为如果不是做 Kubernetes,都没有资格参与这个竞标过程。所以,在这个事情之后,国内的 Startup 也发生了变化。现在国内的几家 Startup 都去贡献 Kubernetes 或者直接宣布自己已经转型成一个 Kubernetes 公司,现在国内已经找不到一家 Startup 说不做 Kubernetes,真已经找不到了。


Kubernetes 任重道远

伴随着这些事情,是不是 Kubernetes 真的要一统天下,或者说 Kubernetes 已经完美了吗?


显然不是。根据最新 Newstack 的一个统计,现在 Kubernetes 被用户诟病最大的是问题竟然是来自于实现的复杂性和运维的复杂性,当然在 1.5、1.6、1.7、1.8 之后已经解决了不少,比如说部署。大家都知道用 Kubeadm 是非常简单的,但之前留下来的印象还是始终在用户的脑海中挥之不去。比如说像梦琦 ( KEUC 干货 | 谷歌大神详解 Kubernetes 配置管理最佳方法)他们 CTL 和微软 Deis 的这些人,已经在很多方面上正在进一步提高 Kubernetes 对用户友好的事情,所以我们可以感受到在这块上,接下来 Kubernetes 一定会有更多、更大的动作,这是现状。

PaaS 曾经两个核心问题
为什么会发生这些事情,Kubernetes 为什么会逐渐成为主流呢?还是回到 PaaS 当年的两个核心问题上第一,如何把代码或者二进制变成最小的可运行单元,有了这些才能实现我们所说的 Buid Once,Run Anywhere。大概五、六年前,这个事是交给 APP Engine 厂商或者服务来做的,比如说 SAE、BAE、TAE,谷歌有 GAE。这样的 APP Engine 往往在打包服务的时候,采用的方式就需要引入一个依赖,Library 或者是其他 Dependency 一般来说称之为比较有侵入性的依赖,使得这个应用将来可以和云平台有一定的交互能力。
在此之后,由 Cloud Foundry 和 Open Shift 项目会掀起经典 PaaS 的热潮。为什么呢?因为他们给了一个新的概念,所谓一个 Buildpack 正适应了可运行单位的概念,比如说 JAVA 应用的 Buildpack,其实就是一个 Tomcat 加上一个 War 包,这两个东西打包在一起, 把它扔到云上就能跑起来。

同样这样的东西可以在本地启动起来,所以这就是最小可运行单位,但还不够。Docker 最终拿出它的杀手锏,就是 Docker Image,Docker Image 做得更彻底,直接把应用所运行的 OS Library 文件目录所有的 Dependency 全部打包在一起,这个东西可移植性比 Buildpack 更高,所以我们来到了所谓的容器时代。
但是这个事还没完,对于 PaaS 来说还有第二个问题需要解决,就是如何把可运行单位 Run 起来,变成最终面向的服务。这个事是以前 App Engine 或者是经典的 PaaS 都没有得出非常统一的结论的。比如说 Cloud Foundry 有一个 DEA,就是用一个 Cgroup Container 把刚刚的 Buildpack run 起来。
但对 Docker 来说,Docker 说不行,要放到 Docker 容器里。还有更多的厂商,像 App Engine 往往更依赖于底层的IaaS能力,就是用虚拟机的能力去跑。实际情况就是,大家都不知道该怎么办。这个事正是 Kubernetes 后来发力的地方,可是为什么 Kubernetes 能在这个事上做得更好呢?其实很简单,Kubernetes 有一个“王炸”,就是可以抄 Borg。
如果大家关心 Kubernetes 最早的一些 Issue 和 Feature,其实会发现很多都来自 Borg 这个系统,有很多很长的 Issue,你就想那个人怎么能写那么长的 Issue,实际上很多都是从 Borg 里 Copy 出来的。有了这样的基础,Kubernetes 才能够扔出这么一串编排概念出来。突然间,没有任何的征兆,这也是 Kubernetes 之间一度被认为是有所谓的前瞻性,其实并不是前瞻性。而是谷歌 Run 这个东西已经 Run 了很久了,他们的经验拿出来给你看其实就是 Pod,Replica 等等这些编排概念,就是那些论文里一笔带过的东西。
这还没完,很快 Kubernetes 又发布了一系列的 Interface ,包括CRI、CNI、CSI 等等。这些东西就是说现在有了一个 Platform,如何接入到已有的系统,接入到一个硬件系统,接入到一个网络系统,这是一个构造生态的手段,同时 Kubernetes 上线的这个插件特性,这是很多项目比如说像 Cloud Foundry 或者是 Mesos 之前都不具备的,这正是 Kubernetes 为什么会赢的重要原因。


Kubernetes 1.8 之后的发展主线

所以,Kubernetes 发布之后,很多项目说咱们也干脆 Copy Kubernetes 的 Feature 吧,也上一个 Service,搞一个 Replica 。OK,这样 Kubernetes 就定义了这一层该怎么做的标准,这就是为什么 Kubernetes 会成为广泛被大家所认可的今天的状态。有了这些之后,大家可能会关注 Kubernetes1.8 发布了,怎么融入到社区做这些事情,这也是今天主要回答的问题。


什么是主线?必然是受到社区重点关注,具有一定的技术和战略价值,比如说梦琦介绍的 CLI 和 API 部分,就很重要。
具体说下来有两点,首先在 1.8 之后,尤其是在 Docker 已经改名 Moby 之后,在 Runtime 逐渐趋于稳定,不会太出现一个 RKT 这样的容器来 Challenge Docker 的地位。Runtime 这一层一个容器应该怎么做,镜像怎么定义,这个事情已经趋于稳定了,所以 Kubernetes 用 CRI 屏蔽了的 Runtime 的很多细节,这已经完全足够了。但在此之后,必然会发生一些事情,就是 Sig-App,就是直面用户的那部分,包括 Kubernetes 的 API 所关注东西必然会成为下一个 Kubernetes 的创新点,大家一定要记住,这里的创新是面向更友好的用户体验,更简洁,更具有让你眼前一亮的设计。
既然今天 Kubernetes 已经确定了比较领先的生态地位,接下来所有和 Kubernetes 可扩展性相关的 Feature 或者是领域,一定会成为厂商重点竞争的地方,包括现在 NVIDIA 、Intel、Redhat 都已经占据了一部分,一会儿都会提到。所以,这一定是将来最火热的部分。这两点将会成为 Kubernetes1.8 之后的主旋律,也是今天所要关心的新的 Feature。


社区参与者应着重关注的主线

Control Panel 核心概念 Pod

Kubernetes Control Panel 核心概念是 Pod,大家都知道 Pod 的第一作用是帮我们解耦容器的关系,第二个作用是它是 Kubernetes 里最原子的调度单位,并且 Pod 的Container 是 Share Namepsace 的,包括 Network、IPC。并且里面的 Pod 容器是 Shear Volume 的,这些东西有什么意义吗?马上会介绍。但是最终的目的是一个,就是希望在所谓的容器云里能够引入进程组的概念,而不是管理单一的容器或者进程。


Pod 抑制制作“胖”容器


如果说 Pod 有什么作用?首先,第一个 Pod 或者谷歌希望做的事情就是抑制住你去做一个“胖”容器的冲动。什么是“胖”容器?比如说很多人在一个容器里跑很多进程,用一个 Systemd 去管。其实这是很麻烦的事情,因为监控和整个应用生命周期的管理,都会和真实的应用进程不一致。这个事怎么解决,很棘手。所以 Kubernetes 不希望制作这种“胖”容器。


我经常举的例子是一个 JAVA 的应用,它是有两个东西组成,一个 War 包和 Tomcat。如果不用 Pod,可以把它们两个打包进一个镜像,然后一起 Run,可以,但这时候他们俩耦合在一起了,我怎么独立更新他们两个,我不可能每次更新 Tomcat 都把线上的镜像都重新 Build 一遍吧。这是第一个事。
我们也可以维护一个 Persistent Volume 。在 Kubernetes 里可以这样做,就是两个容器,两个镜像。一个镜像存一个 War 包,另一个存 Tomcat。接下来怎么定义呢?就是一个 Pod Run 这两个容器,其中 War 包容会定义成一个 InitContainer。initContainer 的特点是什么呢?它会先于所有的用户容器启动,并且按顺序执行完。这样的话在 War 包容器运行这样一个命令,叫 Copy War 包到一个指定目录,这个指定目录是一个 Pod 的 Volume。执行了这个之后,War 包容器就可以退出了。


接下来再执行用户容器是 Tomact。Tomcat 就是一个正常的标准 Tomcat 的镜像,执行命令也不变。只不过它会去 Mount 刚刚 Copy 过文件的目录 Volume,到 Webapps 目录下。这时候再去启动 Tomcat,我的 War 包就已经存在于 App 目录下,成功了。这就是一个解耦容器关系非常典型的例子。

Pod :容器设计模式

第二个 Pod 所希望给的价值是所谓的容器设计模式,大家可能已经经常提到了,说的是什么呢?

举一个最简单的例子就是 Sidecar 模式。例子非常明确,就是说现在有 Helloworld ,会在 /var/log 下面写日志。然后有一个 Fluentd ,希望把 /var/log 里的内容文件读出来,发到 ES 里。像这样的两个容器显然就构成了一个 Pod 的协作关系。所以,我会在一个 Pod 定义两个容器,并且因为他们的 Volume 是 Share 的,我就 Share 这样的 /var/log 目录就好了。所以,这时候,他们之间的文件交换,Helloworld 写一个文件,不需要进行任何的 Copy 和文件交换的操作,这就是 Pod 的文件交互模式,如何应用在生产环境的例子。


但这还没有完,更高级的做法在 Kubernetes 1.7、1.8 之后,我们称之为 Initializer 的模式。比如说现在还是一个 Helloworld,希望里面有一个  Log Agent 运行,可是这时候没有必要在所有的 Helloworld 都定义一个 Log Agent 容器。因为没有必要,机械的重复劳动不需要。


怎么办呢?Pod 里就定义一个 Helloworld 就可以了,然后声明一下,启动之前要加载一个 Initializer ,它的名字叫 Log Agent。这个 Log Agent 定义在哪儿呢?我额外定义了一个 Config,这个 Config 的内容就是 Log Agent 这个容器的 yaml 的描述,就是蓝色图框所示的部分。这个 Config 是存在 Etcd 里的,全局存起来。
这样的话,在 Kubernetes 里启动这个 Helloworld Pod,Kubernetes 会自动在这个 Pod 里注入一个容器,名叫 Log Agent,使用的数据就是蓝色图框的内容。所以这个起来之后,本来定义的是一个容器,起来之后里面其实有两个容器,另一个是 Kubernetes 帮你注入的,这个就是 Initializer 。但这还没有完。
还有一个更高级的做法,大师级的做法,就是 Istio。这个项目非常火,这个是做什么的呢?它是面向容器的微服务框架,他和 Spring 做的工作非常像,比如说服务拆分、流量控制。两个或者是多个服务之间的访问授权,以及他们之间的流量策略控制,都是交给 Istio 做的。


它是怎么实现的?想想 Spring 为什么能做这个?因为 Spring 有两个王牌,IOC 和 AOP,大家都知道,依赖注入和切面编程。同样这个理念在 Pod 的帮助下也能实现在容器世界里。怎么实现呢?Istio 里会在每个 Pod 会注入 Envoy 容器,是自动注入的,就和 Spring 切面编程在代码执行前注入逻辑的道理是一样的。
这个 Envoy 容器是干什么的?就可以理解为高级版的 Nginx,是一个双向的 Ingress 和 Egress 都支持的 Proxy 。有了这个,大家都记得 Pod 里的两个容器之间的 Network Namespace 又是共享的,我就可以让这个 Pod 的进出流量都走 Envoy。Envoy 是系统自动注入进去的,用户不需要定义,所以接下来当我要控制两个服务器之间的访问,比说流量、切片,就是 Istio 自动配置每个 Pod 的里 Envoy 的容器实现。
这里举个例子。现在有这样的微服务,有微服务 A,还有一个微服务 B。他们两个之间有一个 A 调用 B 的关系,这时候要做一个灰度发布,在线上新部署了一个B 的新版本叫 Version 2,我的要求是 A 访问 B 的流量,99% 还在原来的 V1 上,切 1% 到新版本 V2 上。怎么做?只要在 Istio 里申明要 A、B 之间的流量比例,Istio 会自动配置 A 的 Envoy 容器,使得出来的容量分流一部分到 V1 上,另一部分按照比例分到 V2 上。这就是 Kubernetes 如何在容器这个世界里实现类似 AOP 的切面控制的原理。
这个项目是谷歌,Lyft 和 IBM 一起做的,其实可以认为它就是一个源自于 Kubernetes 的项目,因为它必须依赖于 Pod 的概念。同样这样的实现在 Cloud Foundry 也可以做,因为Cloud Foundry 的容器是“胖”容器,本身里面有一个 Init 进程,如果在 Init 帮助下起一个 Envoy 的小容器,小的 Namespace ,这个是可以的。同样这个事在虚拟机里也可以做,无非就是在一个虚拟机启动多个容器的意思。但这个事在现在的 Docker Swarm 模式里就很难做,没办法在 Docker 容器里说注入一个 Envoy,Swarm 模式的网络也不支持这么干。
当然谷歌对这个事很 Open,一周前 Istio 的人和 Docker Team 就开了一个会,想把 Istio 推到 Swarm 模式 上。最终的结果就是宿主机上 Workaround,比如说现在要做一个切面, Swarm 模式 会给你在宿主机上起一个匿名容器,就是你不知道也看不见的容器,用来跑 Envoy。所以大家可以感觉到,它其实游离于当前 Schedule 掌控之外的,带来了管理的复杂度和资源管理的问题(比如怎么原子调度),但是现在没别的办法,让 Swarm 支持 Pod 不太可能 。

Pod 的实现

然后我们讲讲 Pod 怎么实现。Kubernetes 的 Pod 实现强依赖于 CRI。我想在 Kubernetes 里创建一个 Pod,名字叫 Foo,有两个容器 A 和 B。它怎么做呢?Kubernetes 的会去 Call Kubelet 里 CRI 的一个 API 叫 RunPodSandbox。Call 这个之后,如果是 Docker 做 Runtime 的话,,Docker 会启动一个 Container Foo,这个非常小的 Container,我们称之为 Inford Container,它是用来 Hold 整个 Pod 里的 Network Namespace ,其他的容器都去 Join 的一个 Network Namespace ,就实现了容器间 Network Namespace 的共享。


所以接下来 Call 第二个 API 叫 Create Container A 和 Start ContainerA。这时候 Kubelet 才会在机器 Call Docker 的 API 给你起一个容器 A。接下来大家都猜到了再操作 B,这时候 B 启动。
所以在 Kubernetes 里启动两个容器的 Pod,实际上是三个容器,因为必须有一个额外的叫 Foo 的 Infra Container。但是前面说由于有 CRI 的存在,所以 Kubernetes 不需要关心 Runtime 实际的操作。比如说你要用的是 Hyper,那在 RunPodSandbox 的时候,我们是给你起一个轻量级的虚拟机,作为 Pod,不会有什么 Infra Container。接下来 A 和 B 直接在小虚拟机启动只由部分 Namespace 构成的 Container,Run 这个 Workload。所以在这样的场景下可以实现所谓的 Mix runtime。就是我可以在同一台机器上起同一台基于虚拟化的容器,以及基于 Docker Linux Container, 可以混着跑 。这就是 CRI 的能力。

Controller

第二个东西Controller。前面说的 Pod。Pod 是描述应用的一个原子单位。这样的东西在 Kubernetes 里被使用,梦琦前面介绍过,它依赖于 Reconcile 的过程。说白了第一步去 Wacth Etcd API Object 的变化。下一步我根据变化决定要干什么,这就是 Reconcile 的典型过程,Reconcile Diff 期望值和定义值之间的差异 。并且这样的实现,梦琦也说过它是一个 Level Driven 的 ,它对应到汉语是状态驱动。它的对应面就是 Edge Driven 。
这和我们说的 Event Driven 一样,有什么区别呢?典型的例子这是 Tim Hocking 介绍过的一个 ,假设现在有一个 Device,有一个 CPU。Device 想让 CPU 知道我现在 Ready 了,有什么办法呢?可以发一个脉冲,如果 CPU 关心这个脉冲的话,它能知道 OK,这有一个脉冲,知道你 Ready 了。


但是对于 Kubernetes 来说,采用的模式是 Device 直接改变了 CPU 之间的电频,从 0 到 1,并且维持这个状态,不变,直到状态发生下一次的改变。这样带来的好处是这边的 CPU 不会 <iss 脉冲,任意时刻只要检查到我们俩之间的电频是 1,知道你是 Ready,如果是 0,就是不 Ready。这两种设计方法没有什么本质上的优劣,只不过 Kubernetes 希望实现一些事情,比如说像扩展和高性能。这样会比较容易去做。这当然是依赖于 Etcd 的能力,之前有一位同仁问到性能瓶颈,基本上性能瓶颈比较容易出现在 Etcd 上,所以从 V2 升到 V3 之后,Kubernetes 的性能得到了质的提升。
最后,我想强调这样的设计更容易做定制和扩张,因为不需要 Message Bus。Envent Driven 往往需要 Message Bus,就像 Cloud Foundry 的 Nats。

写一个自己的 API Obeject

怎么做扩展呢?很简单就是允许在 Kubernetes 写一个自己的 Object,比如我自己想写一个 Object 叫 Network,然后我还希望写一个 Network Controller,根据 Network 的变化决定下一步要做什么,我要达到这样的效果。
这个在 Kubernetes 怎么做呢?其实非常简单,有现成的模板可以 Copy。我们知道 Kubernetes 里把对象存在 Etcd 里,它怎么操作 Etcd 的,是 AIPServer。所以API Server 变成的是一个 DAO 层的角色。为了能够让 Kubernetes 知道现在要迁一个新的 Object,需要定义一个 Type。需要 Type 描述 Network 是长什么样,比如说要有一个内容,还有一堆属性,比如说 IP Range,Gateway IP 都可以定义在 Type 里。然后再写一个小方法,把 Types 注册到 API server 里。这样这两步做完,Kubernetes 就知道我有一个新的 Object,叫 Network, 这两部分代码加起来不会超过 20 行。


下一步是希望 Watch 这步的变化,知道这步是干什么。这就是 Controller,Controller 就是做这个,写 Controller 也有模板,这里就不给大家贴了,不会超过 20 行。写行 Controller 之后,用户就可以说现在要 Create 一个 Network,名字叫 Net1,这个事会被 Network Controller Watch 到,从而触发在 Network Controller 定义的 OnAdd 方法。这个里面想做什么,完全取决于你自己做的事就是了,比如 CallNeutron API分配网络,创建 Port,做这些事情。这就是一个 Controller 的工作原理。

Demo

这里有一个我们自己写的 Demo,已经捐给 OpenStack 的项目。非常短,大概十行二十行左右,右边是 OnAdd 方法,一旦 OnAdd 被触发,就去 Call Neutron 创建 Network,这都是开源的,如果有兴趣可以去研究。


Control Panel 

关键是有了这个 Controller 之后才有了 Control Panel。


也就是说你可以认为所有的 Kubernetes 控制平面要做的事情,都是基于这样的一个 Controller 模式去做的。什么意思?比如,Kubernetes 的核心就是的 Pod,用户说想要多个 Pod 的副本,Kubernetes 给你的概念叫 Deployment,Deployment 就去是描述有多个 Pod 副本的 Controller。再比如说应用有状态就用 Statesful,跑一次性任务就用 Job,其实都是 Controller 在管理的。这些就不介绍了。

Extensibility

Extensibility,就是可扩展性的问题。Kubernetes 的可扩展性有通用模型,想扩展的组件需要提供一个 General Package 。这样 Kubelet 去启容器的时候,不是去找  Docker,而是找 General Package 。第二,定义好的基于这个 General Package 的Interface,比如 CRI,至于怎么实现就不在 Kubernetes 管的范围内。


具体在 Kubernetes 怎么实现?有三种做法:第一种就是 Binary ,典型的是 FlexVolume 和 CNI。把所需要实现的参数,通过 Kubelet 以 Json 或者是文件的方式传过去。第二种是基于 GRPC 的 Server,你们之间的协议是通过 Protoc 文件定义。最后一个是比较小众的做法,是基于 Http Server。

CNI

举个典型的例子,CNI 给 Kubernetes 暴露出来的统一的接口只有这两个。具体实现的时候,其实是给你在宿主机上配置了 Network Namespace。这个 Namespace 里的 IP、路由怎么配置,网卡怎么桥接,这个 Plugin 去做。


相当于建了一个毛坯房,请施工队进去装修,装修了之后,说好了,我就把Pod往里一扔,你们就连接上 Network Namespace,如果它是 Calico 装修的,这个网络就是走 Calico 的网络。如果是 Flannel 装修就是 Flannel 的网络。所以这个东西的实现,非常非常的简单。就不多介绍了,我的伙伴 Feiskyer 会专门讲这个。

Flexvolum

第二个 Flexvolume。它对 Kubernetes 提供的统一接口就是一个 Attach,一个Mount。Attach 用来描述我的这个 Volume 如何挂在宿主机上,Mount 描述我的所有的Volume 怎么 Bindmount 在我的容器里。所有的 Volume 都是这两步的。


所以 FlexVolume 怎么实现呢?就是写一个 Binary 。这个 Binary 要实现 Kubernetes 定义好的操作,比如说 Attach,既然是要自己实现,从哪里里?只要写在 FlexVolume定义的时候,写在 Options 的字段,下面的 Key Value 组合随便写,这些都会被原封不动的一个 Json Options 的方式传递给attach 的方法作为一个参数,在里面比如说我是一个想用 Cinder Volume 做实现,就去 Json 里拿到 Cinder Config ,然后把Volume 的 ID 拿来,Attach 在自己的宿主机上,然后再 Bind mount 进我的容器里。
这样的 Mount 的操作就 OK了。这就是写自己的 Volume 插件的方式,也是最推荐的。现在 CSI 还没有做好,还没有办法用。其实 CSI 怎么做?就是把这个 Binary 改成基于 GRPC 的调用,就是传的时候,是写了一个 GRPC 的 Remote Call 。

Device Plugin

今天最后强调 Device Plugin。它会被用来取代现在 Kubernetes 已有的 GPU 支持,因为现有支持是基于 Dockertools 包的,它不走 CRI,依赖于 Docker,这样的东西是不完备的,接下来会走 CRI 加 Device Plugin。并且有这样 General 的方案才能支持 Docker 不支持的硬件,比如说高性能的网卡等等。



Device Plugin 怎么实现的呢?很简单,首先在宿主机跑一个Device Plugin,它读宿主机上比如说 GPU 的信息,把它通过 List  watch 到 Kubelet,Kubelet 把这个信息同步给 Scheduler,Scheduler 不需要再去 Hack Scheduler 一个资源叫 GPU,因为在 Scheduler 提供一个 Key value 的组合,是一个 General  的资源定义,所以只要这个 Key value 传过去,Kubernetes 就知道有三个 GPU。
接下来 Scheduler 的时候,Pod 需要一个 GPU,然后 Kubelet 掌握了本机的 GPU 信息,然后它就分配一个 GPU 出来,然后把它的 ID 作为参数去执行 Allocate 的方法,这个方法会返回 ID 对应的 Devices 的路径和需要 Mount 的依赖目录 。把这两个作为参数传给 CRI,再交给后面的 Docker。这时候这时候 Docker 启动了之后,会挂在指定 Mounts 里目录,里面有 Driver,并且会加载指定路径的 Device ,这些都是 CRI 的标准格式,这个容器就有 GPU 了。

展  望

谷歌有一个半官方的例子,非常简单大家可以记住一这个网址,就是如何写一个GPU 的 Device Plugin。非常简单,这里就不做介绍了。


最后需要提示大家一点,Device Plugin 是接下来 Kubernetes 支持各种各样高性能硬件的方式。所以,千万去 Hack Docker,当 Docker 去 FPGA,再让 Kubernetes 调,这样做肯定会和社区走偏。所以,希望大家拥抱变化,它将来会有很多的变化,但不要走偏。今天我主要介绍了两个东西,一个就是怎么Use Kubernetes,一个是 Hack Kubernetes。这就是我演讲的主要内容,谢谢大家!



181