Kubernetes的基本概念和术语

Kubernetes的基本概念和术语

Kubernetes中的大部分概念如

  • Node
  • Pod
  • Replication Controller
  • Service

等都可以被看作一种资源对象,几乎所有资源对象都可以通过Kubernetes提供的kubectl工具(或者API编程调用)执行增、删、改、查等操作并将其保存在etcd中持久化存储。

从这个角度来看,Kubernetes其实是一个高度自动化的资源控制系统,它通过跟踪对比etcd库里保存的资源期望状态与当前环境中的实际资源状态的差异来实现自动控制和自动纠错的高级功能。

在声明一个Kubernetes资源对象的时候,需要注意一个关键属性:apiVersion。以下面的Pod声明为例,可以看到Pod这种资源对象归属于v1这个核心API。

apiVersion: v1
kind: Pod
metadata:
  name: myweb
  labels:
    app: 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'

Kubernetes平台采用了“核心+外围扩展”的设计思路,在保持平台核心稳定的同时具备持续演进升级的优势。Kubernetes大部分常见的核心资源对象都归属于v1这个核心API,比如

  • Node
  • Pod
  • Service
  • Endpoints
  • Namespace
  • RC
  • PersistentVolume

在版本迭代过程中,Kubernetes先后扩展了

  • extensions/v1beta1
  • apps/v1beta1
  • apps/v1beta2

等API组,而在1.9版本之后引入了apps/v1这个正式的扩展API组,正式淘汰(deprecated)了extensions/v1beta1、apps/v1beta1、apps/v1beta2这三个API组。

我们可以采用YAMLJSON格式声明(定义或创建)一个Kubernetes资源对象,每个资源对象都有自己的特定语法格式(可以理解为数据库中一个特定的表),但随着Kubernetes版本的持续升级,一些资源对象会不断引入新的属性。为了在不影响当前功能的情况下引入对新特性的支持,我们通常会采用下面两种典型方法。

方法1

在设计数据库表的时候,在每个表中都增加一个很长的备注字段,之后扩展的数据以某种格式(如XML、JSON、简单字符串拼接等)放入备注字段。因为数据库表的结构没有发生变化,所以此时程序的改动范围是最小的,风险也更小,但看起来不太美观。

方法2

直接修改数据库表,增加一个或多个新的列,此时程序的改动范围较大,风险更大,但看起来比较美观。

显然,两种方法都不完美。更加优雅的做法是,先采用方法1实现这个新特性,经过几个版本的迭代,等新特性变得稳定成熟了以后,可以在后续版本中采用方法2升级到正式版。为此,Kubernetes为每个资源对象都增加了类似数据库表里备注字段的通用属性Annotations,以实现方法1的升级。

Master

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

在Master上运行着以下关键进程。

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

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

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

  • etcd:存储Kubernetes 里的所有的资源对象的数据都被保存在etcd 中。

Node

除了MasterKubernetes集群中的其他机器被称为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:

roverliang@roverliangdeMac-mini study % kubectl get nodes
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   21h   v1.18.3

查看Node 的详细信息:

# kubectl describe node __NODE_NAME__
kubectl describe node minikube

Pod

PodKubernetes最重要的基本概念,如图1.4所示是Pod的组成示意图,我们看到每个Pod都有一个特殊的被称为“根容器”的Pause容器

pod结构示意图

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直接通信,这通常采用虚拟二层网络技术来实现,例如FlannelOpen vSwitch等,因此我们需要牢记一点:在Kubernetes里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

Pod其实有两种类型:普通的Pod静态Pod(Static Pod)。后者比较特殊,它并没被存放在Kubernetesetcd存储里,而是被存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动、运行。

而普通的Pod一旦被创建,就会被放入etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动。

在默认情况下,当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,就会将这个Node上的所有Pod重新调度到其他节点上。Pod、容器与Node的关系如图1.5所示。

Pod、容器与Node的关系

Kubernetes里的所有资源对象都可以采用YAML或者JSON格式的文件来定义或描述,下面是我们在之前的Hello World例子里用到的myweb这个Pod的资源定义文件:

apiVersion: v1
kind: Pod
metadata:
  name: myweb
  labels:
    app: 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里还能定义资源对象的标签,这里声明myweb拥有一个name=myweb的标签。

在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。

我们所熟悉的Docker Volume在Kubernetes里也有对应的概念—Pod Volume,后者有一些扩展,比如可以用分布式文件系统GlusterFS实现后端存储功能;Pod Volume是被定义在Pod上,然后被各个容器挂载到自己的文件系统中的。

这里顺便提一下Kubernetes的Event概念。Event是一个事件的记录,记录了事件的最早产生时间、最后重现时间、重复次数、发起者、类型,以及导致此事件的原因等众多信息。Event通常会被关联到某个具体的资源对象上,是排查故障的重要参考信息,之前我们看到Node的描述信息包括了Event,而Pod同样有Event记录,当我们发现某个Pod迟迟无法创建时,可以用kubectl describe pod xxxx来查看它的描述信息,以定位问题的成因,比如下面这个Event记录信息表明Pod里的一个容器被探针检测为失败一次:

kubectl describe pod __YOUR_POD_NAME__

每个Pod都可以对其能使用的服务器上的计算资源设置限额,当前可以设置限额的计算资源有CPUMemory两种,其中CPU的资源单位为CPU(Core)的数量,是一个绝对值而非相对值。

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

由于CPU配额是一个绝对值,所以无论在拥有一个Core的机器上,还是在拥有48个Core的机器上,100m这个配额所代表的CPU的使用量都是一样的。与CPU配额类似,Memory配额也是一个绝对值,它的单位是内存字节数。

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

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

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

通常,我们会把Requests设置为一个较小的数值,符合容器平时的工作负载情况下的资源需求,而把Limit设置为峰值负载情况下资源占用的最大量。下面这段定义表明MySQL容器申请最少0.25个CPU及64MiB内存,在运行过程中MySQL容器所能使用的资源配额为0.5个CPU及128MiB内存:

spec:
  containers:
  - name: myweb
    image: kubeguide/tomcat-app:v1
    resources:
      requests:
        memoty: "64mi"
        cpu: "250m"
      limits: 
        memory: "128mi"
        cpu: "500m"

Pod及其pod周边对象

posted @ 2020-08-04 17:21  roverliang  阅读(180)  评论(0编辑  收藏  举报