Kubernetes基本概念与组件

Kubernetes(简称 K8S) 的出现是容器化技术发展的必然结果,容器化是应用程序级别的虚拟化,运行单个内核上有多个独立的用户空间实例,这些实例就是容器;容器提供了将应用程序的代码、运行时、系统工具、系统库和配置打包到一个实例中的标准方法,而且容器是共享一个内核的;由于容器技术的兴起,导致大量的容器应用出现,所以就出现了一些用来支持应用程序容器化部署和组织的容器编排技术,一些流行的开源容器编排工具有 Docker Swarm、Kubernetes 等,但是在发展过程中 Kubernetes 现在已经成为了容器编排领域事实上的一个标准了。

架构

未命名文件 (2).png
Kubernetes由master和Node两种节点构成,分别对应着控制节点和工作节点。

其中master节点由三个独立的组件构成,分别是:

  • kube-apiserver:负责整个集群的通信的api服务;
  • kube-schedule:负责容器调度;
  • kube-controller-manager:负责维护集群状态。

整个集群的数据都是通过kube-apiserver保存到etcd数据库中的,而其他的所有组件的通信也都是通过kube-apiserver和etcd进行通信的。

node节点最核心的组件就是kubelet,还有底层的容器运行时,比如docker,其中kubelet主要实现和底层的容器运行时进行通信的。这个通信的过程也被kubernetes抽象成一个CRI(Container Runtime Interface)的远程调用接口,这个接口定义了容器运行时的所有标准操作,比如容器的创建、删除等,只是目前kubelet里面内置了docker关于这个CRI实现的一个shim,所以如果我们底层是docker容器的话就不需要单独安装这个CRI的实现的组件了。其他的容器运行时是需要提供这样的一个接口组件的。

kubelet的另外一个重要功能就是调用网络插件(CNI)和存储插件(CSI)为容器配置网络和存储功能,同样的kubelet也是把这两个重要功能提供接口暴露给外部,所以如果我们想要实现自己的网络插件,只需要使用CNI就可以对接到k8s集群中。

image.png

组件

kube-apiserver

APIServer提供了资源对象的唯一操作入口,其他所有组件都必须通过它提供的api来操作资源数据。只有APIServer会与etcd进行通信,其他模块都必须通过APIServer访问集群状态。APIServer作为k8s系统的入口,封装了核心对象的增删改查操作。APIServer以RESTFul接口方式提供给外部客户端和内部组件调用,APIServer再对相关的资源数据(全量查询+变化监听)进行操作,以达到实时完成相关的业务功能。以APIServer为k8s的唯一入口的设计主要有以下好处:

  • 保证集群状态访问的安全;
  • APIServer隔离了集群状态访问和后端存储实现,这样APIServer状态访问的方式不会因为后端存储技术的改变而改变,让后端存储方式选择更加灵活,方便了整个架构的扩展。

kube-controller-manager

image.png
Controller Manager 用于实现 Kubernetes 集群故障检测和恢复的自动化工作。主要负责执行各种控制器:

  • Replication Controller:主要是定期关联Replication Controller(RC)和Pod,以保证集群中一个RC(一种资源对象)所关联的Pod副本数始终保持为与预设值一致。
  • Node Controller:kubelet在启动时会通过APIServer注册自身的节点信息,并定时向APIServer汇报状态信息。APIServer在接受到信息后将信息更新到etcd中。Node Controller通过APIServer实时获取Node的相关信息,实现管理和监控集群中的各Node节点的相关控制功能。
  • ResourceQuota Controller:资源配额管理控制器用于确保指定的资源对象在任何时候都不会超量占用系统上的物理资源。
  • Namespace Controller:用户通过APIServer可以创建新的Namespace并保存到etcd中,Namespace Controller定时通过APIServer读取这些Namespace信息来操作Namespace。比如:Namespace被API标记为优雅删除,则将该Namespace状态设置为Terminating并保存到etcd中,同时Namespace Controller删除该Namespace下的Serviceaccount、Deployment、Pod等资源。
  • Service Account Controller:服务账号控制器主要在命名空间内管理ServiceAccount,以保证名为default的ServiceAccount在每个命名空间中存在。
  • Token Controller:令牌控制器主要用作监听ServiceAccount的创建和删除动作以及监听secrt的添加、删除动作。
  • Service Controller:服务控制器主要用做监听Service的变化,比如:创建的是一个LoadBancer类型的Service,Service Controller则要确保外部的云平台上对该Service对应的LoadBancer实例被创建、删除以及相应的路由转发表被更新。
  • Endpoint Controller:Endpoints表示了一个Service对应的所有Pod副本的访问地址,而Endpoint Controller是负责生成和维护所有Endpoints对象的控制器。Endpoint Controller负责监听Service和对应的Pod副本的变化。定期关联Serivce和Pod(关联信息有Endpoint对象维护),以保证Service到Pod映射的映射总是最新的。

Kube-scheduler

Scheduler是负责整个集群的资源调度,主要职责如下:

  • 主要用于收集和分析当前Kubernetes集群中所有Node节点的资源(包括CPU、内存等)负载情况,然后依据资源占用情况分发新建的Pod到k8s集群中可用的节点。
  • 实时监测集群中未分发和已分发的所有运行的Pod。
  • 实时监测Node节点信息,由于频繁查找Node节点,所以Scheduler同时会缓存一份最新的信息在本地。
  • 在分发Pod到指定的Node节点后,会把Pod相关的Binding信息写会APIServer,以方便其他组件使用。

Kubelet

kubelet是负责容器真正运行的核心组件,主要职责如下:

  • 负责Node节点上Pod的创建、修改、监控、删除等全生命周期的管理;
  • 定时上报本地Node的状态信息到APIServer;
  • 是Master和Node之间的桥梁,接受APIServer分配给他的任务并执行;
  • 在Node上的主要的工作具体如下:
    • 设置容器的环境变量、给容器绑定Volume、给容器绑定Port、根据指定的Pod运行单一的容器、给指定的Pod创建Network容器
    • 同步Pod状态
    • 在容器中运行命令、杀死容器、删除Pod的所有容器

Kube-proxy

kube-proxy是为了解决外部网络能够访问集群中容器提供的应用服务而设计的,Proxy运行在每个Node上。
每创建一个Service,kube-proxy就会从APIServer获取Service和Endpoints的配置信息,然后根据配置信息在Node上启动一个Proxy的进程并监听相应的服务端口。
当接收到外部请求时,kube-proxy会根据Load Balancer将请求分发到后端容器中处理。
kube-proxy不但解决了同一宿主机相同服务端口冲突问题,还提供了Service转发服务端口对外提供服务的能力。
kube-proxy后端使用随机、轮询等负载均衡算法进行调度。

kubectl

Kubectl 是 Kubernetes 的集群管理命令行客户端工具集。通过 Kubectl 命令对 API Server 进行操作,API Server 响应并返回对应的命令结果,从而达到对 Kubernetes 集群的管理。

核心资源对象

Pod

Pod是一组紧密关联的的容器集合,他们共享PID、IPC、Network、UTS和Namespace,是k8s调度的基本单位。Pod的设计理念是支持多个容器在一个Pod中共享网络和文件系统,可以通过进程见通信和文件共享这种简单高效的方式组合完成服务。容器的本质就是继承,那么Pod实际上就是进程组,只是这一组进程是作为一个整体来进行调度的。
image.png
在k8s中,所有的资源对象都使用资源清单(yaml)来定义,定义一个nginx服务,包含一个镜像为nginx的容器(nginx-pod.yaml)

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: nginx
  5. labels:
  6. app: nginx
  7. spec:
  8. containers:
  9. - name: nginx
  10. image: nginx
  11. ports:
  12. - containerPort: 80

定义完资源清单文件后,可以使用kubectl工具将这个pod创建到k8s集群中

$ kubectl apply -f nginx-pod.yaml

Pod在k8s集群中被创建的基本流程如下:
image.png

  • 用户通过REST API创建一个Pod
  • apiserver将其写入etcd
  • scheduler检测到未绑定Node的Pod,开始调度并更新Pod的Node绑定
  • kubelet检测到有新的Pod调度过来,通过container runtime运行该pod
  • kubelet通过container runtime取到pod状态,并更新到apiserver中

Label

Label标签在k8s资源对象中使用很多,也是非常重要的一个属性,Label是识别k8s对象的标签,以key/value的方式附加到对象上(key最长不能超过63字节,value可以为空,也可以是不超过253字节的字符串)。Label不提供唯一性,并且实际上经常是很多对象(如Pod)都使用相同的Label来标志具体的应用。Label定义好后其他的对象可以使用Label Selector来选择一组相同Label的对象(比如Service用Label来选择一组Pod)。label selector支持一下几种方式:

  • 等式:如app=nginxenv != prod
  • 集合:如env in (prod, qa)
  • 多个Label(他们之间是AND关系),如app=nginx,env=test

Namespace

Namespace(命名空间)是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的Pods、Deployments、Services等都是属于某一个Namespace的(默认是default),但Node、PersistentVolumes等资源则不属于任何Namespace,是全局的。

注意它并不是Linux Namespace,二者没有任何关系,它只是k8s划分不同工作空间的一个逻辑单位

Deployment

Deployment确保任意时间都有指定数量的pod副本在运行。如果为某个pod创建了Deployment并且指定3个副本,他会创建3个Pod,并且持续监控他们。如果某个Pod不响应,那么Deployment会替换它,始终保持总数为3。
如果之前不响应的Pod恢复了,现在就会有4个Pod,那么Deployment会将其中的一个终止,保持总数为3。如果在运行中将副本总数改为5,Deployment会立刻启动2个新的Pod,保证总数为5。
当创建Deployment时,需要指定两个东西:

  • Pod模板:用来创建Pod副本的模板
  • Label标签:Deployment需要监控的Pod的标签

Service

Service是应用服务的抽象,通过label为应用提供负载均衡和服务发现。匹配Labels的Pod IP和端口列表组成Endpoints,由kube-proxy负责将服务IP负载均衡到这些Endpoints上。
每个Service都会自动分配一个cluster IP(仅在集群内部可以访问的虚拟地址)和DNS名,其他容器可以通过该地址或DNS来访问服务,而不需要了解后端容器的运行。
image.png