Jusene's Blog

Kubernetes基本概念和术语

字数统计: 4.1k阅读时长: 16 min
2018/03/27 Share

Kubernetes

Kubernetes集群的两种管理角色:Master和Node

Master

Kubernets里的Master指的是集群控制节点,每个Kubernets集群里需要一个Master节点来负责整个集群的管理和控制,基本上Kubernets的所有控制命令都发给它,它来负责具体执行过程。Master节点通常高可用建议3台服务器来完成。

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

  • Kubernets API Server(kube-apiserver):提供了HTTP Rest接口的关键服务进程,是Kubernets里所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程。
  • Kubernets Controller Manager(kube-controller-manager):Kubernets里所有资源对象的自动化控制中心。
  • Kubernets Scheduler(kube-scheduler):负责资源调度(Pod调度)的进程
    另外,在Master节点上还需要启动一个etcd服务,因为Kubernets里的所有服务资源对象的数据全部是保存在etcd中的

Node

Node节点是Kubernets集群中的工作负载节点,每个Node都会被Master分配一些工作负载,当某个Node宕机时,其上的工作负载会被Master自动转移到其他节点上去。

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

  • kubelet:负责Pod对应的容器创建、启停等任务,同时与Master节点密切协作,实现集群管理的基本功能
  • kube-proxy:实现Kubernetes Service的通信与负载均衡机制的重要组件
  • Docker Engine: Docker引擎

查看集群有多少个node:

1
kubectl get nodes

查看某个node的详细信息:

1
kubectl describe node <node name>

资源对象

Pod

Pod是Kubernets的最重要也是最基本的概念,每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包括一个或者多个紧要相关的用户业务容器。

在一组容器作为一个单元的情况下,我们难以对‘整体’简单地进行判断及有效地进行行动。引入业务无关的并且不易死亡的Pause容器作为Pod的根容器,以它的状态代表整个容器组的状态,就简单、巧妙地解决了这个难题。

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

1
apiVersion: v1
2
kind: Pod
3
metadata:
4
  name: mysql
5
  labels:
6
    name: mysql
7
spec:
8
  containers:
9
  - name: mysql
10
    image: mysql:latest
11
    resources:
12
      requests:
13
        memory: "64Mi"
14
        cpu: "250m"
15
      limits:
16
        memory: "128Mi"
17
        cpu: "500m"
18
    ports:
19
    - containerPort: 3306
20
      hostPort: 3306
21
    env:
22
    - name: MYSQL_ROOT_PASSWORD
23
      value: "123456"

resources:

  • requests: 该资源的最小申量,系统必须满足
  • limits: 该资源最大允许使用的量,不能被突破,当容器试图使用超过这个量的资源时,可能被kubernets kill并重启

Label

Label是kubernetes系统中的另一个核心概念。一个Label是一个key=value的键值对,我们可以通过指定的资源对象绑定一个或多个不同的label来实现多维度的资源分组管理功能,给某个资源对象定义一个Label,就相当于打了一个标签,随后通过Label Selector查询和筛选拥有某些Label的资源对象。

Pod,Label定义在其metadata中

1
apiVersion: v1
2
kind: Pod
3
metadata: 
4
   name: myweb
5
   labels:
6
     app: myweb

管理对象RC和Service在spec中定义Selector与Pod进行关联:

1
apiVersion: v1
2
kind: ReplicationController
3
metadata:
4
   name: myweb
5
spec:
6
   replicas: 1
7
   selector:
8
     app: myweb
9
   template:
10
   ....
1
apiVersion: v1
2
kind: Service
3
metadata:
4
  name: myweb
5
spec:
6
  selector:
7
    app: myweb
8
  ports:
9
  - port: 8080
10
  ....

新出现的管理对象如Deployment、ReplicaSet、DaemonSet和Job则可以在Selector中使用给予集合的筛选条件定义:

1
selector:
2
  matchLabels:
3
    app: myweb
4
  matchExpressions:
5
    - {key: tier,operator: In,values: [frontend]}
6
    - {key: environment,operator: NotIn,values: [dev]}

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”定向调度”的特性。

Replication Controller

RC是kubernetes系统中的核心概念之一,简单来说,它其实是定义了一个期望的场景,RC的定义包含以下几部分:

  • Pod期待的副本数(replicas)
  • 用于筛选目标Pod的Label Selector
  • 当Pod的副本数量小于预期数量时,用于创建新Pod的Pod模版
1
apiVersion: v1
2
kind: ReplicationController
3
metadata:
4
  name: backend
5
spec:
6
  replicas: 1
7
  selector:
8
     tier: backend
9
  template:
10
     metadata:
11
        labels:
12
            app: mysql
13
            tier: backend
14
     spec:
15
        containers:
16
        - name: mysql-demo
17
          image: mysql:latest
18
          imagePullPolicy: IfNotPresent
19
          resources:
20
             requests:
21
                memory: '64Mi'
22
                cpu: '300m'
23
            limits:
24
                memory: '128Mi'
25
                cpu: '500m'
26
          env:
27
          - name: MYSQL_ROOT_PASSWORD
28
            value: 123456
29
          ports:
30
          - containerPort: 3306
31
            hostPort: 3306

总结关于RC的一些特性与作用:

  • 在大多数情况下,我们通过定义一个RC实现pod的创建过程及副本数量的自动控制
  • RC里包括完成的Pod摸版
  • RC通过Label Selector机制实现对Pod副本的自动控制
  • 通过改变RC里的Pod副本数量,可以实现Pod的扩容或缩容功能
  • 通过改变RC里Pod模版中的镜像版本,可以实现Pod的滚动升级功能

Replica Set

官方解释为下一代RC,它与RC当前存在的唯一区别是:Replica Set支持给予集合的Label Selector,而RC只支持基于等式的Label Selector:

1
apiVersion: extensions/v1beta1
2
kind: ReplicaSet
3
metadata:
4
  name: mysql
5
spec:
6
  replicas: 1
7
  selector:
8
    matchLabels:
9
      app: mysql
10
    matchExpressions:
11
      - {key: tier,operator: In,values: [backend]}
12
  template:
13
    metadata:
14
      labels:
15
        app: mysql
16
        tier: backend
17
    spec:
18
      containers:
19
      - name: mysql
20
        image: mysql:latest
21
        imagePullPolicy: IfNotPresent
22
        resources:
23
          requests:
24
             memory: "64Mi"
25
             cpu: "250m"
26
          limits:
27
             memory: "128Mi"
28
             cpu: "500m"
29
        ports:
30
        - containerPort: 3306
31
          hostPort: 3306
32
        env:
33
        - name: MYSQL_ROOT_PASSWORD
34
          value: '123456'

kubectl的RC的绝大部分命令同样适用于Replica Set。此外,当前我们很少单独使用Replica Set,它主要被Deployment这个更高层次的资源对象所使用,从而形成一整套Pod创建、删除、更新的编排机制。Replica Set和Deployment这两重要资源对象逐步替换了之前的RC的作用,是kubernets v1.3里Pod自动扩容(伸缩)这个告警功能实现的基础。

Deployment

Deployment的引入的目的是为了更好地解决Pod编排问题。为此,Deployment在内部使用了Replica Set来实现,Deployment相对于RC的最大升级是我们可以随时知道当前Pod部署的进度。

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

  • 创建一个Deployment对象来生成对应的Replica Set并完成Pod副本的创建过程
  • 检查Deployment的状态来看部署动作是否完成(Pod副本的数量是否达到预期的值)
  • 更新Deployment以创建新的Pod(比如镜像升级)
  • 如果当前Deployment不稳定,则回滚到早先的Deployment版本
  • 暂停Deployment以便于一次性修改多个PodTemplateSpec的配置项,之后再恢复Deployment,进行新的发布
  • 扩展Deployment以应对高负载
  • 查看Deployment的状态,以此作为发布是否成功的指标
  • 清理不在需要的旧版本ReplicaSets
1
apiVersion: extensions/v1beta1
2
kind: Deployment
3
metadata:
4
  name: mysql
5
spec:
6
  replicas: 1
7
  selector:
8
    matchLabels:
9
      app: mysql
10
    matchExpressions:
11
      - {key: tier,operator: In,values: [backend]}
12
  template:
13
    metadata:
14
      labels:
15
        app: mysql
16
        tier: backend
17
    spec:
18
      volumes:
19
      - name: data
20
        hostPath:
21
          path: /data
22
      containers:
23
      - name: mysql-demo
24
        image: mysql:latest
25
        volumeMounts:
26
           - mountPath: /mydata
27
             name: data
28
        imagePullPolicy: IfNotPresent
29
        resources:
30
          requests:
31
             memory: "64Mi"
32
             cpu: "250m"
33
          limits:
34
             memory: "128Mi"
35
             cpu: "500m"
36
        ports:
37
        - containerPort: 3306
38
          hostPort: 3309
39
        env:
40
        - name: MYSQL_ROOT_PASSWORD
41
          value: '123456'

Horizontal Pod Autoscaler

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

  • CPUUtilizationPercentage
  • 应用程序自定义的度量指标,比如服务每秒内的相应的请求数(TPS和QPS)

CPUUtilizationPercentage计算过程中使用的Pod的cpu使用量通常是1min内的平均值,目前通过查询Heapster扩展组件来得到这个值,所以需要安装部署Heapster,并且如果Pod没有定义Pod Request的值,则无法使用CPUUtilizationPercentage来实现Pod的横向扩展能力。Kubernetes从v1.2版本开始支持应用程序自定义度量指标。

1
apiVersion: autoscaling/v1
2
kind: HorizontalPodAutoscaler
3
metadata:
4
   name: auto
5
   namespace: default
6
spec:
7
   maxReplicas: 10
8
   minReplicas: 1
9
   scaleTargetRef:
10
      kind: Deployment
11
      name: mysql
12
   targetCPUUtilizationPercentage: 90

StatefulSet

在Kubernetes系统中,Pod的管理对象RC、Deployment、DaemonSet和Job都是无状态的服务。但现实中很多服务都是有状态的,特别是一些复杂的中间件集群,如mysql集群、mongodb集群等,这些集群有一个共同点:

  • 每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互通信
  • 集群的规模比较固定
  • 集群中的每个节点都是有状态的,通常会持久化数据到永久存储中
  • 如果磁盘损坏,则集群里的每个节点无法正常运行,集群功能受损

为了解决上述问题,引入StatefulSet,有如下特性:

  • StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员,假设StatefulSet的名字叫kafka,那么第1个Pod叫kafka-0,第二个叫kafka-1
  • StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod时,前n-1个Pod已经是运行且准备好的状态
  • StatefulSet里的Pod采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷

Service

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

运行在每个Node上的kube-proxy进程其实是一个智能的软件负载均衡器,它负责把对service的请求转发到后端的某个Pod实例上,并在内部实现负载均衡和会话保持,Service不是共用一个负载均衡器的IP地址,而是每个service分配一个全局唯一的IP地址,这个虚拟IP被称为Cluster IP,Pod的Endpoint地址会随着Pod的销毁和重组创建而发生改变,而Cluster IP不会发生改变,于是服务发现这个棘手的问题在kubernetes的整个架构中轻松解决。

1
apiVersion: v1
2
kind: Service
3
metadata:
4
   name: mysql
5
spec:
6
   ports:
7
   - port: 3306
8
   selector:
9
   name: mysql

Kubernetes Service支持多个Endpoint,在存在多个Endpoint的情况下,要求每个Endpoint定义一个名字来区分:

1
apiVersion: v1
2
kind: Service
3
metadata:
4
  name: tomcat-service
5
spec:
6
  ports:
7
  - port: 8080
8
    name: service-port
9
  - port: 8005
10
    name: shutdown-port

外部系统访问service,我们先要知道Cluster IP:

  • cluster ip仅仅作用于kubernetes service对象,并由kubernetes管理和分配ip地址
  • cluster ip无法被ping,因为没有一个‘实体网络对象’来响应
  • cluster ip只能结合service port组成一个具体的通信接口,单独的cluster ip不具备tcp/ip通信基础,并且它们属于kubernetes集群这样一个封闭的空间,集群之外的节点如果要访问这个通信接口,则需要做一些额外的工作
  • 在kubernetes集群之内,Node IP,Pod IP,Cluster IP网之间的通信,采用的是kubernetes自己设计的一种编程方式的特殊路由规则

想要集群外部直接访问,NodePort是解决上述问题最直接的方法:

1
apiVersion: v1
2
kind: Service
3
metadata:
4
  name: tomcat-service
5
spec:
6
  type: NodePort
7
  ports:
8
  - port: 8080
9
    nodePort: 31002
10
  selector:
11
    tier: frontend

Volume

Volume是pod中能够被多个容器访问的共享目录,Kubernets的Volume定义在Pod上,然后被一个Pod里的多个容器挂载到具体的目录下:其次,Kubernets中的Volume与Pod的生命周期相同,但与容器的生命周期不相关。

1
apiVersion: v1
2
kind: Pod
3
metadata:
4
  name: mysql
5
  labels:
6
    name: mysql
7
spec:
8
  volumes:
9
  - name: datavol
10
    emptyDir: {}
11
  containers:
12
  - name: mysql
13
    image: mysql:latest
14
    resources:
15
      requests:
16
        memory: "64Mi"
17
        cpu: "250m"
18
      limits:
19
        memory: "128Mi"
20
        cpu: "500m"
21
    volumeMounts:
22
    - mountPath: /mysqldata
23
      name: datavol
24
    ports:
25
    - containerPort: 3306
26
      hostPort: 3306
27
    env:
28
    - name: MYSQL_ROOT_PASSWORD
29
      value: "123456"

emptyDir

一个emptyDir Volume是在Pod分配到Node时创建的。初始内容为空,并且无需指定宿主机上的对应的目录文件,因为这是kubernetes自动分配的一个目录,emptyDir的一些用途:

  • 临时空间,例如用于某些应用程序运行时的临时目录,且无需永久保存
  • 长时间的中间过程CheckPoint的临时保存目录
  • 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)

hostPath

hostPath为Pod上挂载宿主机上的文件或者目录,它通常可以用于以下几方面。

  • 容器应用程序生成的日志文件需要多久保存时,可以使用宿主机的高速文件系统进行存储
  • 需要访问宿主机上的Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主机/var/lib/docker
1
volumes:
2
- name: 'hostpath'
3
  hostPath:
4
    path: /data

NFS

1
volumes:
2
- name: nfs
3
  nfs:
4
    server: nfs-server.address
5
    path: /

其他类型的Volume

  • gcePersistentDisk: 谷歌公有云提供的永久磁盘(Persitent Disk,PD)存放Volume的数据
  • awsElasticBlockStore: 亚马逊公有云提供的EBS Volume储存数据
  • iscsi: 使用ISCSIc存储设备上的目录挂载到Pod中
  • flocker: 使用Flocker来管理存储卷
  • glusterfs: 使用开源GlusterFS网络文件系统的目录挂载到Pod中
  • rdb: 使用Ceph块设备共享存储(Rados Block Device)挂载到Pod中
  • gitRepo: 通过挂载一个空目录,并从GIT库clone一个git repository以供Pod使用
  • secret: 一个secret volume用于为Pod提个加密的信息,secret volume是通过tmfs(内存文件系统)实现的,所以这种的volume总是不会持久化

Persistent Volume

网路存储是相对于计算资源而存在的一种实体资源,比如在使用虚拟机的情况下,我们通常会先定义一个网络存储,然后从中划出一个网盘并挂载到虚拟机上。Persistent Volume(简称PV)和与之相关联的Persistent Volume Chaim(简称PVC)也起到类似的作用。

PV可以理解成kubernetes集群中的某个网络存储中对应的一块存储,它与Volume很类似:

  • PV只能是网络存储,不属于任何Node,但可以在每个Node上访问
  • PV并不是定义在Pod上的,而是独立与Pod之外定义的
  • PV目前支持的包括:gcePersistentDisk、AWSElasticBlockStore、AzureFile、AzureDisk、FC(Fibew Channel)、Flocker、NFS、iSCSI、RDB(Rados Block Device)、CephFS、Cinder、GlusterFS、VsphereVloume、Quobyte Volumes、VMware Photon、Portworx Volumes、ScaleIO Volumes和HostPath(单机测试)。
1
apiVersion: v1
2
kind: PersistentVolume
3
metadata:
4
   name: pv0003
5
spec:
6
   capacity:
7
      storage: 5Gi
8
   accessModes:
9
      - ReadWriteOnce
10
   nfs:
11
      path: /somepath
12
      server: 172.16.2.3
  • ReadWriteOnce: 读写权限、并且只能被单个node挂载
  • ReadOnlyMany: 只读权限、允许被多个Node挂载
  • ReadWriteMany: 读写权限、允许被多个node挂载

如果某个Pod想申请某种类型的PV,则首先需要定义一个PersistentVolumeChaim(PVC):

1
apiVersion: v1
2
kind: PersistentVolumeClaim
3
metadata:
4
  name: myclaim
5
spec:
6
  accessModes:
7
    - ReadWriteOnce
8
  resources:
9
    requests:
10
       storage: 8Gi

然后在Pod的Volume定义中引用上述PVC即可:

1
volumes:
2
   - name: mypod
3
     persistentVolumeClaim:
4
       claimName: myclaim

PV的状态:

  • Available: 空闲状态
  • Bound: 已经绑定到某个PVC上
  • Released: 对应的PVC已经删除,但资源还没有被集群收回
  • Failed: PV自动回收失败

Namespace

Namespace(命名空间)是kubernetes系统的另一个非常重要的概念,Namespace在很多情况下用于实现多租户的资源隔离。Namespace通过将集群内部的资源对象‘分配’到不同的Namespace中,形成逻辑上的分组的不同项目、小组或用户组。

kubernetes集群启动后,会创建一个名为‘default’的namespace:

1
~]# kubectl get namespaces
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
  name: busybox
5
  namespace: development
6
spec:
7
  containers:
8
  - image: busybox
9
    command: 
10
      - sleep
11
      - "3600"
12
    name: busybox

kubectl get命令将仅显示“default”命名空间的资源对象:

1
~]# kubectl get pods --namespace=development

Annotation

Annotation与Label类似,也使用key/value键对值的形式进行定义。不同的是Label具有严格的命名规则,定义了kubernetes对象的元数据,并且用于label selector,而Annotation则是用户任意定义的“附加”信息。

CATALOG
  1. 1. Kubernetes
    1. 1.1. Master
    2. 1.2. Node
  2. 2. 资源对象
    1. 2.1. Pod
    2. 2.2. Label
    3. 2.3. Replication Controller
    4. 2.4. Replica Set
    5. 2.5. Deployment
    6. 2.6. Horizontal Pod Autoscaler
    7. 2.7. StatefulSet
    8. 2.8. Service
    9. 2.9. Volume
      1. 2.9.1. emptyDir
      2. 2.9.2. hostPath
      3. 2.9.3. NFS
      4. 2.9.4. 其他类型的Volume
    10. 2.10. Persistent Volume
    11. 2.11. Namespace
    12. 2.12. Annotation