k8s 笔记(四) 控制器

2020/03/15 k8s

1. 控制器介绍

ReplicaSet 是下一代的 Replication Controller。 ReplicaSet 和 Replication Controller 的唯一区别是选择器的支持。 ReplicaSet 支持新的基于集合的选择器(selector)需求

2. ReplicaSet

ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 然而 Deployment 是一个更高级的概念,它管理 ReplicaSet, 并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,更建议使用 Deploymen。

示例:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # 3个副本数
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - { key: tier,operator: In, values:[frontend]}
  template:
    metadata:
      labels:
        app: guestbook
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 80

将资源清单保存到frontend.yaml 中,执行 kubectl create -f frontend.yaml 就可以看到对应的 pod已经创建

$ kubectl get rs --show-labels=true  -l app=guestbook
NAME       DESIRED   CURRENT   READY   AGE   LABELS
frontend   3         3         3       25m   app=guestbook,tier=frontend

$ kubectl get pod --show-labels=true -l app=guestbook
NAME             READY   STATUS    RESTARTS   AGE   LABELS
frontend-82tvl   1/1     Running   0          25m   app=guestbook,tier=frontend
frontend-q878l   1/1     Running   0          25m   app=guestbook,tier=frontend
frontend-wh7n4   1/1     Running   0          25m   app=guestbook,tier=frontend

2.1. 编写 ReplicaSet Spec

与所有其他Kubernetes API 对象一样, ReplicaSet 也需要 apiVersion kind metadata spec 字段

  • Pod 模板

    .spec.template.spec 唯一需求的字段。

    .spec.template 是 Pod 模板,和 Pod 的语法完全一样,只需要将 Pod 的metadataspec语法嵌套进去就可以了.

    重启策略: spec.template.spec.restartPolicy 唯一允许 Always

  • Pod 选择器

    .spec.seletor 字段是标签选择器。ReplicaSet 管理所有与标签选择器匹配的Pod。 它不区分是否为自己创建的Pod。 这允许在不影响运行中的 Pod 的情况下替换副本集. .spec.template.metadata.labels 必须匹配 .spec.selector, 否则它将被 API 拒绝。

    通常不应该创建标签与此选择器匹配的任何Pod,或者直接与另一个 ReplicaSet 或 另一个控制器(如 Deployment) 标签匹配的任何Pod , 如果这样做, ReplicaSet 会认为它创造了其他 Pod 。 kubernetes 并不会阻止你这样做。

    示例:

      $ cat pod.yaml
      apiVersion: v1
      kind: Pod
      metadata:
        name: frontend-test
        labels:
          app: guestbook
          tier: frontend
      spec:
        containers:
        - name: frontend-test
          image: harbor.tansuotv.cn/library/nginx:v1
    	    
      $ kubectl create -f pod.yaml
      pod/frontend-test created
    
      $ kubectl get pod  --show-labels=true -l app=guestbook
      NAME             READY   STATUS        RESTARTS   AGE   LABELS
      frontend-82tvl   1/1     Running       0          79m   app=guestbook,tier=frontend
      frontend-q878l   1/1     Running       0          79m   app=guestbook,tier=frontend
      frontend-test    0/1     Terminating   0          5s    app=guestbook,tier=frontend
      frontend-wh7n4   1/1     Running       0          79m   app=guestbook,tier=frontend
    	
    
  • Replicas

    通过设置 .spec.replicas 可以指定要同时运行多少个 Pod。 在任何时间运行 Pod 数量 可能高于或低于 .spec.replicas 指定的数量,例如在副本刚刚被增加或减少后,或者 Pod 正在被关闭或者替换。

2.2. 使用 ReplicaSets 的具体方法

  • 删除 ReplicaSet 和它的 Pod

    要删除 ReplicaSet 和它的所有 Pod, 使用 kubectl delete 命令。 默认情况下,垃圾收集器自动删除所有依赖的 Pod。

    当使用 REST API 或 client-go 库时, 您必须在删除选项中将 propagationPolicy 设置为 BackgroundForeground。 例如:

    ``` kubectl proxy –port=8080 curl -X DELETE ‘localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend’ \

    -d ‘{“kind”:”DeleteOptions”,”apiVersion”:”v1”,”propagationPolicy”:”Foreground”}’ \ -H “Content-Type: application/json” Z```

  • 只删除ReplicaSet

    可以只删除 ReplicaSet 而不影响它的 Pod, 方法是使用 kubectl delete 命令去设置 --cascade=false 选项

    当使用 REST API 或 client-go库时, 必须将 propagationPolicy 设置为 Orphan。例如:

      kubectl proxy --port=8080
      curl -X DELETE  'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
      > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
      > -H "Content-Type: application/json"
    

    一旦删除了原来的ReplicaSet ,就可以创建一个新的来替换它。 由于新旧ReplicaSet的.spec.selector是相同的,新的 ReplicaSet 将接管老的 Pod。 但是,它不会努力使现有的Pod 与新的、不同的Pod 模板匹配。 若想要以可控的方式将Pod 更新到新的 spec,就要使用滚动更新的方式

  • 将Pod 从 ReplicaSet 中隔离

    可以通过改变标签来从 ReplicaSet 的目标集中移除 Pod。这种技术可以用来从服务中去除 Pod,以便进行排错、数据恢复等。 以这种方式移除的 Pod 将被自动替换(假设副本的数量没有改变)。

      $ kubectl edit pod frontend-42x87
      pod/frontend-42x87 edited
    
  • 缩放 ReplicaSet

    通过更新 .spec.replicas 字段,ReplicaSet 可以被轻松的进行缩放。ReplicaSet 控制器能确保匹配标签选择器的数量的 Pod 是可用的和可操作的。

      $ kubectl edit rs frontend
      replicaset.extensions/frontend edited
    
  • ReplicaSet 作为水平的Pod 自动缩放器目标

    ReplicaSet 也可以作为 水平的Pod缩放器(HPA)的目标,ReplicaSet 可以被 HPA自动缩放

    示例:

      apiVersion: autoscaling/v1
      kind: HorizontalPodAutoscaler
      metadata:
        name: frontend-scaler
      spec:
        scaleTargetRef:
          kind: ReplicaSet
          name: frontend
        minReplicas: 3
        maxReplicas: 10
        targetCPUUtilizationPercentage: 50
    

    将这个列表保存到 hpa-rs.yaml 并提交到 Kubernetes 集群,就能创建它所定义的 HPA,进而就能根据复制的 Pod 的 CPU 利用率对目标 ReplicaSet进行自动缩放。

    kubectl create -f https://k8s.io/examples/controllers/hpa-rs.yaml

    或者,可以使用 kubectl autoscale 命令完成相同的操作。 (而且它更简单!)

    kubectl autoscale rs frontend

3. Reployment

Deployment 是个高级 API 对象,它以 kubectl rolling-update的方式更新其底层副本集及其Pod。

如果需要滚动更新功能,建议使用Deployment, 因为 Deployment 与 kubectl rolling-update 不同的是: 它是声明式的、服务端的、并且具有其他特性。

3.1. 创建 Deployment

示例:

apiVersion: extensions/v1beta1
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: nginx:1.15.4
        ports:
        - containerPort: 80

该清单主要完成以下工作:

  • 创建名为 nginx-deployment 的 Deployment,由.metadata.name 字段指示
  • Deployment 创建三个复制的 Pods,由 replicas 字段指示
  • selector 字段定义 Deployment 如何查找要管理的 Pods。 在这种情况下,只要选择在 Pod 模板(app: nginx) 中定义的标签, 更复杂的选择规则是可能的, 只要 Pod 模板本身满足规则

注意:

matchLabels 字段是 {key,value} 的映射。单个 {key,value}在 matchLabels 映射中的值等效于 matchExpressions 的元素,其键字段是“key”,运算符为“In”,值数组仅包含“value”。所有要求,从 matchLabelsmatchExpressions,必须满足才能匹配。

  • template 字段包含以下子字段
  • Pod 使用label字段 标记为 app: nginx
  • Pod 模板规范或.template.spec字段指示Pods运行一个容器,nginx 运行 nginx
  • 创建一个容器并使用 name字段将其命名为nginx

注意:

可以指定 --record 标志来写入在资源注释kubernetes.io/change-cause中执行的命令。它对以后的检查是有用的。

检查创建结果

$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/3     3            2           8m


$ kubectl get pod
NAME                               READY   STATUS              RESTARTS   AGE
nginx-deployment-9b644dcd5-dj6nw   0/1     ContainerCreating   0          24s
nginx-deployment-9b644dcd5-lb8hm   1/1     Running             0          24s
nginx-deployment-9b644dcd5-tp674   1/1     Running             0          24s

**查看Deployment 状态 **

$ kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out

查看Deployment 创建的 ReplicaSet (rs)

$ kubectl get rs
NAME                         DESIRED   CURRENT   READY   AGE
nginx-deployment-9b644dcd5   3         3         3       38m

要查看每个 Pod 自动生成的标签

$ kubectl get pods --show-labels
NAME                               READY   STATUS    RESTARTS   AGE   LABELS
nginx-deployment-9b644dcd5-dj6nw   1/1     Running   0          39m   app=nginx,pod-template-hash=9b644dcd5
nginx-deployment-9b644dcd5-lb8hm   1/1     Running   0          39m   app=nginx,pod-template-hash=9b644dcd5
nginx-deployment-9b644dcd5-tp674   1/1     Running   0          39m   app=nginx,pod-template-hash=9b644dcd5

3.2. 更新 Deployment

$ kubectl --record deployment/nginx-deployment set image nginx=nginx:1.9.1
deployment.extensions/nginx-deployment image updated


$ kubectl get pod
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-7448597cd5-q8p52   1/1     Running             0          23s
nginx-deployment-7448597cd5-xm98k   0/1     ContainerCreating   0          27s
nginx-deployment-7448597cd5-z9762   1/1     Running             0          27s

查看展开状态

$ kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 2 of 3 updated replicas are available...

$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/3     3            2           46m

查看 ReplicaSet 状态

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-7448597cd5   3         3         2       3m38s
nginx-deployment-7b45cc56cf   0         0         0       4m48s

3.3. 回滚

触发 Deployment 展开时,将创建 Deployment 修改版。这意味着仅当 Deployment Pod 模板 (.spec.template) 发生更改时,才会创建新修改版本,例如,如果更新模板的标签或容器镜像 。其他更新,如扩展 Deployment 、不要创建 Deployment 修改版,以便方便同时手动或自动缩放。这意味着,当回滚到较早的修改版时,只有 Deployment Pod 模板部分回滚。

检查Deployment 展开历史

  • 检查 Deployment 修改历史:

      $ kubectl rollout history deployment.v1.apps/nginx-deployment
      deployment.apps/nginx-deployment
      REVISION  CHANGE-CAUSE
      2         kubectl deployment/nginx-deployment set image nginx=nginx:1.91. --record=true
      3         <none>
      4         kubectl deployment/nginx-deployment set image nginx=nginx:1.9.1 --record=true
    
  • 查看修改历史详细信息

      $ kubectl rollout history deployment/nginx-deployment --revision=2
      deployment.extensions/nginx-deployment with revision #2
      Pod Template:
        Labels:	app=nginx
          pod-template-hash=7b45cc56cf
        Annotations:	kubernetes.io/change-cause: kubectl deployment/nginx-deployment set image nginx=nginx:1.91. --record=true
        Containers:
         nginx:
          Image:	nginx:1.91.
          Port:	80/TCP
          Host Port:	0/TCP
          Environment:	<none>
          Mounts:	<none>
        Volumes:	<none>
    
  • 回滚到上一次修改

      $ kubectl rollout undo deployment.v1.apps/nginx-deployment
      deployment.apps/nginx-deployment rolled back
    	
      $ kubectl get pod -o wide
      NAME                                READY   STATUS              RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
      nginx-deployment-7448597cd5-q8p52   1/1     Running             0          71m   10.244.2.47   k8s-n2   <none>           <none>
      nginx-deployment-7448597cd5-z9762   1/1     Running             0          71m   10.244.2.46   k8s-n2   <none>           <none>
      nginx-deployment-7448597cd5-zhqb5   0/1     Terminating         0          53m   <none>        k8s-n1   <none>           <none>
      nginx-deployment-9b644dcd5-58fxf    0/1     ContainerCreating   0          4s    <none>        k8s-n2   <none>           <none>
      nginx-deployment-9b644dcd5-wgc6f    0/1     ContainerCreating   0          4s    <none>        k8s-n1   <none>           <none>
    	
      $ kubectl get deployment nginx-deployment
      NAME               READY   UP-TO-DATE   AVAILABLE   AGE
      nginx-deployment   3/3     3            3           114m
    
    

更多回滚命令参考

$ kubectl rollout undo -h
Rollback to a previous rollout.

Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc

  # Rollback to daemonset revision 3
  kubectl rollout undo daemonset/abc --to-revision=3

  # Rollback to the previous deployment with dry-run
  kubectl rollout undo --dry-run=true deployment/abc
 ....

3.4. 缩放

将 pod 副本集从3个 修改为10个

$ kubectl scale deployment.v1.apps/nginx-deployment --replicas=10

deployment.apps/nginx-deployment scaled

$ kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-9b644dcd5-58fxf   1/1     Running   0          3m26s
nginx-deployment-9b644dcd5-6ts8v   1/1     Running   0          18s
nginx-deployment-9b644dcd5-924j2   1/1     Running   0          18s
nginx-deployment-9b644dcd5-jnp2v   1/1     Running   0          18s
nginx-deployment-9b644dcd5-mbclq   1/1     Running   0          18s
nginx-deployment-9b644dcd5-pmkth   1/1     Running   0          18s
nginx-deployment-9b644dcd5-r2nx6   1/1     Running   0          18s
nginx-deployment-9b644dcd5-wgc6f   1/1     Running   0          3m26s
nginx-deployment-9b644dcd5-z6nlq   1/1     Running   0          3m21s
nginx-deployment-9b644dcd5-zhts4   1/1     Running   0          18s

水平缩放

基于现有 Pod 的 CPU 利用率缩放

kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-percent=80

3.5. 暂停、恢复

可以在触发一个或多个更新之前暂停 Deployment ,然后继续它。这允许在暂停和恢复之间应用多个修补程序,而不会触发不必要的 Deployment

示例:

# 新建 deployment
$ kubectl apply -f nginx-deployment.yaml
deployment.extensions/nginx-deployment created

# 查看deployment
$ kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           5s

# 查看rs
$ kubectl get rs
NAME                         DESIRED   CURRENT   READY   AGE
nginx-deployment-9b644dcd5   3         3         3       9s

# 暂停 deployment
$ kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused

# 更新镜像
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.extensions/nginx-deployment image updated

# 查看rollout history
$ kubectl rollout history deployment/nginx-deployment
deployment.extensions/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>

# 查看rs状态
$ kubectl get rs
NAME                         DESIRED   CURRENT   READY   AGE
nginx-deployment-9b644dcd5   3         3         3       2m5s

# 修改资源限制
$ kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.extensions/nginx-deployment resource requirements updated

# 恢复
$ kubectl rollout resume deployment/nginx-deployment
deployment.extensions/nginx-deployment resumed

# 查看rs状态
$ kubectl get rs 
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-7576c67d77   3         3         2       10s
nginx-deployment-9b644dcd5    0         0         0       3m24s

$ kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 2 of 3 updated replicas are available...


所有deployment 在 pause 状态的更新、滚动操作都不会执行 ,等到 resume 后 会继续执行

3.6. Deployment 状态

使用 kubectl rollout status 监视 Deployment 的进度

$ kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out

3.7. Deployment 失败

可能引起 Deployment 失败的因素有:

  • 赔额不足
  • 就绪探测失败
  • 镜像拉取错误
  • 权限不足
  • 限制范围
  • 应用程序运行时配置错误

检测此条件的一种方法是在 Deployment 规范中指定截止时间参数:([.spec.progressDeadlineSeconds](#progress-deadline-seconds))。
.spec.progressDeadlineSeconds 进度截止时间秒表示 Deployment 控制器在指示(处于 Deployment 状态)之前等待的秒数 Deployment 进度已停止。

以下 kubectl 命令设置具有进度的规范,使控制器报告 10 分钟后 Deployment 进度不足:

$ kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
deployment.apps/nginx-deployment patched

超过截止时间后, Deployment 控制器将添加具有以下属性到 Deployment 的 .status.conditions:

  • Type=Progressing
  • Status=False
  • Reason=ProgressDeadlineExceeded

注意:

Kubernetes 对已停止的 Deployment 不执行任何操作,只需使用 Reason=ProgressDeadlineExceeded。 更高级别的编排器可以利用它并相应地采取行动,例如,将 Deployment 回滚到其以前的版本。

注意: 如果暂停 Deployment ,Kubernetes 不会根据指定的截止时间检查进度。可以在展开栏中间安全地暂停 Deployment ,并在不触发超过最后期限时恢复。

Deployments 可能会出现短暂的错误,既不是因为设置的超时时间过短,也不是因为任何真正的暂时性错误。例如配额不足。如果描述 Deployment ,将注意到以下部分:

kubectl describe deployment nginx-deployment

...
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-b7556d645 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  46m   deployment-controller  Scaled up replica set nginx-deployment-9b644dcd5 to 3
  Normal  ScalingReplicaSet  42m   deployment-controller  Scaled up replica set nginx-deployment-7576c67d77 to 1
  Normal  ScalingReplicaSet  42m   deployment-controller  Scaled down replica set nginx-deployment-9b644dcd5 to 2
  Normal  ScalingReplicaSet  42m   deployment-controller  Scaled up replica set nginx-deployment-7576c67d77 to 2
...

如果运行 kubectl get deployment nginx-deployment -o yaml, Deployment 状态输出:

$ kubectl get deployment nginx-deployment -o yaml
...
status:
  availableReplicas: 3
  conditions:
  - lastTransitionTime: "2020-03-17T08:59:10Z"
    lastUpdateTime: "2020-03-17T08:59:10Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  - lastTransitionTime: "2020-03-17T09:43:19Z"
    lastUpdateTime: "2020-03-17T09:43:19Z"
    message: ReplicaSet "nginx-deployment-b7556d645" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  observedGeneration: 7
  readyReplicas: 3
  replicas: 3
  updatedReplicas: 3
...

最终,一旦超过 Deployment 进度截止时间,Kubernetes 将更新状态和进度状态:

Conditions:
  Type            Status  Reason
  ----            ------  ------
  Available       True    MinimumReplicasAvailable
  Progressing     False   ProgressDeadlineExceeded
  ReplicaFailure  True    FailedCreate

4. DaemonSet

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

DaemonSet 的一些典型用法:

  • 在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph。
  • 在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash。
  • 在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter、Flowmill、Sysdig 代理、collectd、Dynatrace OneAgent、AppDynamics 代理、Datadog 代理、New Relic 代理、Ganglia gmond 或者 Instana 代理。

Search

    Table of Contents