Kubernetes基本概念和术语

156 阅读15分钟

Kubernetes基本概念和术语

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

Master

基本概念

  K8s中Master指的是集群控制节点,负责整个集群的管理和控制,基本上所有控制命令都是由master接收并执行,看到这里也知道这是一个很重要的组件,所以通常Master需要独立部署保证高可用。

Master节点上运行着一些关键进程

  1. kube-apiserver,提供了HTTP REST接口的关键服务进程,是k8s里所有资源的增删改查操作的唯一入口,也是集群控制的入口进程。
  2. kube-controller-manager,k8s里所有资源对象的自动化控制中心,可以理解为资源对象的大总管
  3. kube-scheduler,负责资源调度(Pod调度)的进程,相当于调度室。 往往Master节点还启动了一个etcd Server进程,因为K8s里的所有资源对象的数据全部是保存在etcd中的

Node

基本概念

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

Node节点上运行着一些关键进程

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

Pod

基本概念

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

image.png

为什么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),

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

image.png

k8s资源对象的定义

apiVersion: v1
kind: Pod  # 表示为一个Pod
metadata:
  name: myweb # Pod的名称
spec: # 包含的容器组在spec中定义
  replicas: 5 # Pod副本期待数,一次运行5个Pod实例
  selector: # 标签选择器
    app: myweb # 符合目标的Pod拥有此标签
  template:
    metadata:
      labels:
        app: myweb # Pod副本拥有的标签,对应上面RC的selector
    spec:
      containers: # Pod内容器的定义部分
      - name: myweb # 容器名
        image: kubeguide/tomcat-app:v1 # 容器对应的Docker Image
        resources: # 资源最小申请量
          memory: "64Mi" # 内存
          cpu: "250m" # cpu
        limits: # 资源最大申请量
          memory: "128Mi"
          cpu: "500m"   
        ports:
        - containerPort: 8080 # 容器暴露的端口
        env: # 注入到容器内的环境变量
        - name: MYSQL_SERVICE_HOST
          value: 'mysql'
        - name: MYSQL_SERVICE_PORT
          value: '3306'

EndPoint概念

  Pod的 IP 加上这里的容器端口(containerPort),就组成了一个新的概念Endpoint,它代表着此 Pod 里的一个服务进程的对外通信地址。一个 Pod 也存在着具有多个Endpoint的情况,比如当我们把 Tomcat 定义为一个Pod的时候,可以对外暴露管理端口与服务端口这两个Endpoint。

Label(标签)

基本概念

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

  我们可以通过给指定的资源对象捆绑一个或多个不同的 Label 来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等管理工作。例如:部署不同版本的应用到不同的环境中;或者监控和分析应用(日志记录、监控、告警)等。Label相当于我们熟悉的标签,给某个资源定义一个label,相当于打上了一个标签,然后我们就可以使用Selector查询和筛选拥有某些label的资源对象

Replication Controller(RC)

基本概念

  RC是k8s系统中的核心概念之一,简单来说,其实是定义一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,RC的定义如下:

  • Pod期待的副本数(replicas)
  • 用于筛选目标Pod的Label Selector
  • 当Pod的副本数量小于预期数量(replicas)时,用于创建新Pod的Pod模板(template)   当我们定义一个RC并提交到k8s集群中后,Master节点的Controller Manager组件就会得到通知并定期巡检系统中当前存活的目标Pod,并确保目标Pod实例数量刚好等于此RC的期望值,如果Pod副本过多,系统会停掉一些Pod,否则则会自动创建。   在运行时,可以通过修改RC的副本数量,来实现Pod的动态缩放(Scaling)功能,通过kubectl scale来完成:
kubectl scale rc redis-slave --replicas=3

  滚动升级:我们构建完一个新的docker镜像后,可以通过修改RC里模板中的镜像版本,实现Pod的滚动升级功能

  删除RC并不会影响通过该RC已创建的Pod,为了删除Pod,可以设置replicas的值为0,然后更新此RC,也可以使用kubectl提供的stop和delete命令来删除RC和RC控制的Pod

Deployment

基本概念

  Deployment是k8s1.2引入的新概念,引入的目的是为了更好地解决Pod的编排问题。

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

使用场景

  • 创建一个Deployment 对象来生成对应的Replica Set并完成Pod副本的创建过程。
  • 检查Deployment的状态来看部署动作是否完成(Pod副本的数量是否达到预期的值)。
  • 更新 Deployment以创建新的Pod(比如镜像升级)。
  • 如果当前 Deployment不稳定,则回滚到一个早先的 Deployment 版本。
  • 挂起或恢复一个Deployment

Horizontal Pod Autoscaler(HPA)

基本概念

  Horizontal Pod Autoscaling 简称 HPA,意思是Pod横向自动扩容,与之前的RC、Deployment一样,也属于一种Kubemetes资源对象。通过追踪分析 RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标 Pod的副本数,这是HPA的实现原理。当前,HPA可以有以下两种方式作为 Pod 负载的度量指标。

  • CPUUtilizationPercentage。这是一个算术平均值,即目标Pod所有副本自身的CPU利用率的平均值;一个Pod自身的CPU利用率是该Pod当前CPU使用量除以它的Pod Request的值,当CPUUtilizationPercentage大于80%,则可能当前的Pod副本数不足以支持接下来的更多请求,需要进行动态扩容,当请求高峰过去后,Pod的CPU利用率降下来,则Pod副本数应该自动减少到合理的水平;必要条件: Pod需要定义Pod Request值,需要安装Heapster
  • 应用程序自定义的度量指标,比如服务在每秒内的相应的请求数(TPS或QPS)。 HPA定义实例
apiVersion: autoscaling/v1
kind: HorizontalPodAutoScaler
metadata:
  name: tomcat-demo
  namespace: default
spec:
  maxReplicas: 10 # 最大副本数
  minReplicas: 1 # 最小副本数
  scaleTargetRef: # 控制的目标
    kind: Deployment
    name: tomcat-demo
  targetCPUUtilizationPercentage: 90 # 扩容阈值

使用kubectl创建HPA资源对象

kubectl autoscale deployment tomcat-demo --cpu-percent=90 --min=1 --max=10

Service(服务)

基本概念

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

Pod、RC、Service的关系

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

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  type: NodePort # 多node可以使用LoadBalancer实现负载均衡来转发到Node
  ports:
  - port: 8080
    nodePort: 31002 # 分配一个可用端口
  selector:
    tier: frontend

查看相关信息和Service的clusterIP

kubectl get svc tomcat-service -o yaml

Volume(存储卷)

基本概念

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

template:
  metadata:
    labels:
      app: app-demo
      tier: frontend
  spec:
    volumes: # 声明一个Volume
      - name: detavol
        emptyDir: {} # Volume类型
    containers:
    - name: tomcat-demo
      image: tomcat
      volumeMounts:
        - mountPath: /mydata-data # mount到容器的/mydata-data目录
          name: datavol
      imagePullPolicy: IfNotPresent

Volume类型

emptyDir
hostPath

hostPath为在Pod.上挂载宿主机上的文件或目录

volumes: # 声明一个Volume
      - name: detavol
        hostPath:
          path: "data"
gcePersistentDisk

使用这种类型的Volume表示使用谷歌公有云提供的永久磁盘(Persistent Disk,PD)存放Volume 的数据,它与EmptyDir不同,PD上的内容会被永久保存,当Pod被删除时,PD只是被卸载(Unmount),但不会被删除。需要注意的是,你需要先创建一个永久磁盘(PD),才能使用gcePersistentDisk。

gcloud命令创建PD

gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk
volumes: # 声明一个Volume
      - name: detavol
        gcePersistentDisk:
          pdName: my=data=disk
          faType: ext4
awsElasticBlockStore

与GCE类似,该类型的Volume使用亚马逊公有云提供的EBS Volume存储数据,需要先创建一个EBS Volume才能使用awsElasticBlockStore. 通过aws ec2 create-volume命令可以创建一个EBS volume:

aws ec2 create-volume --availability-zone eu-west-la --size 10 --volume-type gp2
volumes: # 声明一个Volume
      - name: detavol
        awsElasticBlockStore:
          volumeID: aws://<avaliability-zone>/<volume-id>
          faType: ext4
NFS

使用NFS 网络文件系统提供的共享目录存储数据时,我们需要在系统中部署一个NFSServer。定义NFS类型的Volume 的示例如下:

volumes: # 声明一个Volume
      - name: nfs
        nfs:
          # 改为你的NFS服务器地址
          server: nfs.server.localhost
          path: "/"
其他类型的Volume

Persistent Volume

PV可以理解成Kubernetes集群中的某个网络存储中对应的一块存储,它与Volume很类似,但有以下区别。

  • PV只能是网络存储,不属于任何Node,但可以在每个Node 上访问。
  • PV并不是定义在Pod 上的,而是独立于Pod之外定义。
  • PV目前只有几种类型:GCE Persistent Disks、NFS、RBD、isCSCI、 AWS、ElasticBlockStore、GlusterFS 等。 下面给出了NFS 类型PV的一个yaml定义文件,声明了需要5Gi的存储空间:
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce # 读写权限,并且只能被单个Node挂载
  nfs:
    path: /somepath
    server: 172.17.0.2

ReadWriteOnce: 读写权限,只能被单个Node挂载 ReadOnlyMany:只读,允许多个Node挂载 ReadWriteMany:读写,允许多个Node挂载

Namespace(命名空间)

Namespace(命名空间)是Kubernetes 系统中的另一个非常重要的概念,Namespace在很多情况下用于实现多租户的资源隔离。Namespace通过将集群内部的资源对象“分配”到不同的Namespace 中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。

Kubernetes集群在启动后,会创建一个名为“default”的Namespace,通过 kubectl可以查看到;

接下来,如果不特别指明Namespace,则用户创建的Pod、RC、Service都将被系统创建到这个默认的名为default 的 Namespace 中。

当我们给每个租户创建一个Namespace来实现多租户的资源隔离时,还能结合Kubernetes的资源配额管理,限定不同租户能占用的资源,例如CPU使用量、内存使用量等。关于资源配额管理的问题,在后面的章节中会详细介绍。

Annotation(注解)

Annotation 与 Label类似,也使用key/value键值对的形式进行定义。不同的是Label具有严格的命名规则,它定义的是Kubernetes对象的元数据(Metadata),并且用于Label Selector。而Annotation则是用户任意定义的“附加”信息,以便于外部工具进行查找,很多时候,Kubernetes的模块自身会通过Annotation的方式标记资源对象的一些特殊信息。