k8s学习-资源控制器

4.3、资源控制器

4.3.1、概念

Kubernetes中内建了很多种controller(控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为。

4.3.2、分类

ReplicationController&ReplicaSet

ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数量,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收;

在新的Kubernetes中建议使用ReplicaSet来取代ReplicationController。ReplicaSet跟前者没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector;

例子
mkdir -p /usr/local/docker/kubernetes/plugins/test/res
cd /usr/local/docker/kubernetes/plugins/test/res

vim rs.yml

apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 3 # 副本数 3
  selector:
    matchLabels: # 标签
      tier: frontend
  template:
    metadata: # 必须和上面定义的label匹配
      labels:
        tier: frontend
    spec:
      containers:
      - name: rs-nginx
        image: habor-repo.com/library/nginx:v1
        env: # 容器添加环境变量
        - name: GET_HOST_FROM
          value: dns
        ports:
        - containerPort: 80 # 容器的端口

测试:

kubectl create -f rs.yml
[ res]# kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
frontend-2mgxs   1/1     Running   0          5s
frontend-4rb72   1/1     Running   0          5s
frontend-fxlhr   1/1     Running   0          5s # 三个正常运行

# 查看标签
[ res]# kubectl get pod --show-labels
NAME             READY   STATUS    RESTARTS   AGE    LABELS
frontend-2mgxs   1/1     Running   0          2m8s   tier=frontend
frontend-4rb72   1/1     Running   0          2m8s   tier=frontend
frontend-fxlhr   1/1     Running   0          2m8s   tier=frontend

# 编辑标签
kubectl label pod frontend-2mgxs tier=frontend-1 --overwrite=true

#再次查看标签
[ res]# kubectl get pod --show-labels
NAME             READY   STATUS    RESTARTS   AGE     LABELS
frontend-2mgxs   1/1     Running   0          4m29s   tier=frontend-1
frontend-428wm   1/1     Running   0          5s      tier=frontend
frontend-4rb72   1/1     Running   0          4m29s   tier=frontend
frontend-fxlhr   1/1     Running   0          4m29s   tier=frontend
# 发现变成了四个容器,这是因为在定义rs.yml中的matchLabels会匹配template中的label,而此时frontend-2mgxs的label被修改了,rs就一维其中一个pod挂掉了,于是重新创建了一个pod来维持replicas=3的状态

# 查看所有的 replicaset 简写为 rs
[ res]# kubectl get rs 
NAME       DESIRED   CURRENT   READY   AGE
frontend   3         3         3       12m

# 删除某个 rs
kubectl delete rs frontend
# 删除所有pod
kubectl delete pod --all

Deployment

Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)的方法,用来替代以前的ReplicationController来方便的管理应用。典型场景包括:

  • 定义Deployment来创建Pod和ReplicaSet
  • 滚动升级和回滚应用
  • 扩容和缩容
  • 暂停和继续
例子

vim deployment.yml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3 # 副本数 3
  template:
    metadata: # 必须和上面定义的label匹配
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: habor-repo.com/library/nginx:v1
        env: # 容器添加环境变量
        - name: GET_HOST_FROM
          value: dns
        ports:
        - containerPort: 80 # 容器的端口

测试:

kubectl apply -f deployment.yml
#kubectl create 和 apply 的区别
#1. kubectl create命令,是先删除所有现有的东西,重新根据yaml文件生成新的。所以要求yaml文件中的配置必须是完整的
#2. kubectl create命令,用同一个yaml 文件执行替换replace命令,将会不成功,fail掉。

# 查看 deployment
kubectl get deploy
#或者
kubectl get deployment
[ res]# kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           3m22s

# 查看 rs
[ res]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-5b5cd5679f   3         3         3       4m9s
# deployment创建的时候会创建对应点rs,这里的nginx-deployment-5b5cd5679f就是对应的rs

# 查看 pod
[ res]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-5b5cd5679f-4vwmv   1/1     Running   0          5m21s
nginx-deployment-5b5cd5679f-845ms   1/1     Running   0          5m21s
nginx-deployment-5b5cd5679f-87s8f   1/1     Running   0          5m21s
# 发现 pod名字是rs名字加上随机后缀
扩容
# 扩容为10个副本
kubectl scale deployment nginx-deployment --replicas 10 

# 集群支持horizontal pod autoscaling 的话还可以自动扩展
kubectl autoscale deployment nginx-deploment --min=10 --max=15 --cpu-percent=80
更新&回滚
# ***************** 更新 ****************
# 1) kubectl set image deployment/[deployent名] [容器名]=[镜像名]
kubectl set image deployment/nginx-deployment nginx=habor-repo.com/library/nginx:v2

# 2) kubectl edit deployment/[deployent名]
kubectl edit deployment/nginx-deployment

# ***************** 回滚 ****************
# 查看历史 回滚
kubectl rollout history deployment/nginx-deployment
# 查看历史 RS(ReplicaSet)
kubectl get rs

# 1) 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
# 2) 回滚到指定历史版本
kubectl rollout undo deployment/nginx-deployment --to-version=2

# 暂停deployment 的更新(暂停后当前的nginx继续可用,更新的pod暂时不可用)
kubectl rollout pause deployment/nginx-deployment
# 恢复deployment 更新
kubectl rollout resume deployment/nginx-deployment

# 查看回滚状态
kubectl rollout status deployment/nginx-deployment


# 如果 rollout 完成会返回一个状态值 0,必须紧跟着回滚命令执行
echo $?
更新策略
  • Deployment可以保证在升级的时候只有一定数量的Pod是down的。默认的,他会确保至少有比期望的pod数量少一个是up状态(最多一个不可用)。

  • Deployment同时也可以确保只创建出超过期望数量的一定数量的Pod。默认的,他会确保最多比期望的Pod数量多的一个Pod是up的(最多一个surge,最多超出一个)

  • 未来的kubernetes版本中,将从1-1变成25%-25%(即更新的时候先创建replicas值25%新pod,然后停掉replicas的25%的旧pod)

kubectl describe deployment [deployment名]

rollover(并行rollout)

加入创建的10个replicas的nginx:v1,当前启动了三个pod的时候你把镜像修改为了nginx:v2,那么deployment会立即杀掉已经启动的nginx:v1,剩下的7个nginx会自动使用升级后的nginx:v2。

清理Policy

设置.spec.revisionHistoryLimit来指定deployment最多保留多少个revision历史记录,如果设置为0表示没有历史记录无法回滚。

# 查看文档:
[ ~]# kubectl explain deployment.spec | grep re
   revisionHistoryLimit	<integer> # 文档说明
     The number of old ReplicaSets to retain to allow rollback. This is a
     "retaining all old RelicaSets".
     DEPRECATED. The config this deployment is rolling back to. Will be cleared
     Label selector for pods. Existing ReplicaSets whose pods are selected by
     The deployment strategy to use to replace existing pods with new ones.
   template	<Object> -required-
     Template describes the pods that will be created.

DaemonSet

DaemonSet用来确保全部(或者一些)Node上运行一个Pod的副本。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群中移除时,这些Pod会被回收。删除DaemonSet将会删除创建的所有的Pod。典型应用场景:

  • 运行集群存储daemon,例如每个Node运行glusterd、ceph
  • 在每个Node上运行日志收集daemon,例如fluentd、logstash
  • 在每个Node上运行监控daemon,例如Prometheus NodeExplorer、collectd、Datadog代理、New Relic代理,或者Ganglia gmod
例子

vim daemonset.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemon-example
  labels:
    app: daemonset
spec:
  # replicas: 3 # 不允许该参数,因为DaemonSet在Node上只能有一个副本 
  selector:
    matchLabels:
      name: daemon-example
  template:
    metadata: # 必须和上面定义matchLabels的label匹配
      labels:
        name: daemon-example
    spec:
      containers:
      - name: nginx
        image: habor-repo.com/library/nginx:v1
        env: # 容器添加环境变量
        - name: GET_HOST_FROM
          value: dns
        ports:
        - containerPort: 80 # 容器的端口

测试

kubectl create -f daemonset.yml

# ds 是 daemonset 的缩写
[ ~]# kubectl get ds
NAME             DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemon-example   2         2         2       2            2           <none>          5s

[ ~]# kubectl get pod -o wide
NAME                   READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
daemon-example-2jm49   1/1     Running   0          30s   10.244.1.38   k8s-node1   <none>           <none>
daemon-example-tqzcp   1/1     Running   0          30s   10.244.2.51   k8s-node2   <none>           <none>

# 删除
kubectl delete ds daemon-example

Job

Job负责批处理任务,即仅执行一次的任务,他能保证批处理任务的一个或者多个Pod成功结束

特殊说明
  • spec.template格式同Pod
  • RestartPolicy仅支持NeverOnFailure
  • 单个Pod时,默认Pod成功运行后Job结束
  • .spec.completions标志Job结束运行的Pod个数,默认是1
  • .spec.parallelism标志并行运行的Pod个数,默认是1
  • .spec.activeDeadlineSecond标志失败Pod的重试最大时间,超过这个时间不会继续重试(单位:秒)
例子

vim job.yml

apiVersion: batch/v1
kind: Job
metadata:
  name: echo
spec:
  template:
    metadata: 
      name: echo
    spec:
      containers:
      - name: echo
        image: habor-repo.com/library/busybox:v1
        command: [‘sh‘, ‘-c‘, ‘echo the job app is running! && sleep 30‘]
      restartPolicy: Never

测试:

kubectl create -f job.yml

# 查看 job
[ ~]# kubectl get job 
NAME   COMPLETIONS   DURATION   AGE
echo   0/1           11s        11s

# 查看 pod
[ ~]# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
echo-7cn2h   1/1     Running   0          27s

# 查看日志
[ ~]# kubectl logs echo-7cn2h
the job app is running!

# 查看描述
[ ~]# kubectl describe pod echo-7cn2h

# 再次查看状态
[ ~]# kubectl get job
NAME   COMPLETIONS   DURATION   AGE
echo   1/1           31s        82s

# 删除 job (注意删除job不会删除pod,还需要手动删除pod)
kubectl delete job echo
kubectl get job # 发现没有job

CronJob

管理基于时间的Job,即:

  • 在给定时间点只运行一次
  • 周期性的在给定时间点运行

使用前提:当前Kubernetes集群版本>=1.8。对于旧版本集群,启动API Server时,通过传递选项--runtime-config=batch/v2alph1=true可以开启batch/v2alph1 API。

特殊说明
  • .spec.schedule:调度,必需字段,指定任务运行周期,格式同Cron表达式

  • .spec.jobTemplate:Job模板,必需字段,指定需要运行的任务,格式同Pod

  • .spec.startingDeadlineSecond:启动Job的期限(单位:秒),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的Job将被认为是失败的。如果没有指定,则没有期限。

  • .spec.concurrencyPolicy:并发策略,可选字段,指定了如何处理被Cron Job创建的Job的并发执行。允许下面策略中的一种:

    • Allow(默认):允许并发运行Job
    • Forbid:禁止并发运行。如果前一个还没完成,直接跳过下一个
    • Replace:取消当前正在运行的Job,用一个新的来替代

    注意:当前策略只能应用于同一个Cron Job创建Job。如果存在多个Cron Job,他们创建的Job之间总是并发运行。

  • .spec.suspend:挂起,该字段也是可选的,如果设置为true,后续所有的执行都会被挂起。它对应开始执行的Job不起作用。默认是false

  • .spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit:历史限制,可选字段,指定可以保留多少完成和失败的Job。默认值是31。如果设置为0那么相关类型的Job完成后将不会被保留。

例子

vim cronjob.yml

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: habor-repo.com/library/busybox:v1
            command: [‘sh‘, ‘-c‘, ‘echo [$date]the cronjob app is running!‘]
          restartPolicy: OnFailure

测试:

# 创建
kubectl create -f cronjob.yml
# 查看 cronjob
[ ~]# kubectl get cronjob
NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     0        <none>          5s

# 查看 job 需要等待执行完毕后才能看到 job 出现
[ ~]# kubectl get job -w 
NAME               COMPLETIONS   DURATION   AGE
hello-1583557200   1/1           1s         8s

# 查看 pod 需要 job 执行完毕后才出现
[ ~]# kubectl get pod 
NAME                     READY   STATUS      RESTARTS   AGE
hello-1583557200-n2c8m   0/1     Completed   0          38s


# 查看日志
[ ~]# kubectl logs hello-1583557200-n2c8m
[] cronjob app is running!

# 删除
kubectl delete cronjob --all

StatefulSet

StatefulSet作为Controller为Pod提供的唯一标识。他可以保证scale的顺序

StatefulSet是为了解决所有状态服务的问题(对应Deployment个ReplicaSet是无状态而设计),其应用场景包括:

  • 稳定持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
  • 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
  • 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init container来实现
  • 有序收缩,有需删除(即从N-1到0)

加入有个StatefulSet的name为web:

apiVersion: apps/v1
kind: StatefulSet
metadata:  
  name: web
spec:
  • 匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,web-2
  • StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为:$(podname).(headless servername),也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化
  • StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(servicename).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名

Horizontal Pod Autoscaling

应用的资源使用率都有高峰和低谷的时候,消峰填谷,提高集群整体的资源利用率,让service中的pod自定调整,即使Pod水平缩放。

# 以镜像 gcr.io/google_containers/hpa-example 举例子
kubectl run php-apache --image=gcr.io/google_containers/hpa-example --requests=cpu=200m --expose--port=80

# 创建 HPA 控制器 (相关算法参考文档)
# https://github.com/kubernetes/community/blob/master/contributors/design-proposals/horizontal-pod-autoscaler.md#autoscaling-algorithm
kubectl autoscale deployment php-apache --cpu-percent=50--min=1--max=10

# 增加负载,查看负载节点数目
kubectl run -i--tty load-generator --image=busybox /bin/sh
# whiletrue; dowget-q-O- http://php-apache.default.svc.cluster.local; done

# 实时观察php-apache的资源占用情况
# kubectl top pod -n <名称空间>
# 例如:
kubectl top pod -n kube-system

资源限制

文档:https://kubernetes.io/docs/concepts/policy/resource-quotas/

1)Pod级别限制:

Kubernetes 对资源的限制实际上是通过 cgroup 来控制的,cgroup 是容器的一组用来控制内核如何运行进程的相关属性集合。针对内存、CPU 和各种设备都有对应的 cgroup

默认情况下,Pod 运行没有 CPU 和内存的限额。这意味着系统中的任何 Pod 将能够像执行该 Pod 所在的节点一样,消耗足够多的 CPU 和内存。一般会针对某些应用的 pod 资源进行资源限制,这个资源限制是通过resources 的 requests 和 limits 来实现

例如:

kubectl explain pod.spec.containers.resources

apiVersion: v1
kind: Pod 
metadata:
  name: my-app 
  namespace: default 
  labels: 
    app: myapp 
spec:
  containers:
  - name: nginx
    imagePullPolicy: IfNotPresent
    image: habor-repo.com/library/nginx:v1
    ports:
    - name: http
      protocol: TCP
      containerPort: 80
    resources:
      limits: # 上线
        cpu: 4
        memory: 2Gi
      requests: # 初始
        cpu: 250m # 250m HZ 频率的CPU
        memory: 1Gi

2)名称空间级别:

2.1)、计算资源配额

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
  namespace: spark-cluster
spec:
  hard:
    pods: 20
    requests.cpu: 20
    requests.memory: 100Gi
    limits.cpu: 40
    limits.memory: 200Gi

2.2)、配置对象数量配额限制

apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
  namespace: spark-cluster
spec:
  hard:
    configmaps: 20 # 最大configmap
    persistentvolumeclaims: 4 # 最大pvc
    replicationcontrollers: 20 # 最大副本
    secrets: 10
    services: 10
    services.loadbalancers: 2

2.3)、配置 CPU 和内存 LimitRange

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  - default: # 即 limit 的值
      memory: 50Gi
      cpu: 5
    defaultRequest: # 即 request 的值
      memory: 1Gi
      cpu: 1
    type: Container

相关推荐