一、Kubernetes简介
Kubernetes是Google于2014年开源的一个容器编排工具,使用Google自己的go语言编写,由Borg衍生而来。Borg是Google内部已经运行近十年的容器编排工具,由于docker的横空出世,导致Google原本准备作为秘密武器的容器技术胎死腹中。计划被打乱,容器层面已经痛失良机,慢人一步,只有在编排工具层面下手了,Google当机立断,基于Brog的逻辑编写了Kubernetes,开源并捐给了CNCF(云远程计算基金会),由于Google近十年的使用经验,所以Kubernetes一出世就横扫了其它编排工具,时至今日,地位依然稳固。
Kubernetes源于希腊语,有“舵”或“飞行员”的意思。k8s,是由Kubernetes中间的八个字母缩写为数字8得来的。Google采用这个名字的深意就是:既然你docker把自己定位成驮着集装箱在大海上遨游的鲸鱼,那么我就以Kubernetes掌舵大航海时代的话语权,鲸鱼必须按照我设定的路线巡游。
Kubernetes的一大亮点就是自动化,在Kubernetes的解决方案中,一个服务可以自我扩展、自我诊断,并且容易升级,在收到服务扩容的请求后,Kubernetes会触发调度流程,最终在选定的目标节点上启动相应数量的服务实例副本,这些实例在启动成功后会自动加入负载均衡器中并生效,Kubernetes会定时巡查每个服务的所有实例的可用性,确保服务实例的数量与预期的数量一致,当它发现某个实例不可用时,会自动重启或在其它节点上重建该实例,整个过程无需额外的人工操作。 ——来自《Kubernetes权威指南》
![1419513-20190807135442962-276586567.png](https://i-blog.csdnimg.cn/blog_migrate/781bfcbdf91786f55d3fcb732a609bd2.png)
二、Kubernetes对象
k8s的api是一种Restful风格的API,在这种设计风格下,数据也好、服务也罢,一切都可以称之为资源(resources)。在k8s中将这些资源实例化后称之为对象。比如Pod在没有使用之前就是一个抽象的概念,可以称之为资源,你指定为Pod创建了容器之后,就可以称之为对象。
基础对象
Pod:这个逐条介绍吧,有点多。
- k8s最小部署单元是Pod,一个Pod可以包含一个或多个容器。
- 每一个Pod中默认有一个基础设施容器infrastructure container,后续加进来的容器都会共享此基础容器的Network、IPC、UTS名称空间(共享网络设备、网络协议、主机名、域名等),因此同一个Pod中的容器可以通过lo互相通信。还可以选择共享基础容器的存储卷。
- 每个Pod都会被分配一个单独的IP地址,且每个Pod都提供了Endpoint(Pod IP+Container Port)以被客户端访问。
Pod分为普通Pod和静态Pod。
- 普通Pod一旦被创建,就会被放入etcd中存储,随后会被Master调度到某个Node上并进行绑定,随后会被对应Node上的kubelet实例化成一组容器并启动起来。如果Pod所在的Node宕机了,Master会将这个Node上的所有Pod重新调度到其它Node节点上。
- 静态Pod不会存储到etcd中,而是存放在某个Node节点上的一个具体文件中,并且只在此Node上启动运行。
- Service:Service是一组Pod的抽象,每个Service都拥有一个唯一指定的名字,并被分配一个虚拟IP(Cluster IP、Service IP或VIP)。Service通过代理后端Pod对外或者对内提供访问,就好比nginx和后端服务的关系。来自这个IP的请求都会经过调度后转发给后端Pod中的容器。Service通过LabelSelector去选择一组Pod提供服务。下面会举例Service和Pod如何关联。
Label:标签用于区分对象,使用标签引用对象而不再是IP地址。Label以键值对的形式存在,每个对象可以有多个标签,通过标签可以关联对象。
- 假设Service代理一个或者多个Pod,但是某一个Pod因故障被删重新调度出一个新Pod,那么这个Pod的IP可能会发生改变,因为容器的IP是随机的。那Service怎么能知道这个新Pod的IP呢。这时使用标签就可以完美的解决问题。k8s中的Pod,所谓一个萝卜一个坑,只要不是手动删除Pod,那么这个Pod一定会一直存在,down掉会重启,故障会重建。在最初创建Pod时,它的Label就已经写死了,当然后面是可以手动改的。比如app:nginx。所以即便重建了Pod,IP变了,Label不会变。Service通过LabelSelector去找Label为app:nginx的服务依然能够找到。
- Ingress:给Service提供外部访问功能。
- Namespace:可以抽象理解为对象的集合。比如将集群内部的对象划分到不同得到项目组或用户组。比如Pods、Services都是属于某一个Namespace的(默认是default)。
Volume:数据卷,共享Pod中使用的数据。
高级对象
- ReplicationController:简称RC。在旧版的k8s中,只有RC对象,使用它来确保Pod以用户指定的副本数量运行。容器异常或者缺少都会自动处理。
- ReplicaSet:ReplicaSet 是 ReplicationController 的替代物。因此作用基本相同,RC与RS唯一区别就是支持LableSelector不同,RS支持基于集合的标签。官方建议使用Deployment来自动管理RS,因为有些功能RS不支持,Deployment支持。
- Deployment:Pod控制器,它支持版本记录、回滚、暂停升级等高级特性。Pod是不可以被直接创建的,需要先创建控制器,然后由控制器去创建Pod。每个Pod都对应一个deployment控制器。
- StatefulSet:为了解决有状态服务的问题(对应 Deployments 和 ReplicaSets是为无状态服务而设计)。
- DaemonSet:保证在每个Node节点上都运行一个Pod,常用来部署一些集群的日志、监控等应用。比如fluentd、logstash、prometheus等。
- Job:一次性任务,运行完后Pod销毁,不再自动重建。
- CronJob:定时任务
三、Kubernetes组件
Kubernetes的结构略微复杂,我会从大的层面一点点往下拆分叙述。整个Kubernetes集群大致划分为四部分:Clients,Master,Node,Registry。k8s本身其实就Master和Node两部分。
- Master:是Kubernetes集群的管理节点,是提供集群资源访问与管理的唯一入口。
- Node:是Kubernetes集群运行Pod的服务节点,实质上也就是运行容器。
- Registry:容器的运行需要依赖于镜像。
- Clients:编程接口,图形化接口,命令行接口。我们通过这些接口向Master发请求来管理容器,比如创建、删除等操作,我们称发起请求者为管理客户端(Clients)。
![1419513-20190807153057299-803196647.png](https://i-blog.csdnimg.cn/blog_migrate/0eae413290d3e7d38a78816656d9f342.png)
Master的组件
Master节点有四个核心组件,每一个组件都是单独的服务,下面组件中只有etcd不是k8s自己提供,它只是k8s的主要组成部分,etcd也是CNCF的成员。
kube-apiserver:是整个k8s集群对外提供服务的唯一接口,它提供请求过滤、访问控制等机制,是各组件的协调者,此API是声明式的(简单说就是用户想要什么规格的容器直接跟kube-apiserver说就行了,过程不用你管)。用户的合法请求会被API放行,然后存入etcd中。
- 是否合法指的是:etcd就好像公司领导,kuber-apiserver就是门口保安,领导规定,必须什么样的人你能放进来。k8s将etcd所能接受的数据规格范式加以封装定义在了kube-apiserver中,符合规格才能放行。
- 程序的编程范式包括声明式和命令式。声明式强调结果;命令式强调过程。
- kube-scheduler:资源调度器。kube-apiserver收到新建Pod的请求,识别其合法并存入etcd,然后kube-scheduler去watch kube-apiserver知道此需求,根据预定的调度策略评估出一个最合适Node节点来运行Pod,如果没有最合适,那就随机,最后会把调度的结果记录在etcd中。
- kube-controller:控制器。就好比人类的大脑一样,负责维护集群的状态、故障检测与恢复、自动扩展、节点状态等等。kube-controller有一个control loop的机制,它会循环检测集群中Pod的状态,假如Nginx启的不是预期的80端口,那就由kube-controller来控制容器重启、重建,直到达到预期效果为止。
- replication-controller:管理维护Replication Controller,关联Replication Controller和Pod,保证Replication Controller定义的Pod副本数量与实际运行Pod数量一致。
etcd:是一个键值(key:value)格式的存储系统,保存应用程序配置信息。
举例:用户发送新建Nginx容器的请求给kube-apiserver,kube-apiserver识别其合法后以键值对的方式存入etcd,kube-scheduler和kube-controller通过watch kube-apiserver知道此需求,然后kube-scheduler负责资源分配并决定容器运行在哪个Node上,至于运行时所需的镜像及运行的健康状态的维护都由kube-controller来负责,kube-controller会循环将当前容器的状态与watch到的用户预期的需求做对比,看是否匹配。
- k8s watch功能:k8s提供的watch功能是建立在etcd之上的。早起的k8s架构中kube-apiserver、kube-controller、kube-scheduler、Kubelet等都是直接去watch etcd的,但是随着实例的增多,对etcd造成的压力也越来越大,因此,现在是当etcd中的键值发生变化时,通知kube-apiserver,其它的组件需要watch时去直接找kube-apiserver,这样大大减小了etcd的压力。
![1419513-20190807153515903-330599964.png](https://i-blog.csdnimg.cn/blog_migrate/ba1e1b81f6b0f98660ce13a7005e321d.png)
Node的组件
Node节点负责运行容器。下面的组件中docker并不是k8s的自己的组件。k8s支持多种容器引擎,比如Core OS的rkt,只不过k8s标准支持的容器是docker,其它容器引擎想要与k8s配合使用,需要接入到k8s的cri接口 。因为不同容器技术的变动速度是不一样,k8s只能以一个相对比较权威的容器技术来作为标准,与之完美兼容。
- kubelet:kubelet也会去watch kube-apiserver,如果发现有新任务的调度结果分到了自己这个Node节点上,便会接过来执行此任务。完成后将结果汇报给kube-apiserver。
- docker:假如kubelet接过来的任务中是创建容器,那kubelet就会调docker组件在本节点上执行创建。
- container runtime:负责pod和容器的运行,就是上面说的cri。
- kubeletes-proxy:是用来维护Service网络。根据Service的信息创建代理服务,实现Service到Pod的请求路由和转发,本身也有负载均衡功能。支持 iptables 和 ipvs 两种模式。
![1419513-20190808111839860-1920645944.png](https://i-blog.csdnimg.cn/blog_migrate/ef0b809acc378b83cf418c5c8f3fa73f.png)
Addons
除了上面Master和Node的几个核心组件,还有下面一些扩展插件,其中有些插件是非必须的。
- Coredns:维护Service与cluster ip之间的对应关系
- CNI:容器网络接口。k8s的网络模型需要借助插件才能实现,比如flannel,calico等,flannel插件就是用来维护Pod网络的。
- Web UI(Dashboard):图形界面,并非必须。
- Fluentd:为集群提供日志采集、存储和查询。
- Traefik:Ingress Controller的软件实现。
![1419513-20190807220917551-268033028.png](https://i-blog.csdnimg.cn/blog_migrate/9de8765217a7d20bc45344a523da4bd4.png)
四、小小建议
Kubernetes的概念还是蛮多的,不建议是一脑门扎到概念上,尽量结合实践去理解,可以多看看官网,部分页面是有中文支持的。在下写的时候脑门也是嗡嗡的,可能会有不完善或者偏差的地方,未完待续吧......
参考资料
- 《Kubernetes权威指南》
- 《Kubernetes进阶实战》
- Kubernetes官网
- ywhu的博客:k8s的watch功能
写作不易,转载请注明出处,谢谢~~