You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
13 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 59 | 数据中心操作系统:上市敲钟
在这门课程里面我们说了内核态有很多的模块可以帮助我们管理硬件设备最重要的四种硬件资源是CPU、内存、存储和网络。
最初使用汇编语言的前辈在程序中需要指定使用的硬件资源例如指定使用哪个寄存器、放在内存的哪个位置、写入或者读取哪个串口等等。对于这些资源的使用需要程序员自己心里非常地清楚要不然一旦jump错了位置程序就无法运行。
为了将程序员从对硬件的直接操作中解放出来提升程序设计的效率于是我们有了操作系统这一层用来实现对于硬件资源的统一管理。某个程序应该使用哪个CPU、哪部分内存、哪部分硬盘只需要调用API就可以了这些都由操作系统自行分配和管理。
其实操作系统最重要的事情,就是调度。因此,在内核态就产生了这些模块:进程管理子系统、内存管理子系统、文件子系统、设备子系统和网络子系统。
这些模块通过统一的API也就是系统调用对上提供服务。基于这些API用户态有很多的工具可以帮我们使用好Linux操作系统比如用户管理、软件安装、软件运行、周期性进程、文件管理、网络管理和存储管理。
但是到目前为止,我们能管理的还是少数几台机器。当我们面临数据中心成千上万台机器的时候,仍然非常“痛苦”。如果我们运维数据中心依然像运维一台台物理机的前辈一样,天天关心哪个程序放在了哪台机器上,使用多少内存、多少硬盘,每台机器总共有多少内存、多少硬盘,还剩多少内存和硬盘,那头就大了。
因而对应到数据中心我们也需要一个调度器将运维人员从指定物理机或者虚拟机的痛苦中解放出来实现对于物理资源的统一管理这就是Kubernetes。
Kubernetes究竟有哪些功能可以解放运维人员呢为什么它能做数据中心的操作系统呢
我列了两个表格将操作系统的功能和模块与Kubernetes的功能和模块做了一个对比你可以看看。
![](https://static001.geekbang.org/resource/image/49/47/497c8c2c0cb193e0380ed1d7c82ac147.jpeg)
Kubernetes作为数据中心的操作系统还是主要管理数据中心里面的四种硬件资源CPU、内存、存储、网络。
对于CPU和内存这两种计算资源的管理我们可以通过Docker技术完成。它可以将CPU和内存资源通过namespace和cgroup从大的资源池里面隔离出来并通过镜像技术实现计算资源在数据中心里面的自由漂移。
就像我们上面说的一样没有操作系统的时候汇编程序员需要指定程序运行的CPU和内存物理地址。同理数据中心的管理员原来还需要指定程序运行的服务器及使用的CPU和内存。现在Kubernetes里面有一个调度器Scheduler你只需要告诉它你想运行10个4核8G的Java程序它会自动帮你选择空闲的、有足够资源的服务器去运行这些程序。
对于操作系统上的进程来讲有主线程做主要的工作还有其它线程做辅助的工作。对于数据中心里面的运行的程序来讲也会有一个主要提供服务的程序例如上面的Java程序也会有一些提供辅助功能的程序例如监控、环境预设值等。Kubernetes将多个Docker组装成一个Pod的概念。在一个Pod里面往往有一个Docker为主多个Docker为辅。
操作系统上的进程会在CPU上切换来切换去它使用的内存也会换入换出。在数据中心里面这些运行中的程序能不能在机器之间迁移呢能不能在一台服务器故障的时候选择其它的服务器运行呢反正我关心的是运行10个4核8G的Java程序又不在乎它在哪台上运行。
Kubernetes里面有Controller的概念可以控制Pod们的运行状态以及占用的资源。如果10个变9个了就选一台机器添加一个如果10个变11个了就随机删除一个。
操作系统上的进程有时候有亲和性的要求比如它可能希望在某一个CPU上运行不切换CPU从而提高运行效率。或者两个线程要求在一个CPU上从而可以使用Per CPU变量不加锁交互和协作比较方便。有的时候一个线程想避开另一个线程不要共用CPU以防相互干扰。Kubernetes的Scheduler也是有亲和性功能的你可以选择两个Pod永远运行在一台物理机上这样本地通信就非常方便了你也可以选择两个Pod永远不要运行在同一台物理机上这样一个挂了不影响另一个。
你可能会问Docker可以将CPU内存资源进行抽象在服务器之间迁移那数据应该怎么办呢如果数据放在每一台服务器上其实就像散落在汪洋大海里面用的时候根本找不到所以必须要有统一的存储。正像一台操作系统上多个进程之间要通过文件系统保存持久化的数据并且实现共享在数据中心里面也需要一个这样的基础设施。
统一的存储常常有三种形式,我们分别来看。
第一种方式是**对象存储**。
顾名思义这种方式是将文件作为一个完整对象的方式来保存。每一个文件对我们来说都应该有一个唯一标识这个对象的key而文件的内容就是value。对象可以分门别类地保存在一个叫作存储空间Bucket的地方有点儿像文件夹。
对于任何一个文件对象我们都可以通过HTTP RESTful API来远程获取对象。由于是简单的key-value模式当需要保存大容量数据的时候我们就比较容易根据唯一的key进行横向扩展所以对象存储能够容纳的数据量往往非常大。在数据中心里面保存文档、视频等是很好的方式当然缺点就是你没办法像操作文件一样操作它而是要将value当成整个的来对待。
第二种方式是**分布式文件系统**。
这种是最容易习惯的,因为使用它和使用本地的文件系统几乎没有什么区别,只不过是通过网络的方式访问远程的文件系统。多个容器能看到统一的文件系统,一个容器写入文件系统,另一个容器能够看到,可以实现共享。缺点是分布式文件系统的性能和规模是个矛盾,规模一大性能就难以保证,性能好则规模不会很大,所以不像对象存储一样能够保持海量的数据。
第三种方式是**分布式块存储**。
这就相当于云硬盘,也即存储虚拟化的方式,只不过将盘挂载给容器而不是虚拟机。块存储没有分布式文件系统这一层,一旦挂载到某一个容器,可以有本地的文件系统,这样做的缺点是,一般情况下,不同容器挂载的块存储都是不共享的,好处是在同样规模的情况下,性能相对分布式文件系统要好。如果为了解决一个容器从一台服务器迁移到另一台服务器,如何保持数据存储的问题,块存储是一个很好的选择。它不用解决多个容器共享数据的问题。
这三种形式对象存储使用HTTP进行访问当然任何容器都能访问到不需要Kubernetes去管理它。而分布式文件系统和分布式块存储就需要对接到Kubernetes让Kubernetes可以管理它们。如何对接呢Kubernetes提供Container Storage InterfaceCSI接口这是一个标准接口不同的存储可以实现这个接口来对接Kubernetes。是不是特别像设备驱动程序呀操作系统只要定义统一的接口不同的存储设备的驱动实现这些接口就能被操作系统使用了。
存储的问题解决了接下来是网络。因为不同的服务器上的Docker还是需要互相通信的。
Kubernetes有自己的网络模型里面是这样规定的。
1.IP-per-Pod每个 Pod 都拥有一个独立 IP 地址Pod 内所有容器共享一个网络命名空间。
2.集群内所有 Pod 都在一个直接连通的扁平网络中,可通过 IP 直接访问。
* 所有容器之间无需 NAT 就可以直接互相访问。
* 所有 Node 和所有容器之间无需 NAT 就可以直接互相访问。
* 容器自己看到的 IP 跟其它容器看到的一样。
这其实是说里面的每一个Docker访问另一个Docker的时候都是感觉在一个扁平的网络里面。
要实现这样的网络模型有很多种方式例如Kubernetes自己提供Calico、Flannel。当然也可以对接Openvswitch这样的虚拟交换机也可以使用brctl这种传统的桥接模式也可以对接硬件交换机。
这又是一种类似驱动的模式和操作系统面临的问题是一样的。Kubernetes同样是提供统一的接口Container Network InterfaceCNI容器网络接口。无论你用哪种方式实现网络模型只要对接这个统一的接口Kubernetes就可以管理容器的网络。
至此Kubernetes作为数据中心的操作系统内核的问题解决了。
接下来是用户态的工作模式问题了。我们能不能像操作一台服务器那样操作数据中心呢?
使用操作系统需要安装一些软件于是我们需要yum之类的包管理系统使得软件的使用者和软件的编译者分隔开来软件的编译者需要知道这个软件需要安装哪些包包之间的依赖关系是什么软件安装到什么地方而软件的使用者仅仅需要yum install就可以了。Kubernetes就有这样一套包管理软件Helm你可以用它来很方便地安装、升级、扩容一些数据中心里面的常用软件例如数据库、缓存、消息队列。
使用操作系统,运行一个进程是最常见的需求。第一种进程是**交互式命令行**运行起来就是执行一个任务结束了马上返回结果。在Kubernetes里面有对应的概念叫作JobJob 负责批量处理短暂的一次性任务 (Short Lived One-off Tasks),即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束。
第二种进程是**nohup长期运行**的进程。在Kubernetes里对应的概念是Deployment使用 Deployment 来创建 ReplicaSet。ReplicaSet 在后台创建 Pod。也即Doployment里面会声明我希望某个进程以N的Pod副本的形式运行并且长期运行一旦副本变少就会自动添加。
第三种进程是**系统服务**。在Kubernetes里面对应的概念是DaemonSet它保证在每个节点上都运行一个容器副本常用来部署一些集群的日志、监控或者其他系统管理应用。
第四种进程是**周期性进程**也即Crontab常常用来设置一些周期性的任务。在Kubernetes里面对应的概念是CronJob定时任务就类似于 Linux 系统的 Crontab在指定的时间周期运行指定的任务。
使用操作系统我们还需使用文件系统或者使用网络发送数据。虽然在Kubernetes里面有CSI和CNI来对接存储和网络但是在用户态不能让用户意识到后面具体设备而是应该有抽象的概念。
对于存储来讲Kubernetes有Volume的概念。Kubernetes Volume 的生命周期与 Pod 绑定在一起容器挂掉后Kubelet 再次重启容器时Volume 的数据依然还在,而 Pod 删除时Volume 才会真的被清理。数据是否丢失取决于具体的 Volume 类型。Volume的概念是对具体存储设备的抽象就像当我们使用ext4文件系统时不用管它是基于什么硬盘一样。
对于网络来讲Kubernetes有自己的DNS有Service的概念。Kubernetes Service是一个 Pod 的逻辑分组,这一组 Pod 能够被 Service 访问。每一个Service都一个名字Kubernetes会将Service的名字作为域名解析成为一个虚拟的Cluster IP然后通过负载均衡转发到后端的Pod。虽然Pod可能漂移IP会变但是Service会一直不变。
对应到Linux操作系统的iptablesKubernetes 在有个概念叫Network PolicyNetwork Policy 提供了基于策略的网络控制,用于隔离应用并减少攻击面。它使用标签选择器模拟传统的分段网络,并通过策略控制它们之间的流量以及来自外部的流量。
是不是很神奇有了Kubernetes我们就能像管理一台Linux服务器那样去管理数据中心了。
如果想深入了解Kubernetes这个数据中心的操作系统你可以订阅极客时间的专栏“[深入剖析Kubernetes](https://time.geekbang.org/column/article/114197)”。
## 总结时刻
下面,你可以对照着这个图,来总结一下这个数据中心操作系统的功能。
![](https://static001.geekbang.org/resource/image/1a/e5/1a8450f1fcda83b75c9ba301ebf9fbe5.jpg)
## 课堂练习
Kubernetes有一个简单的版本你可以按照官方文档用一台虚拟机安装一个试验一下。
欢迎留言和我分享你的疑惑和见解,也欢迎收藏本节内容,反复研读。你也可以把今天的内容分享给你的朋友,和他一起学习和进步。
![](https://static001.geekbang.org/resource/image/8c/37/8c0a95fa07a8b9a1abfd394479bdd637.jpg)