基本概念和术语

大部分概念如Node、Pod、ReplicationController、Service等都可以看作一种“资源对象”,几乎所有的资源对象都可以通过Kubernetes提供的kubectl工具(或者API编程调用)执行增、删、改、查等操作并将其保存在etcd中持久化存储。从这个角度来看,Kubernetes其实是一个高度自动化的资源控制系统,它通过跟踪对比etcd库里保存的“资源期望状态”与当前环境中的“实际资源状态”的差异来实现自动控制和自动纠错的高级功能。

 

Master

 

Kubernetes里的Master指的是集群控制节点,每个Kubernetes集群里需要有一个Master节点来负责整个集群的管理和控制,基本上Kubernetes所有的控制命令都是发给它,它来负责具体的执行过程,我们后面所有执行的命令基本都是在Master节点上运行的。Master节点通常会占据一个独立的X86服务器(或者一个虚拟机),一个主要的原因是它太重要了,它是整个集群的“首脑”,如果它宕机或者不可用,那么我们所有的控制命令都将失效。

 

Master节点上运行着以下一组关键进程。

 

    Kubernetes API Server(kube-apiserver),提供了HTTP Rest接口的关键服务进程,是Kubernetes里所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程。

    Kubernetes Controller Manager(kube-controller-manager),Kubernetes里所有资源对象的自动化控制中心,可以理解为资源对象的“大总管”。

    Kubernetes Scheduler(kube-scheduler),负责资源调度(Pod调度)的进程,相当于公交公司的“调度室”。

其实Master节点上往往还启动了一个etcd Server进程,因为Kubernetes里的所有资源对象的数据全部是保存在etcd中的。

 

 

 

Node

 

除了Master,Kubernetes集群中的其他机器被称为Node节点,在较早的版本中也被称为Minion。与Master一样,Node节点可以是一台物理主机,也可以是一台虚拟机。Node节点才是Kubernetes集群中的工作负载节点,每个Node都会被Master分配一些工作负载(Docker容器),当某个Node宕机时,其上的工作负载会被Master自动转移到其他节点上去。

 

每个Node节点上都运行着以下一组关键进程。

 

 

kubelet:负责Pod对应的容器的创建、启停等任务,同时与Master节点密切协作,实现集群管理的基本功能。

kube-proxy:实现Kubernetes Service的通信与负载均衡机制的重要组件。

Docker Engine(docker):Docker引擎,负责本机的容器创建和管理工作。

 

Node节点可以在运行期间动态增加到Kubernetes集群中,前提是这个节点上已经正确安装、配置和启动了上述关键进程,在默认情况下kubelet会向Master注册自己,这也是Kubernetes推荐的Node管理方式。一旦Node被纳入集群管理范围,kubelet进程就会定时向Master节点汇报自身的情报,例如操作系统、Docker版本、机器的CPU和内存情况,以及之前有哪些Pod在运行等,这样Master可以获知每个Node的资源使用情况,并实现高效均衡的资源调度策略。而某个Node超过指定时间不上报信息时,会被Master判定为“失联”,Node的状态被标记为不可用(Not Ready),随后Master会触发“工作负载大转移”的自动流程。

 

查看集群中有多少个Node:   kubectl get nodes

 

查看某个Node的详细信息:  kubectl describe node <node_name>

 

 

 

Node基本信息:名称、标签、创建时间等。

Node当前的运行状态,Node启动以后会做一系列的自检工作,比如磁盘是否满了,如果满了就标注OutOfDisk=True,否则继续检查内存是否不足(MemoryPressure=True),最后一切正常,就切换为Ready状态(Ready=True),这种情况表示Node处于健康状态,可以在其上创建新的Pod。

Node的主机地址与主机名。

Node上的资源总量:描述Node可用的系统资源,包括CPU、内存数量、最大可调度Pod数量等,注意到目前Kubernetes已经实验性地支持GPU资源分配了(alpha.kubernetes.io/nvidia-gpu=0)。

Node可分配资源量:描述Node当前可用于分配的资源量。

主机系统信息:包括主机的唯一标识UUID、Linux kernel版本号、操作系统类型与版本、Kubernetes版本号、kubelet与kube-proxy的版本号等。

当前正在运行的Pod列表概要信息。

已分配的资源使用概要信息,例如资源申请的最低、最大允许使用量占系统总量的百分比。

Node相关的Event信息。

 

 

 

——————————————————————————————————————

Pod

 

Pod是Kubernetes的最重要也最基本的概念,如图所示是Pod的组成示意图,我们看到每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。

 

 

 

 

为什么Kubernetes会设计出一个全新的Pod的概念并且Pod有这样特殊的组成结构?

 

原因之一:在一组容器作为一个单元的情况下,我们难以对“整体”简单地进行判断及有效地进行行动。比如,一个容器死亡了,此时算是整体死亡么?是N/M的死亡率么?引入业务无关并且不易死亡的Pause容器作为Pod的根容器,以它的状态代表整个容器组的状态,就简单、巧妙地解决了这个难题。

 

原因之二:Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。

 

Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP地址。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,这通常采用虚拟二层网络技术来实现,例如Flannel、Openvswitch等,因此我们需要牢记一点:在Kubernetes里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

 

Pod其实有两种类型:普通的Pod及静态Pod(static Pod),后者比较特殊,它并不存放在Kubernetes的etcd存储里,而是存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。而普通的Pod一旦被创建,就会被放入到etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动起来。在默认情况下,当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上。

 

Pod、容器与Node的关系

Kubernetes里的所有资源对象都可以采用yaml或者JSON格式的文件来定义或描述

Node描述文件:

 

     apiVersion: v1

     kind: Pod

     metadata:

       name: myweb

       labels:

         name: myweb

     spec:

       containers:

       - name: myweb

         image: kubeguide/tomcat-app:v1

         ports:

         - containerPort: 8080

         env:

         - name: MYSQL_SERVICE_HOST

           value: 'mysql'

         - name: MYSQL_SERVICE_PORT

           value: '3306'

 

 

 

Kind为Pod表明这是一个Pod的定义,metadata里的name属性为Pod的名字,metadata里还能定义资源对象的标签(Label),这里声明myweb拥有一个name=myweb的标签(Label)。Pod里所包含的容器组的定义则在spec一节中声明,这里定义了一个名字为myweb、对应镜像为kubeguide/tomcat-app:v1的容器,该容器注入了名为MYSQL_SERVICE_HOST=‘mysql’和MYSQL_SERVICE_PORT=‘3306’的环境变量(env关键字),并且在8080端口(containerPort)上启动容器进程。Pod的IP加上这里的容器端口(containerPort),就组成了一个新的概念——Endpoint,它代表着此Pod里的一个服务进程的对外通信地址。一个Pod也存在着具有多个Endpoint的情况,比如当我们把Tomcat定义为一个Pod的时候,可以对外暴露管理端口与服务端口这两个Endpoint。

 

一个CPU的配额对于绝大多数容器来说是相当大的一个资源配额了,通常以千分之一的CPU配额为最小单位,用m来表示。通常一个容器的CPU配额被定义为100~300m,即占用0.1~0.3个CPU。

 

在Kubernetes里,一个计算资源进行配额限定需要设定以下两个参数。

    Requests:该资源的最小申请量,系统必须满足要求。

    Limits:该资源最大允许使用的量,不能被突破,当容器试图使用超过这个量的资源时,可能会被Kubernetes Kill并重启

 

Pod及Pod周边对象的示意图

 

Pod Volume是定义在Pod之上,然后被各个容器挂载到自己的文件系统中的。

Event是一个事件的记录,记录了事件的最早产生时间、最后重现时间、重复次数、发起者、类型,以及导致此事件的原因等众多信息。

 

————————————————————————————————

Label

Label是Kubernetes系统中另外一个核心概念。一个Label是一个key=value的键值对,其中key与value由用户自己指定。Label可以附加到各种资源对象上,例如Node、Pod、Service、RC等,一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去,Label通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。

 

我们可以通过给指定的资源对象捆绑一个或多个不同的Label来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等管理工作。

 

Label相当于我们熟悉的“标签”,给某个资源对象定义一个Label,就相当于给它打了一个标签,随后可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,Kubernetes通过这种方式实现了类似SQL的简单又通用的对象查询机制。

 

Label Selector在Kubernetes中的重要使用场景有以下几处。

 

    kube-controller进程通过资源对象RC上定义的Label Selector来筛选要监控的Pod副本的数量,从而实现Pod副本的数量始终符合预期设定的全自动控制流程。 

    kube-proxy进程通过Service的Label Selector来选择对应的Pod,自动建立起每个Service到对应Pod的请求转发路由表,从而实现Service的智能负载均衡机制。

    通过对某些Node定义特定的Label,并且在Pod定义文件中使用NodeSelector这种标签调度策略,kube-scheduler进程可以实现Pod“定向调度”的特性。

 

 

使用Label可以给对象创建多组标签,Label和LabelSelector共同构成了Kubernetes系统中最核心的应用模型,使得被管理对象能够被精细地分组管理,同时实现了整个集群的高可用性。

 

 

-------------------------------------------------------------------

 

Replication Controller(RC)

 

RC是Kubernetes系统中的核心概念之一,简单来说,它其实是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分。

 

Pod期待的副本数(replicas)。

用于筛选目标Pod的Label Selector。

当Pod的副本数量小于预期数量的时候,用于创建新Pod的Pod模板(template)。

 

下面是一个完整的RC定义的例子,即确保拥有tier=frontend标签的这个Pod(运行Tomcat容器)在整个Kubernetes集群中始终只有一个副本。

 

当我们定义了一个RC并提交到Kubernetes集群中以后,Master节点上的Controller Manager组件就得到通知,定期巡检系统中当前存活的目标Pod,并确保目标Pod实例的数量刚好等于此RC的期望值,如果有过多的Pod副本在运行,系统就会停掉一些Pod,否则系统就会再自动创建一些Pod。可以说,通过RC,Kubernetes实现了用户应用集群的高可用性,并且大大减少了系统管理员在传统IT环境中需要完成的许多手工运维工作(如主机监控脚本、应用监控脚本、故障恢复脚本等)。

 

 

 

在运行时,我们可以通过修改RC的副本数量,来实现Pod的动态缩放(Scaling)功能,这可以通过执行kubectl scale命令来一键完成:

 

 

需要注意的是,删除RC并不会影响通过该RC已创建好的Pod。为了删除所有Pod,可以设置replicas的值为0,然后更新该RC。另外,kubectl提供了stop和delete命令来一次性删除RC和RC控制的全部Pod。

 

当我们的应用升级时,通常会通过Build一个新的Docker镜像,并用新的镜像版本来替代旧的版本的方式达到目的。在系统升级的过程中,我们希望是平滑的方式,比如当前系统中10个对应的旧版本的Pod,最佳的方式是旧版本的Pod每次停止一个,同时创建一个新版本的Pod,在整个升级过程中,此消彼长,而运行中的Pod数量始终是10个,几分钟以后,当所有的Pod都已经是新版本的时候,升级过程完成。通过RC的机制,Kubernetes很容易就实现了这种高级实用的特性,被称为“滚动升级”(Rolling Update)。

 

 

Replica Set,官方解释为“下一代的RC”,它与RC当前存在的唯一区别是:Replica Sets支持基于集合的Label selector(Set-based selector),而RC只支持基于等式的Label Selector(equality-based selector)。

 

Replica Set与Deployment这两个重要资源对象逐步替换了之前的RC的作用。

 

最后我们总结一下关于RC(Replica Set)的一些特性与作用。

 

    在大多数情况下,我们通过定义一个RC实现Pod的创建过程及副本数量的自动控制。

    RC里包括完整的Pod定义模板。

    RC通过Label Selector机制实现对Pod副本的自动控制。

    通过改变RC里的Pod副本数量,可以实现Pod的扩容或缩容功能。

    通过改变RC里Pod模板中的镜像版本,可以实现Pod的滚动升级功能。

 

 

——————————————————————————————————————————

Deployment

 

Deployment是Kubernetes 1.2引入的新概念,引入的目的是为了更好地解决Pod的编排问题。为此,Deployment在内部使用了Replica Set来实现目的,无论从Deployment的作用与目的、它的YAM定义,还是从它的具体命令行操作来看,我们都可以把它看作RC的一次升级,两者的相似度超过90%。

 

Deployment相对于RC的一个最大升级是我们可以随时知道当前Pod“部署”的进度。实际上由于一个Pod的创建、调度、绑定节点及在目标Node上启动对应的容器这一完整过程需要一定的时间,所以我们期待系统启动N个Pod副本的目标状态,实际上是一个连续变化的“部署过程”导致的最终状态。

 

Deployment的典型使用场景有以下几个。

 

    创建一个Deployment对象来生成对应的Replica Set并完成Pod副本的创建过程。

    检查Deployment的状态来看部署动作是否完成(Pod副本的数量是否达到预期的值)。

    更新Deployment以创建新的Pod(比如镜像升级)。

    如果当前Deployment不稳定,则回滚到一个早先的Deployment版本。

    挂起或者恢复一个Deployment。

 

------------------------------------------------------------------------------------------

 

Horizontal Pod Autoscaler(HPA)

 

智能自动扩容,意思是Pod横向自动扩容

 

 

--------------------------------------------------------------------------------------------

 

Service(服务)

 

 

Service也是Kubernetes里的最核心的资源对象之一,Kubernetes里的每个Service其实就是我们经常提起的微服务架构中的一个“微服务”,之前我们所说的Pod、RC等资源对象其实都是为这节所说的“服务”——Kubernetes Service做“嫁衣”的。

 

 

 

从图1.14中我们看到,Kubernetes的Service定义了一个服务的访问入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与其后端Pod副本集群之间则是通过Label Selector来实现“无缝对接”的。而RC的作用实际上是保证Service的服务能力和服务质量始终处于预期的标准。

 

既然每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了一个独立的Endpoint(Pod IP+ContainerPort)以被客户端访问,现在多个Pod副本组成了一个集群来提供服务,那么客户端如何来访问它们呢?一般的做法是部署一个负载均衡器(软件或硬件),为这组Pod开启一个对外的服务端口如8000端口,并且将这些Pod的Endpoint列表加入8000端口的转发列表中,客户端就可以通过负载均衡器的对外IP地址+服务端口来访问此服务,而客户端的请求最后会被转发到哪个Pod,则由负载均衡器的算法所决定。

 

运行在每个Node上的kube-proxy进程其实就是一个智能的软件负载均衡器,它负责把对Service的请求转发到后端的某个Pod实例上,并在内部实现服务的负载均衡与会话保持机制。但Kubernetes发明了一种很巧妙又影响深远的设计:Service不是共用一个负载均衡器的IP地址,而是每个Service分配了一个全局唯一的虚拟IP地址,这个虚拟IP被称为Cluster IP。这样一来,每个服务就变成了具备唯一IP地址的“通信节点”,服务调用就变成了最基础的TCP网络通信问题。

 

我们知道,Pod的Endpoint地址会随着Pod的销毁和重新创建而发生改变,因为新Pod的IP地址与之前旧Pod的不同。而Service一旦创建,Kubernetes就会自动为它分配一个可用的Cluster IP,而且在Service的整个生命周期内,它的Cluster IP不会发生改变。于是,服务发现这个棘手的问题在Kubernetes的架构里也得以轻松解决:只要用Service的Name与Service的Cluster IP地址做一个DNS域名映射即可完美解决问题。现在想想,这真是一个很棒的设计。

 

-----------------------------------------------------------------------------------------

 

Volume(存储卷)

 

Volume是Pod中能够被多个容器访问的共享目录。首先,Kubernetes中的Volume定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下;其次,Kubernetes中的Volume与Pod的生命周期相同,但与容器的生命周期不相关,当容器终止或者重启时,Volume中的数据也不会丢失。最后,Kubernetes支持多种类型的Volume,例如GlusterFS、Ceph等先进的分布式文件系统。

 

Kubernetes提供了非常丰富的Volume类型:

1.emptyDir:Kubernetes自动分配的一个目录,在Pod分配到Node时创建的

2.hostPath:使用宿主机的/data目录定义了一个hostPath类型的Volume

3.gcePersistentDisk:表示使用谷歌公有云提供的永久磁盘(Persistent Disk)存放Volume的数据

4.awsElasticBlockStore:使用亚马逊公有云提供的EBS Volume存储数据

5.NFS:部署一个NFS Server,NFS网络文件系统提供的共享目录存储数据

 

----------------------------------------------------------------------------------------------

 

Persistent Volume

 

PV可以理解成Kubernetes集群中的某个网络存储中对应的一块存储,定义一个网络存储,然后从中划出一个“网盘”并挂接到虚机上。

 

PV只能是网络存储,不属于任何Node,但可以在每个Node上访问。

PV并不是定义在Pod上的,而是独立于Pod之外定义。

PV目前只有几种类型:GCE Persistent Disks、NFS、RBD、iSCSCI、AWS ElasticBlockStore、GlusterFS等。

 

PV的accessModes属性:

ReadWriteOnce:读写权限、并且只能被单个Node挂载。

ReadOnlyMany:只读权限、允许被多个Node挂载。

ReadWriteMany:读写权限、允许被多个Node挂载。

 

如果某个Pod想申请某种条件的PV,则首先需要定义一个PersistentVolumeClaim(PVC)对象

 

----------------------------------------------------------------------------------------

 

Namespace(命名空间)

 

Namespace在很多情况下用于实现多租户的资源隔离。Namespace通过将集群内部的资源对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值