TOC

Kubernetes基础概念

    虽然说Pod是Kubernetes的最小调度单元,但是事实上在每一个node节点之上,看不到Pod的身影,因为它运行的还是容器,只不过在逻辑上,我们把它组织为Pod,就算我们把两个容器,运行为一个共享同一个名称网络空间的容器,我们看起来照样是两个容器。
    为了能够统一管理像Pod这样大量的资源,所以我们需要添加像Pod这些元数据信息,给原数据表现为Label,但是只是其中一种数据,它是K/V格式的数据。
    在Kubernetes我们运行了容器以后,同一类容器或者Pod可能不一样,那么既然如此,当用户的请求到达时我们如何去接入用户的请求,到底给同一类Pod的哪一个Pod去负责处理和响应,还有Pod本身是需要有所谓的控制器来管理,而尽量不要人手工去管理它,事实上在Kubernetes上Pod有两类,我们自己给它分的类,第一类叫自主式Pod,这种Pod是自我管理的,创建之后仍然要提交给Api Server,由Api Server接收之后借助于调度器,将其调度器至指定的node节点,由node启动此Pod,而后如果有Pod中的容器出现故障,需要重启容器,那是由Kubernetes来完成。但是如果node故障,那么容器就消失了;
    所以我们建议使用第二种Pod,就是由于Pod控制器控制管理的Pod,正是控制器这种机制引入,使得Kubernetes的集群设计中,Pod就完全可以成为有生命周期的对象,而后由调度器将其调度至某节点运行以后,它的任务就终止了。
    但是有一些任务,比如我们传统意义上的Nginx或者Tomcat,他们是作为守护进程运行的,那这种运行为Pod容器,我们要确保他随时出于,运行状态,一旦出现故障,我们必须第一时间发现,要么是取代它,要么是重启它,而Kubernetes为此提供的工具就叫做Pod控制器;
    Pod控制器有很多种,最早的一种叫做Replication Controller,当我们启动一个Pod时,比如一个Nginx的Pod,那这个Pod如果不够了,可以再启一个副本,其实每一个都可以称为副本,然后控制器就专门控制同一类Pod对象的各种副本,一旦副本数量少了,自动增加,一旦多了自动销毁,精确符合人预定义的设定,如果Pod调度到的这个节点来运行,这个节点宕机了,当控制器检查到了少了一个副本,就会重新请求一次master创建一个新的节点,那么Replication Controller就是负责实现这个任务的,它还能实现其他的相关任务,比如滚动更新,此前我们启动的任务是1.0版本的镜像启动的,后来我们需要启动1.1版本的镜像,那么我们Pod可以做滚动更新,比如先创建一个新版本的Pod,可以临时超出设定的Pod总大小,然后再在同一类1.0Pod中销毁一个,以此类推,进行滚动更新,而且它还支持滚动更新的回滚操作,滚动回滚;
HPA(HorizontalPodAutoscaler)
    早起的时候Kubernetes只有一个控制器就是Replication Controller,后面到了新版本之后又有了新的控制器,叫做ReplicaSet 叫副本集控制器,但是ReplicaSet 有一个声明式更新控制器,叫做Deployment,但是Deployment只能管理那些无状态的应用,有状态的应用需要一个新的控制器叫做StatefulSet,另外我们如果需要在每一个node上运行一个副本,而不是随意运行还需要一个DacmonSet,如果运行作业要使用Job,周期性运行作业需要Ctonjob,这些是常见的Pod控制器,每一种控制器都是来实现一种特定的应用管理的,来符合用户所期望的方式进行运行;
    像Deployment还支持二级控制器叫HPA水平Pod自动伸缩控制器,比如现在的Pod的CPU或者内存利用率多高,必须确保平均低于百分之六十,HPA一计算需要额外增加2个Pod,那HPA就自动加入了两个Pod,一旦对应的资源使用下降了,HPA还能自动减,但是我们可以确保至少有几个存在,随时按需控制Pod;
服务发现
    我们Pod有两个,Pod有生命周期,万一Pod所在的节点宕机了,那这个Pod需要在其他的节点重建,而重建完成之后的Pod和原来的Pod不是同一个只不过里面运行的是同一个服务,但是Pod已经不是那个Pod了,而且每一个容器应该有IP地址,新创建容器的IP地址和之前的Pod有可能就不一样了,但这个来就有一个问题了,我们的客户端如何去访问这个Pod呢,所以我们写在客户端的配置文件当中直接调用的后端的配置地址也在变化,那此处就需要用到服务发现;
    客户端每次去访问对应后端的服务时,首先需要去我们的服务发现程序里面查询一下,有没有这个服务,所有的Pod启动之后都需要向我们的服务发现的程序进程注册,一旦Pod服务注册就会有一种探测方式,控制器会循环进行服务探测,一旦服务宕机,那么就会将它从中移除,然后找一个新的服务提供者,那么在我们的IT技术领域也有一种服务专门提供服务发现;
    Pod是有生命周期的,因此一个Pod随时都有可能离去,随时都有新的Pod可能会加进来,假设他们提供的都是同一种服务,我们的客户端是没办法通过固定的手段来访问这些Pod的,因为Pod本身是不固定的随时可能被替换掉,无论使用主机名还是IP地址都不可靠,所以这儿就需要用到服务发现机制;
Service流量调度
    因此为了尽可能降低二者之间协调的复杂的,Kubernetes为每一组提供同类服务的Pod和客户端之间添加了一个中间层,这个中间层是固定的,这个中间层就叫Service,Service只要不删除,它的地址和名称就是固定的,而后当客户端需要写在配置文件当中访问某一个服务的时候也不需要发现,不用自动发现某一个功能,他只需要在配置文件当中写入服务的名称和服务的地址即可,而这个服务是一个调度器,还能提供调度的功能,不但能提供稳定的访问入口还能提供调度Pod,一旦Pod宕机,新建的Pod会立即加入Service里面来,并把这个Pod作为后端的可用访问入口之一;
    因为客户端程序访问服务都是靠IP地址端口,而Service关联的后端的Pod不是靠Pod的IP地址来实现,Pod上面有一个固定的Label,只要创建的Pod的Label是统一的,不管地址怎么变化,都能被Service识别,因为Service是靠标签选择器来关联Pod对象的,所以只要Pod存在只要属于这一组标签选择器就能立即被Service作为后端组件存在,并且Service把Pod关联进来之后还会动态探测IP地址是什么,端口是什么,并作为自己调度的后端可用接口,因此客户端的请求到达Service,由Service代理至后端的Pod来实现;
    也就意味着客户端看见的可用服务都是Service的地址,而在Kubernetes之上Service可不是什么应用程序,也不是一个实体组件,只不过是一个iptables DNAT规则,更重要的是Service作为Kubernetes的对象来讲有Service的名称,而Service的名称也就是一个服务名称,而名称可以被解析,可以把Service名称直接解析成Service的IP,名称解析靠DNS来实现,我们装完Kubernetes的第一件事,就是在我们的Kubernetes上部署一个DNS的Pod,以确保各Service名称能被解析,这种Pod是Kubernetes自身需要的Pod,所以我们把它称之为基础系统架构级的对象,也被称为集群的附加组件;
    其实Kubernetes的附件DNS只是其中一个,并且这种DNS有一个特地点,它会动态改变,动态创建,动态删除,动态变动,比如我们把Service的名称改一改,它会自动触发DNS解析记录变更,假设我们手动把Service的地址改了,改完以后会自动触发DNS的解析记录修改的,所以以后客户端访问再去访问某一服务时,可直接去访问服务的名称,而后由集群中专用的DNS服务来进行解析,解析的是Service的地址,不是Pod的地址,因此访问依然是由Service来DNAT来实现,但是我们的Pod是有很多的资源的,那DNAT就是多目标的,对于多目标调度的时候,iptables已经把负载均衡的功能主要交给ipvs来实现,因此如果Service背后的同一类Pod有很多使用DNAT来实现,在调度效果上可能不是很好,因此在1.11版当中已经把其iptables规则进一步改成了ipvs规则,只不过它是NAT模型的ipvs,因此还支持用于自定义的各种调度算法;
    并且Service有两种,第一种可以只为Kubernetes内部集群所访问,第二种是可以直接暴露给集群外部的机器所访问;
    假设我们有一个数据中心,这个数据中心,有很多服务,那么我们可能只需要一个服务向外提供服务,那么最终的结果图应该就是这样的

Kubernetes网络模型

    在Kubernetes网络模型中很独特,它要求整个Kubernetes集群要有三种网络,第一种各Pod运行在同一个网络中,第二种Service运行在一个网络中,它是假的,它只存在于iptables或者ipvs规则当中,第三种就是节点的网络,一共三个网络;
    所以在接入外部访问时,得先接入节点网络,然后到达Service网络最后达到Pod网络,每一个Pod在使用时,Pod和Pod之间通信,在Kubernetes内还存在三种通信网络,因为一个Pod内可能有多个网络,所以同一Pod内的多个容器直接通过lo进行通信就行了,各Pod之间的通信可直接使用对应Pod的地址进行通信,但是如果Pod过多可能会产生广播风暴,那么另外还有一种解决方案,叫做Overlay Network叠加网络我们通过隧道的方式来转发二层报文,使得他们虽然跨主机,但可以表现问工作在同一个二层网络中一样从而实现叠加网络,因此这样一来Pod和Pod就可以直接通信了。
    Pod与Service通信,因为Pod有Pod独立的网络,Service也有Service的独立网络,那他们之间的通信从原理上来讲是不可达的,因为Service只不过是主机之上的iptables的规则地址,所以只需要由网关指向容器把报文指向不是自己,指向的是网关,网关假如是我们的docker0桥,因为iptables规则就在我们当前宿主机之上就有规则,这样一来每一个主机之上都有iptables规则,所以你只要创建一个Service,这个Service是要反映在Kubernetes的每个node上的,每个node都应该有相应的iptables或ipvs规则,如果有一个容器视图去访问Service地址时,它应该把请求送给网关,一般是docker0桥的地址,而docker0桥收到以后发现这个地址需要通过我们的iptables规则表进行检查就知道它到底在哪儿,就找到了它。
    因为Service随时也可能变动,比如删除了Service,或者Service背后的Pod改变了那么Service规则中目标地址也需要改变,如果Pod发生改变那么Service就需要使用标签选择器进行匹配并且获取地址,但是Service如何改变所有node的相关规则呢,那这个就需要一个专门的组件来实现,所以每一个node节点上需要一个组件,这个组件是运行在node之上的一个守护进行,它被称为kube-proxy,它负责随时与Api Server进行通信,因为每一个Pod发生变化之后这个结果需要保存在API Server当中的,对于API Server来说Pod发生改变之后会生成一个通知事件,这个事件可以被任何关联的组件接受到,比如我们的kube-proxy,一旦发现某一个Service背后的Pod地址发生改变,对应的由kube-proxy负责在本地反应在iptables火ipvs规则上,所以Service的管理是靠kube-proxy来实现的,创建一个Service需要靠kube-proxy在每一个node上创建规则,每一个Service的变动也需要kube-proxy来反应到规则上;
    这样一来我们的API Service需要存储整个集群当中的各组件的状态信息,那我们其他的master如何进行数据同步呢,那就涉及到共享存储,对于master主机来讲,所有的数据并不放置在master本地,而是放在共享存储里面,这个存储我们叫做Kubernetes的DB,也就是etcd,而etcd是一个键值存储系统,还支持各种协调工作,比如实现节点的选举啊等,所以etcd更像zookpeer,那etcd如果宕机了,那么整个集群就宕机了,所以etcd需要集群;
    etcd也是restfull风格的集群,可以通过http或https通信,etcd有三个端口一个端口集群内部通信,一个端口向客户的提供服务,也就意味着其内部通信需要点对点通信的证书,要想向客户的通信的需要另外一套证书来实习,而Kubernetes的API Server也需要使用https加密,所以从这个角度来讲,etcd自身需要一套证书,etcd作为服务端来讲它的客户端是API Server,而API Server需要向外部通信也需要一套证书。每个node组件有三个组件,API Server与kubelet进行通信使用https通信,所以我们要手动搭建Kubernetes是极其复杂的需要五套证书;
    所以整个Kubernetes集群是由三类节点组成的,master、etcd、node,他们彼此之间都是http或https通信,而后我们就可以在node之上运行Pod了,各种通信我们还需要构建多种网络出来,但是网络Kubernetes不提供,这还需要依赖于第三方组件来实现,无论是哪个服务商提供的网络管理方案它都应该负责管理两种网络,Pod网络和Service网络,节点网络在我们构建Kubernetes之前应该是就解决好了,而后Kubernetes通过CNI(容器网络接口)插件体系来接入外部网络服务解决方案,只要你是一个网络服务提供商,能遵循CNI开发服务,就能作为Kubernetes的网络解决方案,事实上,这些网络的解决方案可以以附件的方式托管在集群之上的Pod运行,而目前来讲能够作为附件运行的CNI的插件很多,常见的有flannel;
    其实我们网络需要两个维度,第一就是提供网络功能,给Pod提供IP地址给Service提供IP地址,第二Kubernetes的网络解决方案还要求它能够提供Network策略功能,来进行网络策略管理,进行容器隔离等,实际上也就是一些访问规则,因此我们要引入Kubernetes另外一个逻辑组件,叫做名称空间,Kubernetes的名称空间,整个Kubernetes是作为一个集群存在,我们将来可以在集群内部运行无数个Pod,都在同一个网络中,这么多的Pod,极有可能互相干扰,所以我们可以把他们切割成多个名称空间,一类Pod只运行在一个空间中,实现网络策略的管理;
    对于Kubernetes来讲,网络策略和网络功能是两个维度的东西,flannel只支持网络功能,叠加网络的实现,还有一个叫做calico既支持网络功能也支持网络策略,但是calico进行部署和实现有点难,它是一个三层隧道网络,但我们又想要两种想使用,所以就有了第三个方项目面世了,canel,它主要是结合flannel和calico,把他们搭配起来使用,用calico提供网络策略,用flannel来提供网络,他们都可以托管在Kubernetes集群之上;

Kubernetes各组件说明
    在整个Kubernetes集群当中,有很多组件,那么大致可以把他们分为主节点和工作节点两种类型,那么接下来就根据这两种类型的组件进行详细的介绍;
Master节点
kube-apiserver:提供了资源操作的统一入口,各组件协调者,HTTP API提供接口服务,所有对象资源的增删改查和监听都交给apiserver处理后再交给etcd存储,主要有认证、授权、访问控制、API 注册和发现等机制;
kube-scheduler: 负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上;
kube-controller-manager:处理集群中常规后台任务,一个资源对应一个控制器,而kube-controller-manager就是负责管理这些控制器的;
etcd:分布式键值对存储系统,保存了整个集群的状态,比如Pod、service等对象信息,就是一个数据库,只有API Server能与其通信;
coredns:负责为整个集群提供DNS服务;
Node节点
kube-proxy:负责为Service提供cluster内部的服务发现和负载均衡;
kubelet:kubelet是master再Node节点上的agent,管理本机运行容器的生命周期,比如创建容器,Pod挂载数据卷,获取容器和节点状态等工作,同时也负责Volume(CSI)和网络(CNI)的管理;
flannel:Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址,使得不同节点主机创建的Docker容器都可以进行互相访问;
docker:运行容器;
一个Pod的创建流程
    如下主要是对一个自主式Pod的创建流程进行解析;
1、kubectl向kubernetes的api-server发起一个create pod 请求(即我们使用Kubectl敲一个create pod命令);
2、kubernetes的api-server接收到pod创建请求后,不会去直接创建pod,而是生成一个包含创建信息的YAML,然后api-server会将这个信息存储到etcd中,到此为止仅仅是在etcd中添加了一条记录;
3、scheduler是运行在master节点的组件,它主要的功能是监听apiserver,来获取PodSpec.NodeName为空的Pod(类似于通知机制),因此先进行调度计算,找到最闲的node,然后为每个这样的Pod和挑选出来的Node创建一个bingding,这个bingding就表示这个Pod将绑定到哪一个Node(会经过挑选),然后将这个bingding信息写到etcd数据库中;
4、kubelet 通过监测etcd数据库(即不停地看etcd中的记录),发现Kubernetes的apiserver中有了个新的需要执行的任务记录,如果这条记录中的Node与自己的编号相同(即这个Pod由scheduler分配给自己了),则调用node中的docker api,创建container,container创建完成之后,kubelet会将这个Pod的信息反馈给apiserver,由apiserver去更新etcd中的信息;
Replication Controller
    Replication Controller为Kubernetes的一个核心内容,应用托管到Kubernetes之后,需要保证应用能够持续的运行,Replication Controller就是保证这个的,主要功能有以下几点;
1、确保pod数量,它会确保Kubernetes中有指定数量的Pod在运行。如果少于指定数量的pod,Replication Controller会创建新的,反之则会删除掉多余的以保证Pod数量不变;
2、确保pod健康,当pod不健康,运行出错或者无法提供服务时,Replication Controller也会杀死不健康的pod,重新创建新的;
3、弹性伸缩,在业务高峰或者低峰期的时候,可以通过Replication Controller动态的调整pod的数量来提高资源的利用率。同时,配置相应的监控功能(Hroizontal Pod Autoscaler),会定时自动从监控平台获取Replication Controller关联pod的整体资源使用情况,做到自动伸缩;
4、滚动升级,滚动升级为一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定,在初始化升级的时候就可以及时发现和解决问题,避免问题不断扩大;
Replica Sets
    Replica Sets是下一代的RC,它与RC当前存在的唯一区别是,它支持基于集合的Label selector; 而RC只支持基于等式的Label Selector,kubectl命令行工具适用于RC的绝大部分命令都同样适用于Replica Sets,当前我们很少单独使用Replica Set,它主要被Deployment 这个更高层的资源对象所使用,从而形成一整套Pod创建,删除更新的编排机制;
Deployment Controller
    Deployment同样为Kubernetes的一个核心内容,主要职责同样是为了保证pod的数量和健康,90%的功能与Replication Controller完全一样,可以看做新一代的Replication Controller。但是,它又具备了Replication Controller之外的新特性;
1、Replication Controller全部功能,Deployment继承了上面描述的Replication Controller全部功能;
2、事件和状态查看:可以查看Deployment的升级详细进度和状态;
3、回滚:当升级pod镜像或者相关参数的时候发现问题,可以使用回滚操作回滚到上一个稳定的版本或者指定的版本;
4、版本记录: 每一次对Deployment的操作,都能保存下来,给予后续可能的回滚使用;
5、暂停和启动:对于每一次升级,都能够随时暂停和启动;
6、多种升级方案;
    Recreate:删除所有已存在的pod,重新创建新的;
    RollingUpdate:滚动升级,逐步替换的策略,同时滚动升级时,支持更多的附加参数,例如设置最大不可用pod数量,最小升级间隔时间等等;

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注