k8s集群核心概念Controller(控制器)

k8s集群核心概念Controller

一、pod控制器

在 Kubernetes 中内建了很多控制器(controller),这些相当于一个状态机,用来控制 Pod 的具体状态和行为的,在 Kubernetes 中内建控制器有如下几种,它们的功能和特点各不相同。

简单介绍

与所有其它 Kubernetes 配置一样,我们创建资源控制器的时候也是需要,如 apiVersion、kind 和 metadata 等字段的,通过使用这些字段组成配置文件,来完成服务部署的。

  • pod模板:spec.template

    书写配置文件的时候spect.template是一个pod模板,它的模式与pod完全相同,只是它是嵌套的没有apiVersion或kind属性

  • 设置标签

    优先级高:metadata.labels

    优先级低:spec.template.metadata.labels

    没有指定metadata.labels则默认为spec.template.metadata.labels

  • pod选择器

    spec.selector

    spec.template.metadata.labels

    没有指定spec.selector,则默认为spec.template.metadata.labels其中 spec.selector 字段是一个标签选择器,所创建出来的标签用于选择则出匹配的 Pod。如果指定了 spec.template.metadata.labels 字段,则必须和 spec.selector 字段相同,否则在创建的时候将会被 API 拒绝。

  • 多个副本

    spec.replicas

    可以通过设置 spec.replicas 来指定应该同时运行多少个 Pod。在任何时候,处于运行状态的 Pod 个数都可能高于或者低于设定值。例如副本个数刚刚被增加或减少时,或者一个 pod 处于优雅终止过程中而其替代副本已经提前开始创建时。如果没有指定 spec.replicas,那么它默认是 1 个。

资源类型

资源类型缩写别名
clusters-
componentstatusescs
configmapscm
daemonsetsds
deploymentsdeploy
endpointsep
eventev
horizontalpodautoscalershpa
ingressesing
jobs-
limitrangeslimits
namespacesns
networkpolicies-
nodesno
statefulsets-
persistentvolumeclaimspvc
persistentvolumespv
podspo
podsecuritypoliciespsp
podtemplates-
replicasetsrs
replicationcontrollersrc
resourcequotasquota
cronjob-
secrets-
serviceaccountsa
servicessvc
storageclasses-
thirdpartyresources-

格式化输出

要以特定的格式向终端窗口输出详细信息,可以在 kubectl 命令中添加 -o 或者 -output 标志。

-o=custom-columns=<spec>   #使用逗号分隔的自定义列列表打印表格
-o=custom-columns-file=<filename> #使用文件中的自定义列模板打印表格
-o=json    #输出JSON 格式的API对象
-o=jsonpath=< template>       #打印jsonpath表达式中定义的字段
-o=jsonpath-file=<filename>   #打印由文件中的jsonpath表达式定义的字段
-o=name  #仅打印资源名称 
-o=wide  #以纯文本格式输出任何附加信息,对于Pod ,包含节点名称
-o=yaml  #输出 YAML 格式的 API 对象 

Kubectl 命令

Kubectl 详细输出和调试,使用 -v 或 --v 标志跟着一个整数来指定日志级别

--v=0  #总是对操作人员可见。
--v=1  #合理的默认日志级别,如果您不需要详细输出。
--v=2  #可能与系统的重大变化相关的,有关稳定状态的信息和重要的日志信息。这是对大多数系统推荐的日志级别。
--v=3  #有关更改的扩展信息。
--v=4  #调试级别详细输出。
--v=6  #显示请求的资源。
--v=7  #显示 HTTP 请求的 header。
--v=8  #显示 HTTP 请求的内容。

二、ReplicationController

与用户直接创建 pod 的情况不同,RC 能够替换因某些原因被删除或被终止的 pod,例如内核升级等情况。因此,建议使用 RC 来创建 pod,这样我们就可以不用人为的管理令人头痛的 pod 了。

功能特点

用来确保容器应用的副本数始终保持在用户定义的副本数。如果有容器异常退出的话,其会自动创建新的 Pod 来替代,而如果有异常多出来的容器也会被自动回收掉的。

工作方式

当 pod 数量过多时,Replication Controller 会终止多余的 pod;当 pod 数量太少时,RC 将会启动新的 pod。与手动创建的 pod 不同之处在于,由 Replication Controller 创建的 pod 在失败、被删除或被终止时会被自动替换。例如,在中断性维护之后,创建的 pod 会在节点上会重新创建。因此,即使应用程序只需要一个 pod,也应该使用 Replication Controller 来创建 Pod。对应 Replication Controller 我们可以类似理解为进程管理器,但是 Replication Controller 不是监控单个节点上的单个进程,而是监控跨多个节点的多个 pod。

示例运行

创建资源清单文件
# [ReplicationController]
# spec.template是spec的唯一必需字段
# 只允许.spec.template.spec.restartPolicy等于Always

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
  namespace: test-hl
spec:
  replicas: 3
  selector:
    app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginxapp
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports: 
        - containerPort: 88
        resources:
          limits:
            cpu: '1'
            memory: 1Gi
          requests:
            cpu: 200m
            memory: 512Mi
部署服务
root@k8s1:/development/hl/k8s-controller-test# kubectl apply -f 01-create-ReplicationController.yaml 
replicationcontroller/nginx created
查看服务
root@k8s1:/development/hl/k8s-controller-test# kubectl get replicationcontrollers --namespace test-hl
NAME    DESIRED   CURRENT   READY   AGE
nginx   3         3         3       3m30s
root@k8s1:/development/hl/k8s-controller-test# kubectl describe replicationcontrollers --namespace test-hl
Name:         nginx
Namespace:    test-hl
Selector:     app=nginx
Labels:       app=nginx
Annotations:  <none>
Replicas:     3 current / 3 desired
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=nginx
  Containers:
   nginxapp:
    Image:      nginx:latest
    Port:       88/TCP
    Host Port:  0/TCP
    Limits:
      cpu:     1
      memory:  1Gi
    Requests:
      cpu:        200m
      memory:     512Mi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age    From                    Message
  ----    ------            ----   ----                    -------
  Normal  SuccessfulCreate  7m37s  replication-controller  Created pod: nginx-9jd9h
  Normal  SuccessfulCreate  7m36s  replication-controller  Created pod: nginx-r5xnj
  Normal  SuccessfulCreate  7m36s  replication-controller  Created pod: nginx-4j6m9
kubectl命令行删除
root@k8s1:/development/hl/k8s-controller-test# kubectl get replicationcontrollers --namespace test-hl
NAME    DESIRED   CURRENT   READY   AGE
nginx   3         3         3       13m
root@k8s1:/development/hl/k8s-controller-test# kubectl delete replicationcontrollers nginx --namespace test-hl
replicationcontroller "nginx" deleted

三、ReplicaSet

功能特点

ReplicaSetReplicationController的唯一区别是在选择器的支持上。其中 ReplicaSet支持集合(selector)的选择器,其就意味着其支持通过标签进行 Pod 的选择,而 ReplicationController 仅支持基于相等选择器。

工作方式

ReplicaSet确保任何时间都有指定数量的 Pod 副本在运行,而且大多数支持 ReplicationController的 kubectl 命令也支持 ReplicaSet,但是 rolling-update 这个命令是个例外。如果你需要使用滚动更新功能,请考虑使用 Deployment 来创建 Pod。

虽然 ReplicaSet 可以独立的使用和创建, 然而 Deployment 是一个更高级的概念,它管理 ReplicaSet 并向 Pod 提供声明式的更新以及许多其他有用的功能,用作协调 Pod 创建、删除和更新的机制。当你使用 Deployment 的时候,不必担心还要管理它们创建的 ReplicaSet 控制器。因此,建议使用 Deployment 而不是直接使用 ReplicaSet,除非你需要自定义更新业务流程或根本不需要更新。

示例运行

创建资源清单文件
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: redis
  namespace: test-hl
  labels:
    app: redis
spec:
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis-app
        image: redis:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 6379
        resources:
          limits:
            cpu: '1'
            memory: 1Gi
          requests:
            cpu: 200m
            memory: 512Mi  

部署服务

root@k8s1:/development/hl/k8s-controller-test# kubectl apply -f 02-create-ReplicaSet.yaml 
replicaset.apps/redis created
查看服务
root@k8s1:/development/hl/k8s-controller-test# kubectl get replicasets.apps --namespace test-hl
NAME    DESIRED   CURRENT   READY   AGE
redis   3         3         3       2m47s
kubectl命令行删除
root@k8s1:/development/hl/k8s-controller-test# kubectl delete replicasets.apps redis --namespace test-hl
replicaset.apps "redis" deleted

四、Deployment

官方推荐的 Pod 部署方式,所以以后创建 Pod 的话,优先选择!

功能特点

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义的方法,用来替代以前的 ReplicationController 来方便的管理应用。而定义方式分为,命令式(ReplicaSet )和声明式(Deployment)两种,前者侧重于考虑如何实现,而后者侧重于定义想要什么。

应用场景

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

示例运行 -创建

创建资源清单文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: test-hl
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginxapp
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports: 
        - containerPort: 88
        resources:
          limits:
            cpu: '1'
            memory: 1Gi
          requests:
            cpu: 200m
            memory: 512Mi

部署服务

# 部署服务
$ kubectl apply -f 03-create-Deployment.yaml

# 检查Deployments的状态
$ kubectl get deployments.apps --namespace test-hl
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           105s

#上述输出字段含义解释
NAME: 列出了集群中Deployments的名称
DESIRED: 显示应用程序的期望状态的所需副本数
CURRENT: 显示当前正在运行的副本数
UP-TO-DATE: 显示已更新以实现期望状态的副本数
AVAILABLE: 显示应用程序可供用户使用的副本数
AGE: 显示应用程序运行的时间量

# 查看Deployment展开状态
$ kubectl rollout status deployment/nginx-deployment --namespace test-hl
deployment "nginx-deployment" successfully rolled out

# 检查RC的状态
$ kubectl describe rs --namespace test-hl

# 查看每个Pod自动生成的标签
$ kubectl get pods --show-labels --namespace test-hl

示例运行-更新

# 第一种方式
$ kubectl set image deployment/nginx-deployment nginx-app=nginx:1.9.1 --namespace test-hl
deployment.apps/nginx-deployment image updated

# 第二种方式
$ kubectl edit deployment/nginx-deployment --namespace test-hl

使用 rollout 命令来,查看其展开的状态。

# 查看展开状态
$ kubectl rollout status deployment/nginx-deployment --namespace test-hl
deployment "nginx-deployment" successfully rolled out

# 检查RC的状态
$ kubectl get rs --namespace test-hl
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-7b4d8f89cb   3         3         3       3m50s
nginx-deployment-7d4df5fd74   0         0         0       17m

# 查看Pod的状态(生成了新的Pods)
$ kubectl get pods --namespace test-hl
nginx-deployment-7b4d8f89cb-bp5s4   1/1     Running   0          3m58s
nginx-deployment-7b4d8f89cb-ccg8r   1/1     Running   0          5m54s
nginx-deployment-7b4d8f89cb-mh7nl   1/1     Running   0          4m1s
  • Deployment 可确保在更新时仅关闭一定数量的 Pods,默认情况下,它确保至少 75% 所需 Pods 是运行的,即有 25% 的最大不可用。Deployment 还确保仅创建一定数量的 Pods 高于期望的 Pods 数,默认情况下,它可确保最多增加 25% 期望 Pods 数。出现上述情况的时候,多是在进行扩容、缩容、滚动升级和回滚应用时出现。
  • 可以看到,当第一次创建 Deployment 的时候,它创建了一个 ReplicaSet 并将其直接扩展至 3 个副本。更新 Deployment 时,它创建了一个新的 ReplicaSet ,并将其扩展为 1,然后将旧 ReplicaSet 缩小到 2,以便至少有 2 个 Pod 可用,并且最多创建 4 个 Pod。然后,它继续向上和向下扩展新的和旧的 ReplicaSet ,具有相同的滚动更新策略。最后,将有 3 个可用的副本在新的 ReplicaSet 中,旧 ReplicaSet 将缩小到 0。
# 获取Deployment的更多信息
$ kubectl describe deployments

在这里插入图片描述

示例运行 - 回滚

  • 当 Deployment 不稳定或遇到故障的的时候,例如循环崩溃,这时可能就需要回滚 Deployment 了。在默认情况下,所有 Deployment 历史记录都保留在系统中,以便可以随时回滚。当然,可以通过修改历史记录限制来更改该限制。当回滚到较早的修改版时,只有 Deployment Pod 模板部分会回滚。这是因为当 Deployment Pod 模板(.spec.template)发生更改时,才会创建新修改版本。例如,如果更新模板的标签或容器镜像,其他更新,如扩展 Deployment。
  • 假设在更新 Deployment 时犯了一个拼写错误,将镜像名称命名为 nginx:1.91 而不是 nginx:1.9.1,这样我们更新 Pod 的时候就会出现错误。
# 设置镜像来更新服务
$ kubectl set image deployment/nginx-deployment nginx-app=nginx:1.91 --namespace test-hl
deployment.apps/nginx-deployment image updated

# 遇到问题展开状态来验证
# 通过如下命令来查看Deployment是否完成
$ kubectl rollout status deployment/nginx-deployment --namespace test-hl
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...

查看旧 ReplicaSets 和 Pod 的时候,会发现由新 ReplicaSet 创建的 1 个 Pod 卡在镜像拉取循环中,要解决此问题,需要回滚到以前稳定的 Deployment 版本。

# 查看RS状态
$ kubectl get rs --namespace test-hl
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-6b5ff798f6   1         1         0       100s
nginx-deployment-7b4d8f89cb   3         3         3       18m
nginx-deployment-7d4df5fd74   0         0         0       32m

# 查看Pod状态
$ kubectl get pods --namespace test-hl
NAME                                READY   STATUS             RESTARTS   AGE
nginx-deployment-6b5ff798f6-ls6lh   0/1     ImagePullBackOff   0          2m9s
nginx-deployment-7b4d8f89cb-bp5s4   1/1     Running            0          17m
nginx-deployment-7b4d8f89cb-ccg8r   1/1     Running            0          19m
nginx-deployment-7b4d8f89cb-mh7nl   1/1     Running            0          17m

按照如下步骤,检查 Deployment 回滚历史。

# 检查Deployment修改历史
$ kubectl rollout history deployment/nginx-deployment --namespace test-hl
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=03-create-Deployment.yaml --record=true
2         kubectl apply --filename=03-create-Deployment.yaml --record=true

# 查看修改历史的详细信息
$ kubectl rollout history deployment/nginx-deployment --revision=2 --namespace test-hl

在这里插入图片描述

按照下面给出的步骤将 Deployment 从当前版本回滚到以前的版本,即版本 2。现在,Deployment 将回滚到以前的稳定版本。如所见,Deployment 回滚事件回滚到修改版 2 是从 Deployment 控制器生成的。

# 现在已决定撤消当前展开并回滚到以前的版本
$ kubectl rollout undo deployment/nginx-deployment
deployment/nginx-deployment

# 通过下面命令来回滚到特定修改版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=1 --namespace test-hl
deployment.apps/nginx-deployment rolled back

检查回滚是否成功或者 Deployment 是否正在运行,可以通过下面命令查看。

# 查看deployment状态
$ kubectl get deployment nginx-deployment --namespace test-hl
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           21m


# 获取Deployment描述信息
$ kubectl describe deployment nginx-deployment --namespace test-hl

示例运行 - 缩放

我们可以通过使用如下指令,缩放 Deployment。假设启用水平自动缩放 Pod 在集群中,可以为 Deployment 设置自动缩放器,并选择最小和最大 要基于现有 Pods 的 CPU 利用率运行的 Pods。

# 扩容(3->10)
$ kubectl scale deployment/nginx-deployment --replicas=10 --namespace test-hl

# 查看结果
$ kubectl get deployments.apps --namespace test-hl
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   10/10   10           10          23m

# 水平缩放
$ kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80

# 查看结果
$ kubectl get pod,hpa --namespace test-hl
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-7d4df5fd74-cs6cx   1/1     Running   0          31m
pod/nginx-deployment-7d4df5fd74-dfpb4   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-f9wgs   1/1     Running   0          31m
pod/nginx-deployment-7d4df5fd74-fqnjq   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-h67m2   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-jrfwd   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-kzlq5   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-m6lqc   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-nqlmn   1/1     Running   0          9m11s
pod/nginx-deployment-7d4df5fd74-wg927   1/1     Running   0          31m

NAME                                                   REFERENCE                     TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/nginx-deployment   Deployment/nginx-deployment   0%/80%    10        15        10         6m51s

五、DaemonSet

基本概念

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

一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个 DaemonSet。一个稍微复杂的用法是为同一种守护进程部署多个 DaemonSet;每个具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。下面是使用 DaemonSet 的一些典型用法:

  • 运行集群存储 daemon,例如在每个 Node 上运行

    glusterd、ceph

  • 在每个 Node 上运行日志收集 daemon

    fluentd、logstash

  • 在每个 Node 上运行监控 daemon

    Prometheus Node Exporter、collectd、Datadog

调度逻辑

仅在某些节点上运行 Pod:如果指定了 spec.template.spec.nodeSelector,DaemonSet Controller 将在能够与 Node Selector 匹配的节点上创建 Pod。类似这种情况,可以指定 spec.template.spec.affinity,然后 DaemonSet Controller 将在能够与 node Affinity 匹配的节点上创建 Pod。如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。

示例运行

每个 Node 节点都运行一个 nginx 服务。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: deamonset-example
  namespace: test-hl
  labels:
    app: daemonset-example
spec:
  selector:
    matchLabels:
      name: deamonset-example
  template:
    metadata:
      labels:
        name: deamonset-example
    spec:
      containers:
        - name: daemonset-example
          image: nginx:latest
          imagePullPolicy: IfNotPresent
          ports: 
          - containerPort: 88
          resources:
            limits:
              cpu: '1'
              memory: 1Gi
            requests:
              cpu: 200m
              memory: 512Mi
# 创建DaemonSet的Pod
kubectl apply -f 04-create-DaemonSet.yaml

# 查看服务状态
kubectl get daemonsets --namespace test-hl
kubectl get pods --namespace test-hl

每个 Node 节点都运行一个 fluentd 日志监控服务。

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:
      containers:
        - name: fluentd-elasticsearch
          image: fluent/fluentd:latest
          imagePullPolicy: IfNotPresent
          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: /development/hl/k8s-controller-test/DaemonSetLog/log
        - name: varlibdockercontainers
          hostPath:
            path: /development/hl/k8s-controller-test/DaemonSetLog/lib/docker/containers
# 创建DaemonSet的Pod
kubectl apply -f 05-create-DaemonSet-fluent.yaml

# 查看服务状态
kubectl get daemonsets.apps fluentd-elasticsearch --namespace test-hl

六、StatefulSet

StatefulSet 是用来管理有状态应用的工作负载 API 对象。

在 k8s 中,ReplicaSet 和 Deployment 主要是用于处理无状态的服务,无状态服务的需求往往非常简单并且轻量,每一个无状态节点存储的数据在重启之后就会被删除。但是如果我们需要保留,那该怎么办呢?所以为了满足有状态的服务这一特殊需求,StatefulSet 就是 Kubernetes 为了运行有状态服务引入的资源,例如 MySQL 等。

基本概念

产生 StatefulSet 的用途主要是用于管理有状态应用的工作负载对象,与 ReplicaSet 和 Deployment 这两个对象不同,StatefulSet 不仅能管理 Pod 的对象,还它能够保证这些 Pod 的顺序性和唯一性。以及,其会为每个 Pod 设置一个单独的持久标识 ID 号,这些用于标识序列的标识符在发生调度时也不会丢失,即无论怎么调度,每个 Pod 都有一个永久不变的 ID

功能特点

StatefulSets 最为重要的功能就是稳定,稳定意味着 Pod 调度或重调度的整个过程是有持久性的。如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment 或者 ReplicaSet 可能更适用于您的无状态应用部署需要。

  • 稳定的、唯一的网络标识符
  • 稳定的、持久的存储
  • 有序的、优雅的部署和缩放
  • 有序的、自动的滚动更新

需要额外注意的是,删除或者收缩 StatefulSet 并不会删除它关联的存储卷,这样做是为了保证数据安全。而且,StatefulSet 当前需要无头服务来负责 Pod 的网络标识,所以需要事先创建好。

  • 访问方式

我们在下面的示例中是使用 StatefulSet 和对应的无头服务来做演示的,当 StatefulSet Pod 创建之后其具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。该标识和 Pod 是绑定的,不管它被调度在哪个节点上。

  • 有序索引

对于具有 N 个副本的 StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在 StatefulSet 上是唯一的。

  • 稳定的网络 ID

在 StatefulSet 中的每个 Pod 根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。组合主机名的格式为名称(序号)。上例将会创建三个名称分别为 web-0、web-1、web-2 的 Pod。StatefulSet 可以使用 headless 服务 控制它的 Pod 的网络域。管理域的这个服务的格式为:服务名称(命名空间).svc.cluster.local,其中 cluster.local 是集群域。一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为:名称(所属服务的 DNS 域名),其中所属服务由 StatefulSet 的 serviceName 域来设定。

  • 稳定的存储

在 Kubernetes 中 StatefulSet 模式会为每个 VolumeClaimTemplate 创建一个 PersistentVolumes。请注意,当 Pod 或者 StatefulSet 被删除时,与 PersistentVolumeClaims 相关联的 PersistentVolume 并不会被删除。要删除它必须通过手动方式来完成。

  • 管理策略

对于某些分布式系统来说,StatefulSet 的顺序性保证是不必要和/或者不应该的。这些系统仅仅要求唯一性和身份标志。为了解决这个问题,在 Kubernetes 1.7 中引入了 spec.podManagementPolicy

OrderedReady 的 Pod 管理策略:是 StatefulSets 的默认选项,它告诉 StatefulSet 控制器遵循上文展示的顺序性保证。

Parallel 的 Pod 管理策略:是告诉 StatefulSet 控制器并行的终止所有 Pod,在启动或终止另一个 Pod 前,不必等待这些 Pod 变成 Running 和 Ready 或者完全终止状态。

示例运行

名为 nginx 的 Headless Service 用来控制网络域名。

名为 web 的 StatefulSet 有一个 Spec,它表明将在独立的 2 个 Pod 副本中启动 nginx 容器。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: test-hl
  labels:
    app: nginx
spec:
  ports:
    - port: 80
      name: web
  clusterIP: None
  selector:
    app: nginx

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
  namespace: test-hl
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          imagePullPolicy: IfNotPresent 
          ports:
          - containerPort: 80
            name: web
          volumeMounts:
          - name: www
            mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: www
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi
创建和查看 - StatefulSet
# 创建定义在web.yaml中的Headless Service和StatefulSet
$ sudo kubectl apply -f web.yaml

# 验证是否成功创建
$ sudo kubectl get service nginx --namespace test-hl
NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   None         <none>        80/TCP    3m15s


$ sudo kubectl get statefulset web --namespace test-hl
NAME   READY   AGE
web    2/2     3m28s
查看绑定的特点 - StatefulSet
# 使用稳定的网络身份标识
$ sudo kubectl exec web-0 -- bash -c \
    "for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done"
web-0

$ sudo kubectl exec web-1 -- bash -c \
    "for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done"
web-1
# 稳定的网络身份标识
$ sudo kubectl run -i --tty --image busybox:1.28 \
    dns-test --restart=Never --rm nslookup web-0.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.6

nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.6
# 写入稳定的存储
$ sudo kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO    

删除 StatefulSet 中所有的 Pod 之后,我们使用上述查看网络身份标识的命令再次查看,发现 Pod 的序号、主机名、SRV 条目和记录名称没有改变,但和 Pod 相关联的 IP 地址可能发生了改变。因为我们使用的是 StatefulSet 的模式,其他模式不会有这个问题。这就是为什么不要在其他应用中使用 StatefulSet 中的 Pod 的 IP 地址进行连接,这点很重要。

$ sudo kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

# 对应的服务访问地址,我们可以间接访问
web-0.nginx.default.svc.cluster.local
web-1.nginx.default.svc.cluster.local
扩容/缩容 - StatefulSet
# 扩容
$ sudo kubectl scale sts web --replicas=5
statefulset.apps/web scaled

# 缩容
$ sudo kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched
 五个存储仍然存在
$ sudo kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-2   Bound     pvc-e1125b27-b508-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-3   Bound     pvc-e1176df6-b508-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-4   Bound     pvc-e11bb5f8-b508-11e6-932f-42010a800002   1Gi        RWO   
更新 - StatefulSet

StatefulSet 里的 Pod 采用和序号相反的顺序更新。在更新下一个 Pod 前,StatefulSet 控制器终止每个 Pod 并等待它们变成 Running 和 Ready。请注意,虽然在顺序后继者变成 unning 和 Ready 之前 StatefulSet 控制器不会更新下一个 Pod,但它仍然会重建任何在更新过程中发生故障的 Pod,使用的是它们当前的版本。已经接收到更新请求的 Pod 将会被恢复为更新的版本,没有收到请求的 Pod 则会被恢复为之前的版本。像这样,控制器尝试继续使应用保持健康并在出现间歇性故障时保持更新的一致性。

# Patch web StatefulSet 来执行 RollingUpdate 更新策略
$ sudo kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched

# 在一个终端窗口中 patch web StatefulSet 来再次的改变容器镜像
$ sudo kubectl patch statefulset web --type='json' \
    -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", \
    "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
statefulset.apps/web patched
删除 - StatefulSet
# 删除StatefulSet
kubectl delete statefulset web
statefulset.apps "web" deleted

# 删除Pod
kubectl delete pod web-0
pod "web-0" deleted
StatefulSet和Deployment的区别

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

综上选择总结

  • 如果是不需额外数据依赖或者状态维护的部署,或者 replicas 是 1,优先考虑使用 Deployment;
  • 如果单纯的要做数据持久化,防止 pod 宕掉重启数据丢失,那么使用 pv/pvc 就可以了;
  • 如果要打通 app 之间的通信,而又不需要对外暴露,使用 headlessService 即可;
  • 如果需要使用 service 的负载均衡,不要使用 StatefulSet,尽量使用 clusterIP 类型,用 serviceName 做转发;
  • 如果是有多 replicas,且需要挂载多个 pv 且每个 pv 的数据是不同的,因为 pod 和 pv 之间是一一对应的,如果某个 pod 挂掉再重启,还需要连接之前的 pv,不能连到别的 pv 上,考虑使用 StatefulSet;
  • 能不用 StatefulSet,就不要用;

七、Job/CronJob

基本概念

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

Cron Job 管理基于时间的 Job,即在给定时间点只运行一次或周期性地在给定时间点运行。

执行特点

Job 会创建一个或者多个 Pods,并确保指定数量的 Pods 成功终止。随着 Pods 成功结束,Job 跟踪记录成功完成的 Pods 个数。当数量达到指定的成功个数阈值时,任务结束。删除 Job 的操作会清除所创建的全部 Pods。当第一个 Pod 失败或者被删除(比如因为节点硬件失效或者重启)时,Job 对象会启动一个新的 Pod。

CronJob 对于创建周期性的、反复重复的任务很有用,例如执行数据备份或者发送邮件。CronJobs 也可以用来计划在指定时间来执行的独立任务,例如计划当集群看起来很空闲时 执行某个 Job。

  • Job 的并行执行

    • 不设置 .spec.completions,默认值为 .spec.parallelism
    • 多个 Pod 之间必须相互协调,或者借助外部服务确定每个 Pod 要处理哪个工作条目
    • 每个 Pod 都可以独立确定是否其它 Pod 都已完成,进而确定 Job 是否完成
    • 一旦至少 1 个 Pod 成功完成,并且所有 Pod 都已终止,即可宣告 Job 成功完成
    • .spec.completions 字段设置为非 0 的正数值
    • 当 .spec.completions 等于 1 时一个成功的 Pod 就被视为完成
    • 通常只启动一个 Pod,除非该 Pod 失败
    • 当 Pod 成功终止时,立即视 Job 为完成状态
    • 非并行 Job
    • 具有确定完成计数的并行 Job
    • 带工作队列的并行 Job

示例运行

Job

spec.completions标志 Job 结束需要成功运行的 Pod 个数,默认为 1

spec.parallelism标志并行运行的 Pod 的个数,默认为 1

spec.activeDeadlineSeconds 标志失败 Pod 的重试最大时间,超过这个时间不会继续重试

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  restartPolicy: OnFailure
  backoffLimit: 5 # timeout
  activeDeadlineSeconds: 100 # timeout
  ttlSecondsAfterFinished: 100 # ttl
  template:
    spec:
      containers:
        - name: pi
          image: perl
          command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4
# 使用下面的命令来运行此示例
$ sduo kubectl apply -f job.yaml
job.batch/pi created

# 来检查Job的状态
$ sudo kubectl describe jobs/pi

# 查看Job对应的已完成的Pods
$ sudo kubectl get pods

# 查看PI输出结果
$ pods=$(suod kubectl get pods --selector=job-name=pi --output=jsonpath={.items..metadata.name})
$ sduo kubectl logs $pods
3.141592653589793238462......
CronJob
  • spec.schedule:指定任务运行周期(调度)
  • spec.jobTemplate:指定需要运行的任务(Job 模板)
  • spec.startingDeadlineSeconds:启动 Job 的期限(秒级别)
  • spec.concurrencyPolicy:并发策略(Allow/Forbid/Replace)
  • spec.suspend:挂起
  • spec.successfulJobsHistoryLimit:指定了可以保留多少完成的 Job(历史限制;默认 3)
  • spec.failedJobsHistoryLimit:指定了可以保留多少失败的 Job(历史限制;默认 1)
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox
              args:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
# 创建
$ sudo kubectl create -f cronjob.yaml
cronjob "hello" created

# 查看
$ sudo kubectl get jobs
NAME               DESIRED   SUCCESSFUL   AGE
hello-1202039034   1         1            49s

# 查看
$ sudo kubectl get cronjob
NAME      SCHEDULE      SUSPEND   ACTIVE    LAST-SCHEDULE
hello     */1 * * * *   False     0         <none>

# 输出
$ pods=$(sudo kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath={.items..metadata.name})
$ sudo kubectl logs $pods
Mon Aug 29 21:34:09 UTC 2020
Hello from the Kubernetes cluster

# 删除
$ sudo kubectl delete cronjob hello
cronjob "hello" deleted

一旦不再需要 Cron Job,简单地可以使用 kubectl 命令删除它。这将会终止正在创建的 Job。然而,运行中的 Job 将不会被终止,不会删除 Job 或它们的 Pod。为了清理那些 Job 和 Pod,需要列出该 Cron Job 创建的全部 Job,然后删除它们。

# 逐个删除
$ kubectl get jobs
NAME               DESIRED   SUCCESSFUL   AGE
hello-1201907962   1         1            11m
hello-1202039034   1         1            8m
...

$ kubectl delete jobs hello-1201907962 hello-1202039034 ...
job "hello-1201907962" deleted
job "hello-1202039034" deleted
...

# 强制删除
$ sudo kubectl delete jobs --all
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值