Kubernetes:Controller

2021-03-01 11:27

阅读:664

标签:实现   har   data   write   record   running   部分   回收   pre   

简介

Kubernetes集群中的Controller对象可以创建和管理多个Pod,提供副本管理、健康检查、滚动升级和集群级别的自愈能力。例如,如果一个节点故障,Controller就能自动将该节点上的Pod调度到其他健康的节点上。这些Controller运行在Kubernetes集群的主节点上,它们不断控制集群中的资源向期望状态迁移(stauts -> spec)。常用的Controller类型有:

  • ReplicaSet
  • Deployment
  • DaemonSet
  • StatefulSet
  • Job/Cronjob

ReplicaSet

决定一个Pod有多少同时运行的副本,并保证这些副本的期望状态与当前状态一致。

配置

一个典型的ReplicaSet配置如下:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  replicas: 3            # 副本数
  selector: 
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: docker.io/redis:latest
  • 在上述配置信息中,字段spec.template.metadata.labels的值必须与spec.selector值相匹配,否则创建请求会被Kubernetes API拒绝;
  • 被ReplicaSet控制的Pod在创建或更新后,其metadata.ownerReferences字段会添加该ReplicaSet的信息;
  • 一旦删除了原来的ReplicaSet,就可以创建一个新的来替换它。只要新旧ReplicaSet的spec.selector字段是相同的,新的ReplicaSet便会接管原有的Pod。然而,修改ReplicaSet中的template并不会使其接管的Pod的Spec更新。

应用场景

  • 重调度:保证指定数量的Pod正常运行;
  • 弹性伸缩:修改spec.replicas字段,实现Pod数量弹性伸缩;
  • 应用多版本追踪:修改spec.selector字段,实现对一个Pod的多版本管理。

由于ReplicaSet并不支持使用命令kubectl roll-update对Pod进行滚动更新,因此若想要以可控的方式更新Pod,建议使用Deployment。

Deployment

Deployment为Pod和ReplicaSet提供声明式的更新能力,用于管理无状态的应用。

配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.io/nginx:latest
        ports:
        - containerPort: 80
  • .spec.selector字段必须匹配.spec.template.metadata.labels,否则请求会被Kubernetes API拒绝;
  • 当Pod的标签和Deployment的标签选择器匹配,但其模板和.spec.template不同,或者此类Pod的总数超过.spec.replicas的设置时,Deployment会将其终止;
  • 如果Pod的总数未达到期望值,Deployment会基于.spec.template创建新的Pod。

创建

[root@test-master1 ~]# kubectl create -f test.yml --record
deployment.apps/nginx-deployment created
[root@test-master1 ~]# kubectl get deployment
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           9s

查看上线状态

[root@test-master1 ~]# kubectl rollout status deployment.v1.apps/nginx-deployment
deployment "nginx-deployment" successfully rolled out
[root@test-master1 ~]# kubectl get pods --show-labels
NAME                                READY     STATUS    RESTARTS   AGE       LABELS
nginx-deployment-5cbbd6c556-gj4vp   1/1       Running   0          4m        app=nginx,pod-template-hash=1766827112
nginx-deployment-5cbbd6c556-vk4vl   1/1       Running   0          4m        app=nginx,pod-template-hash=1766827112
nginx-deployment-5cbbd6c556-z24z8   1/1       Running   0          4m        app=nginx,pod-template-hash=1766827112
[root@test-master1 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-5cbbd6c556   3         3         3         2d

查看详细信息

[root@test-master1 ~]# kubectl describe rs nginx-deployment-5cbbd6c556
Name:           nginx-deployment-5cbbd6c556
Namespace:      gwr
Selector:       app=nginx,pod-template-hash=1766827112
Labels:         app=nginx
                pod-template-hash=1766827112
...

其中一些参数的含义:

  • NAME:列出了集群中Deployment的名称;
  • READY:应用程序的可用的副本数,显示的格式是“就绪个数/期望个数”;
  • UP-TO-DATE:为了达到期望状态已经更新的副本数;
  • AVAILABLE:显示应用可供用户使用的副本数;
  • AGE:显示应用程序运行的时间。

我们可以发现ReplicaSet被命名为Deployment名称加一个数字的格式(nginx-deployment-5cbbd6c556),这个数字是使用Pod标签中pod-template-hash字段作为种子随机生成的。而此标签字段是通过对Pod的template进行哈希处理得到的,可确保Deployment管理的ReplicaSet不重叠。

更新

使用kubectl edit deployment 命令,可直接对Deployment管理的Pod进行更新。当使用kubectl describe deployments命令查看更新信息时,可以在Events下看到更新的过程:

Events:
    Type    Reason             Age   From                   Message
    ----    ------             ----  ----                   -------
    Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-2035384211 to 3
    Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 1
    Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 2
    Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 2
    Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 1
    Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 3
    Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 0
  • 当第一次创建Deployment时,它自动创建了一个ReplicaSet(nginx-deployment-2035384211)并将其管理的Pod扩容至3个副本;
  • 更新Deployment时,它又创建了一个新的ReplicaSet(nginx-deployment-1564180365),并将其管理的Pod数量设置为1,然后将旧ReplicaSet管理的Pod缩容到2,以便至少有2个Pod可用且最多创建4个Pod;
  • 然后,它使用相同的滚动更新策略继续对新的ReplicaSet扩容并对旧的ReplicaSet缩容;
  • 最终,新ReplicaSet管理的Pod副本数扩容至3个,旧ReplicaSet管理的Pod全部终止,更新完成;
  • 在整个更新过程中,最多只有一个Pod副本不提供服务,且同一时刻不会有过多的Pod副本同时运行(默认最多比预期值多一个)。

回滚

当Deployment不稳定时(例如进入反复崩溃状态),我们需要对其进行回滚操作。默认情况下,Deployment的所有上线记录都保留在系统中,以便可以随时回滚。

  • 查看历史版本:kubectl rollout history deployment
  • 回滚至历史版本:kubectl rollout undo deployment --to-revision=

StatefulSet

StatefulSet用于管理有状态的应用程序,被其管理的Pod有一个按顺序增长的ID。它与Deployment最大的不同在于,StatefulSet始终将一系列不变的名字分配给Pod,这些Pod从同一个模板创建但并不能相互替换且每个Pod都对应一个特有的持久化存储标识。

应用场景

  • 每个Pod拥有稳定的、唯一的网络标识符(DNS Name)
  • 每个Pod拥有稳定的、持久的存储(PersistentVolume)
  • 有序的、优雅的部署和缩放
  • 有序的、自动的滚动更新

配置

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10 # not 0
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi
  • 名为nginx的Headless Service用来给每个Pod配置DNS Name;
  • 名为web的StatefulSet中的字段spec.replicasspec.template.spec字段表明将在独立的3个Pod副本中启动nginx容器;
  • volumeClaimTemplates字段表明将通过PersistentVolumes来为Pod提供持久化存储。

Pod标识

StatefulSet管理的Pod具备一个唯一标识,该标识由以下几部分组成:

  • 序号:假设一个StatefulSet的副本数为N,其中的每一个Pod都会被分配一个序号,序号的取值范围从0到N-1,并且该序号在StatefulSet内部是唯一的。
  • 稳定的网络标识:
    • StatefulSet中每个Pod根据StatefulSet的名称和Pod的序号派生出它的主机名hostname:-
    • StatefulSet可以使用Headless Service来控制其Pod所在的域,该域(domain)的格式为:..svc.cluster.local("cluster.local"是集群的域名);
    • StatefulSet中每一个Pod将被分配一个DNS Name,格式为:.,因此可以直接通过该Pod的DNS Name访问到Pod。
  • 稳定的存储:Kubernetes为每个VolumeClaimTemplate创建一个PersistentVolume。

部署和扩缩容

在默认情况下.spec.podManagementPolicy字段值为OrderedReady,它代表依次进行Pod的部署和扩缩容:

  • 在创建一个副本数为N的StatefulSet时,其Pod将被按{0...N-1}的顺序逐个创建;
  • 在删除一个副本数为N的StatefulSet(或其中所有的Pod)时,其Pod将按照相反的顺序(即 {N-1...0})终止和删除;
  • 在对StatefulSet执行扩容操作时,新增Pod所有的前序Pod必须处于Running(运行)和Ready(就绪)的状态;
  • 终止和删除StatefulSet中的某一个Pod时,该Pod所有的后序Pod必须全部已终止。

若要并行管理Pod,需要设置.spec.podManagementPolicy字段值为Parallel,此时StatefulSet将同时并行地创建或终止其所有的Pod。

更新

StatefulSet的更新策略有两种,它是通过定义spec.updateStrategy.type字段的方式进行选择的。

  • On Delete:Controller将不会自动更新StatefulSet中的Pod,用户必须手动删除Pod以便让StatefulSet创建新的Pod,以此来对spec.template的变动作出反应。
  • Rolling Updates
    StatefulSet会删除和重建StatefulSet中的每个Pod,它将按照与Pod终止相同的顺序(从最大序号到最小序号)进行,每次更新一个Pod。它会等到被更新的Pod进入Running和Ready状态,然后再更新其前序Pod。

若Pod的template出错,导致Pod始终不能进入Running和Ready的状态,StatefulSet将停止滚动更新并一直等待(OrderedReady)。在修复template以后,StatefulSet将继续等待出错的Pod进入就绪状态,而该状态将永远无法出现。因此还必须删除所有已经尝试使用错误template的Pod,随后StatefulSet才会使用修复后的template重建Pod。

DaemonSet

DaemonSet确保全部(或者某些)节点上运行一个Pod的副本,且当有节点加入集群时,也会为他们新增一个Pod。当有节点从集群移除时,这些Pod同样会被回收。删除DaemonSet将会删除它所创建的所有Pod。

使用场景

  • 在每个节点上运行集群守护进程glusterd、ceph等
  • 在每个节点上运行日志收集守护进程fluentd、logstash等
  • 在每个节点上运行监控守护进程Prometheus等

Spec配置

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can‘t run pods
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
  • spec.template.spec.nodeSelector字段指定运行Pod的节点,若不设置则默认在全部节点上运行;
  • spec.template.spec.restartPolicy字段的值默认是always,也必须是always。

调度策略

DaemonSet Controller将会向DaemonSet管理的的Pod添加spec.nodeAffinity字段,并进一步由Kubernetes Scheduler将Pod绑定到目标节点。

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

此外,容忍度(toleration)node.kubernetes.io/unschedulable:NoSchedule将被系统自动添加到DaemonSet的Pod中。由此,默认调度器在调度DaemonSet的Pod时可以忽略节点的unschedulable属性。

通信

与DaemonSet中的Pod进行通信的几种可能模式如下:

  • Push:配置DaemonSet中的Pod,将更新发送到另一个服务,例如统计数据库;

  • 节点IP和已知端口:DaemonSet中的Pod可以使用节点的端口,从而可以通过节点IP访问到Pod。客户端能通过某种方法获取节点IP列表,并且基于此也可以获取到相应的端口;

  • DNS:创建Headless Service并通过设置标签选择器选取Pod,通过使用Endpoints对象或从DNS服务中检索到多个A记录来发现DaemonSet;

  • Service:创建Service并通过设置标签选择器选取Pod,使用该Service随机访问到某个节点上的DaemonSet。由于Service的负载均衡机制,因此没有办法访问到特定节点。

Jobs

Job会创建一个或者多个Pods,并确保指定数量的Pod可以执行到Succeeded状态。随着Pods成功结束,Job跟踪记录成功完成的Pods个数。当数量达到指定的成功个数阈值时,Job结束。删除Job的操作会清除其创建的全部Pod。

配置

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4 # Job 最大的重试次数
  • spec.template.spec.restartPolicy字段定义了Pod的重启策略,此处只允许使用Never和OnFailure两个取值;
  • spec.completionsspec.parallelism字段值默认为1,代表Job只启动一个Pod;
  • spec.completions表示Job期望成功运行至结束的Pod数量。当该字段值大于1时,Job将创建至相应数量的Pod,编号为1-spec.completions
  • spec.parallelism表示并行运行的Pod数量。当该字段值大于1时,Job会依次创建相应数量的 Pod 并行运行,直到spec.completions个Pod成功运行至结束;
  • spec.activeDeadlineSeconds字段指定Job的存活时长,该字段的优先级高于spec.backoffLimit
  • Job终止后Pod不会被删除,可以通过定义spec.ttlSecondsAfterFinished 字段实现自动清理Job以及Job管理的Pod。若字段值为100,则代表100秒后清理。若字段值为0,则代表Job完成后立即清理。

Endpoint Controller

负责维护Endpoint与其对应的Service的关系。Endpoint Controller会周期性地进行检查,确保它们始终运行在用户期望的状态。

GC Controller

在Kubernetes中,每一个从属对象都有一个metadata.ownerReferences字段,标识其拥有者是哪一个对象。GC Controller会删除那些曾经有owner,后来又不再有owner的对象。

参考文献

https://kubernetes.io/docs/home/
https://kuboard.cn/learning/

Kubernetes:Controller

标签:实现   har   data   write   record   running   部分   回收   pre   

原文地址:https://www.cnblogs.com/koktlzz/p/14414016.html


评论


亲,登录后才可以留言!