Kubernetes是什么?
他是一个全新的基于容器技术分布式架构领先方案;
他也是一个开放的开发平台;
他也是一个完备的分布式系统支撑平台;
Kubernetes的基本慨念和术语
- Master
Kubernetes 里的Master 指的是集群控制节点,每个Kubernetes 集群里需要有一个 Master 节点负责整个集群的管理和控制,基本上Kuberneter所有的控制命令都发给它,他来负责具体的执行过程,我们后面所执行的所有命令基本上都是在Master节点上运行的。Masteer通常会占用一个独立的服务器(高可用部署建议用三台服务器);
Master节点上运行着一组关键进程
a). Kubernetes API Server(kube-apiserver):提供了HTTP Rest 接口的关键进程,是Kubernetes里所有资源增、删、改、查等操作的统一入口,也是集群控制的入口进程。
b). Kubernetes Controller Manager(kub-controller-manager):Kubernetes 里所有资源对象的自动化控制中心,可以理解为资源对象的“大总管”;
c). Kubernetes Scheduer(kub-scheduler):负责资源调度(pod调度)的进程;
d). Masternetes 节点上还需要启动一个etcd服务,因为Kubernetes 上所有的资源对象全部保存在etcd中的;
- Node
除了Mater节点外,Kubernetes集群中其他机器的节点被称为Node节点,在较早的版本中也被称为Minion。与Master一样,Node节点可以是一台物理机,也可以是一台虚拟机。Node节点才是Kubernetes集群中的工作负载节点,每个Node节点都会被Master分配一些工作负载(Docker容器),当某个Node宕机时,其上的工作负载会被Master节点自动转移到其他节点上去的。
每个Node节点上都都运行着一组关键进程
a)kubelet:负责Pod 对应的容器的创建、启停等任务,同时与Master 节点密切协作,实现集群管理的基本功能。
b)kube-proxy:实现Kubernetes Server 的通信与负载均衡机制的重要组件。
c)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
然后通过kubectl describe node <node-name>查看某个Node 节点的详细信息:
- Pod
Pod的基本组成:
每个Pod都有一个特殊地被称为”根容器“的Pause的容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。
通过kubectl get pods查看所有pod列表
为什么Pod会设计出一个全新的Pod概念并且对Pod有这样特殊的组成结构?
原因之一:在一组容器作为一个单元的情况下,我们难以对“整体”简单地的进行判断及有效地进行运动。比如,一个容器死亡了,此时算是整体死亡?是N/M的死亡率?引入业务无关且不易死亡的Pause容器作为Pod的根容器,以他的状态代表整个容器组的状态,就简单、巧妙的解决了这个问题。
原因之二:Pod里的uoge业务容器共享Pause容器的IP,共享Pause容器挂载的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好的解决了他们之间的文件共享问题。
Kubernetes为每个Pod都分配了一个唯一的IP地址,称为Pod IP,一个Pod里的多个容器共享Pod IP地址。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,这通常采用虚拟二层网络技术来实现,例如Flannel、Open vSwitch等。因此,我们需要牢记一点:在Kubernetes中,一个Pod里的容器与另外主机上的Pod里的容器可以直接通信。
Pod其实有两种类型:普通的Pod和静态的Pod(Static Pod),后者比较特殊,他并不存放在Kubernetes的etcd存储里,而是存放在某个具体的Node上的一个具体的文件中,并且只在该Node上启动运行。而普通的Pod一旦被创建,就会被放入到etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上进行绑定(Binding)。随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docke容器并存储起来。在默认情况下,当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node节点上的所有Pod重新调度到其他Node节点上。
Pod、容器和Node的关系如下所示:
- Label
Label是Kubernetes里的另外一个核心概念。一个Label是一个key=value的键值对,其中key与value由用户自己指定。Label可以附加到各种资源对象上,例如Node、Pod、Service、RC等,一个资源对象可以定义任意数量的label,同一个Label也可以被添加到任意数量的资源对象上去,Label通常在资源对象定义时被确定,也可以在对象创建后动态的添加或者删除。
我们可以通过给指定的资源对象捆绑一个或多个不同的Label来实现多维度的资源分组管理功能,以便灵活、方便的进行资源分配、调度、配置、部署等管理工作。例如:部署不同的版本的应用到不同的环境中;或者监控和分析应用(日志记录、监控、告警)等。一些常用的Label标签如下。
版本标签:”release“:”stable“,”release“:“canary”....
环境标签:”environment“:”dev“,”environment”:“qa”,“environment”:“producetion”
架构标签:“tier”:“frontend”,“tier”:“backend”,“tier”:“middleware”
分区标签:“partition”:“customerA”,“partition”:“customerB”....
质量管控标签:“track”:“daily”,“track”:“weekly”
Label相当于我们熟悉的“标签”,给某个资源对象定义一个Label,就相当于给他打了一个标签,随后可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象,Kubernetes通过这种方式实现了类似SQL的简单又通用的对象查询机制。
Label Selector 可以类比为SQL语句中的where查询条件,例如,name=redis-slave这个Label Selector 作用于Pod时,可以类比为select * from pod where pod_name = 'redis-slave'这样的语句。当前者有两种不同的Label Selector 的表达式:基于等式的(Equality-based)和基于集合的(Set-based),前者采用“等式类”的表达式匹配标签,下面是一些具体的例子。
name = redis-server:匹配所有具有标签 nameredis-server的资源对象。
env != production:匹配所有不具有标签 env=prouction 的资源对象。
而后者则使用集合操作的表达式匹配标签,下面是一些具体的例子。
name in (redis-master,redis-slave):匹配所有具有标签的nameredis-master或者nameredis-slave的资源对象。
name not in (php-frontend) :匹配所有不具有标签namepho-frontend的资源对象。
可以通过多个Label Selector 表达式的组合实现复杂的条件选择,多个表达式之间用“,”进行分割,几个条件之间是“and”的关系,即同时满足多个条件,比如下面的例子:
name = redis-server,env != production
Label Selector 在Kubernetes 中的重要使用场景有以下几处。
a)kube-controller 进程通过资源对象RC上定义的Label Selector 来筛选要监控的Pod副本的数量,从而实现Pod副本的数量始终负荷预期设定的全自动流程控制。
b) kueb-proxy 进程通过Service 的 Label Selector 来选择对应的Pod,自动建立起每个Service到对应Pod的请求转发路由表,从而实现Servicce的智能负载均衡机制。
c)通过对某些Node 定义特定的Label,并且在Pod定义文件中使用NodeSelector这种标签调度策略,kube-scheduler进程可以实现Pod定向调度的策略。
总结:使用Label 可以给对象创建更多组标签,Label 和 Label Selector 共同构成了Kubernetes 系统中最核心的应用模型,使得被管理者对象能够被精细地分组管理,同时实现了整个集群的高可用性。
- Replication Controller
Replication Controller (简称RC),RC是Kubernetes的核心概念之一,简单地说,他其实是定义了一个期望的场景,即声明了某种Pod的副本的数量在任意时刻都符合某个预期值,所有RC的定义包括以下几个部分:
a)Pod期待的副本数(replicas)
b)用于筛选目标Pod的Label Selector。
c)当Pod的副本数量小于预期值时,用于创建新Pod的Pod 模板(template)。
当我们定义了一个RC并提交到Kubernetes集群中以后,Master节点上的Controller Manager组件就会收到通知,定期巡检系统当中的当前存活的目标Pod,并确保目标Pod实例数量刚好等于此RC的期望值,如果有过多的Pod副本在运行,系统就会停掉一些Pod,否则系统就会再手动创建一些Pod。可以说,通过RC,Kubernetes实现了用户应用集群的高可用性,并且大大减少了系统管理员再传统IT环境中需要手动完成的许多运维工作(如主机监控脚本、应用监控脚本、故障恢复脚本等)。
----通过RC,Kubernetes很容易就实现了这种高级实用的特性,被称为“滚动升级”,具体的操作方法以后在做分析。
由于Replication Controller 与 Kubernetes代码中的模块Replication Controller同名,同时这个词也无法准确表达他的本意,所以在Kubernetes v1.2时,他就升级成了另外一个概念-------Replica Set,官方解释为“下一代的RC”,它与RC当前存在的唯一区别是:Replica Set支持基于集合的Label Selector(Set-based selector),而RC只支持基于等式的Label Selector(equality-based selector),这使得Replica Set的功能更强。
kubectl命令行使用与RC的绝大部分命令同样也适用于Replica Set。此外,当前我们很少单独使用Replica Set,它主要是被Deployment这个更高层级的资源对象所使用,从而形成一套完整的Pod创建、删除、更新的编排机制。当我们使用Deplyment时,无须关心他说如何创建和维护Replica Set的,这一切都是自动发生的。
Replica Set和Deployment这两个重要的资源对象逐步替换看之前的RC的作用,时Kubernetes v1.3里的Pod自动扩容(伸缩)这个告警功能实现的基础,也将继续在Kubernetes未来的版本中发挥重要作用。
总结RC(Replica Set)的一些特性和作用。
a)在大多数情况下,我们通过定义一个RC实现Pod的传教过程及副本数量的自动过程。
b)RC里包含完整的Pod定义模板。
c)RC通过Label Selector机制实现对Pod副本的自动控制。
d)通过改变RC里的Pod的副本数量,可以实现Pod的扩容与缩容功能。
e)通过改变RC里Pod模板的镜像版本,可以实现Pod的滚动升级功能。
- Deployment
Deployment 是Kubernetes v1.2引入的概念,引入的目的是欸蓝更好的解决Pod的编排问题。为此,Deployment 在内部使用了 Replica Set 来实现目的的,无论从Deployment 的作用与目的、它的YAML定义,还是从它的具体命令行操作来看,我们都可以把它看作RC的一次升级,两者的相似度超过90%。
Deployment相对于RC的最大一个升级时我们可以随时知道当前Pof“部署”的进度。实际上由于一个Po的创建、调度、绑定节点及在目标Node上启动对应的的容器这一完整的过程需要一定的时间,所以我们期待系统启动N个Pod副本的目标状态,实际上是一个连续变化的“部署过程”导致的最终状态。
Deployment典型使用场景有以下几个:
a)创建一个Deployment对象来生成对应的Replica Set 并完成Pod副本的创建过程。
b)检查Deployment的状态来看部署动作是否完成(Pod副本的数量是达到预期的值)。
c)更新Deployment以创建新的Pod(比如镜像升级)。
d)如果当前Deployment不稳定,则回滚到一个早先的Deployment版本。
e)暂停Deployment 以便一次性修改多个PodTemplateSpec 的配置项,之后再恢复Deployment,进行新的发布。
f)扩展Deployment以应对高负载。
g)查看 Deployment 的状态,以此作为发布是否成功的标志。
h)清理不再需要的旧的 ReplicaSets。
运行下面命令可以查看 Deployment 的信息
kubectl get deployments
Pod 的管理对象,除了RC和Deployment,还包括ReplicaSet、DaemonSet、StatefulSet、Job等,分别用于不同的业务场景,具体以后再分析。
- Horizontal Pod Autoscaler
以往我们通过手动执行kubectl scale 命令,我们可以实现Pod扩容和缩容。如果仅仅至此为止,显然不符合谷歌对Kubernetes 的定位目标----自动化、智能化。再谷歌看来,分布式系统要能够根据当前负载的变化情况触发水平扩展或缩容的行为,因为这一过程可能是频繁发生的、不可预料的,所以手动控制的方式是不现实的。
- StatefulSet
在Kubernetes 中,Pod 的管理对象RC、Deployment、DaemonSet和job都是面向无状态的服务。但是现实中有很多服务是由状态的,特别是一些负载的中间件集群,例如MYsQL集群、MongoDB集群、Akka集群、Zookeeper集群等,这些应用集群都有以下一些特点。
a) 每个节点都有固定的省份ID,通过这个ID,集群中的成员可以相互发现并通讯。
b) 集群的规模是比较固定的,集群规模不能随意的变动。
c) 集群里的每个节点都是有状态的,通常会持久化数据到永久存储中。
d) 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。
如果用RC/Deployment控制Pod副本数的方式来实现上述有状态的集群,则我们会发现第一点是无法满足的,因为Pod的名字是随机产生的,Pod的ID地址也是在运行期才确定是否有变动的,我们事先无法为每个Pod确定一个唯一不便的ID,另外,为了能够在其他节点上恢复这个失败的节点,这中集群中的Pod需要挂接某种共享存储,为了解决这个问题,Kubernetes v1.4版本开始引入PetSet 这个新的资源对象,并且在 v1.5版本时更名为StatefulSet,StatefulSet从本质上来说,可以看着是Deployment/RC的一个特殊变种,它有如下的一些特性:
a)StatefulSet 里的每一个Pod 都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet的名字叫kafka,那么第一个Pod叫kafka-0,第二个叫kafka-1,以此类推。
b)StatefulSet 控制的Pod副本的启停顺序是受控的,操作第n个Pod时,前n-1 个Pod已经是运行且准备好的状态。
c)StatefulSet 里的Pod 采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod 时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全)。
- Service
Kubernetes 里的每个Servcice 其实就是我们经常提到的微服务架构中的一个“微服务”,之前我们所说的Pod、RC等资源对象其实都是为这节所说的“服务”-----Kubernetes Service作“嫁衣”的。
后面会单独针对Service做讲解,这里首先知道有这么一个对象存在就行。
- Volume(存储卷)
Volume 是Pod 中能够被多个容器访问的共享目录。Kubernetes 的 Volume 概念、用途和目的与Docker的Volume比较相似,但两者不能等价。首先,Kubernetes中的Volume定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下;其次,Kubernetes中的Volume与Pod的生命周期相同,但是与容器的生命周期不相关,当容器终止或重启时,Volume中的数据也不会丢失。最后,Kubernetes支持多种类型的Voume,例如 ClusterFS、Geph等先进的分布式文件系统。
Kuberneter 提供了非常丰富的Volume 类型:
1.emptyDir
2.hosyPath
3.gcePersistentDisk
4.awsElasticBlockStore
5.NFS
- Persistent Volume
前面我们说的Volume是定义在Pod上的,属于“计算资源”的一部分,而实际上。“网络存储”是相对独立于“计算资源”而存在的一种实体资源。比如在使用虚拟机的情况下,我们通常会先定义一个网络存储,然后从中划出一个“网盘”并接到虚拟机上。Persistent Volume (简称 PV)和与之相关的 Persistent Volume Claim (简称 PVC)也起到了类似的作用。
PV可以理解成是 Kubernetes 集群中的某个网络存储中对应的一块存储,他与 Volume 很类似,但又以下区别:
a)PV只能是网络存储,不属于任何 Node,但可以在每个 Node 上访问。
b)PV 并不是定义在 Pod 上的,而是独立于 Pod 之外定义的。
c)PV 目前支持的类型有:gcePersistentDisk、awsElasticBlockStore、AzureFile、AzureDisk、FC(Fibre Channel)、Flocker、NFS、iSCSI....等等,这里就不一一例举了。
PV 是有状态的对象,它有以下几种状态:
a)Available:空闲状态。
b)Bound:已经绑定到某个 PVC 上。
c)Released:对应的PVC 已经删除,但资源还没被集群回收。
d)Failed:PV 自动回收失败。
- Namespace(命名空间)
Namespace(命名空间)是Kubernetes 系统中一个非常重要的概念,Namespace在很多情况下用于实现多租户的资源隔离。Namespace 通过将集群内部的资源对象“分配”到不同的Namespace 中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
Kubernetes 集群在启动后,会创建一个名为“default”的Namespace,通过 kubectl可以查到:
kubectl get namespace:
- Annotation
Annotation于 Label 类似,也使用key/value 键值对的形式进行定义。不同的是Label 具有严格的命名规范,它的定义是 Kubernetes 对象的元数据(Metadata),并且用于 Label Selector。而 Annotation 则是任意定义的“附加”信息,以便外部工具进行查找,很多时候 Kubernetes 的模块自身会通过 Annotation 的方式标记资源对象的一些特殊信息。通常来说,用Annotation 来记录的信息如下:
a)build信息、release信息、Docker镜像信息等,例如时间戳、release id 号、PR 好、镜像 hash值、docker registry 地址等。
b)日志库、监控库、分析库等资源库的地址信息。
c)程序调式工具信息,例如工具名称、把本号等。
d)团队的联系信息,例如电话号码、负责人名称、网址等。
小结
上述这些组件是Kubernetes 系统的核心组件,他们共同组成了 Kubernetes 系统的框架和计算模型。除了上述所介绍的核心组件,在Kubernetes 中还有许多辅助配置的资源对象,例如LimitRange、ResourceQuota。另外,一些系统内部使用的对象 Binging、Event等参考Kubernetes的API文档。