{"msg":"操作成功","code":200,"data":{"createBy":"admin","createTime":"2021-07-28 17:47:28","updateBy":"admin","updateTime":"2021-07-28 17:47:28","remark":null,"id":67,"articleTitle":"Kubernetes（五）Pod控制器","articleUrl":"k8s_controller","articleThumbnail":"https://www.asumimoe.com/imgfiles/20220906/f93daad129a04b8db74eed70cd45263b.png","articleFlag":"0","draftStatus":"1","reprintStatement":"1","articleSummary":"Kubernetes 中我们一般不直接创建 Pod， 而是通过 Controller（控制器）来管理 Pod。","articleContent":"## Kubernetes中的控制器介绍\n\nPod（容器组）是 Kubernetes 中最小的调度单元，可以通过 yaml 定义文件直接创建一个 Pod。但 Pod 本身并不具备自我恢复（self-healing）功能。如果一个 Pod 所在的节点出现故障，或者调度程序自身出现问题，以及节点资源不够或节点进入维护而驱逐 Pod 时，Pod 将被删除，且不能自我恢复。\n\n因此，Kubernetes 中我们一般不直接创建 Pod， 而是通过 Controller（控制器）来管理 Pod。\n\n### Controller\n\nController 能为 Pod 提供如下特性：\n\n- 水平扩展，控制 Pod 运行的副本数。\n- rollout，即版本更新。\n- self-healing，即自我恢复。当节点出现故障时，控制器可以自动地在另一个节点调度一个配置完全一样的 Pod，以替换故障节点上的 Pod。\n\nKubernetes 中支持的控制器包括：\n\n- ReplicationController：用来维护一个数量稳定的 Pod 副本集合的控制器。\n- ReplicaSet：是 ReplicationController 的升级版，比 ReplicationController 多一个特性：支持基于集合的选择器。 不支持滚动更新（RollingUpdate）。\n- Deployment：包含了 ReplicaSet，可通过声明式、滚动更新的方式更新 ReplicaSet 及其 Pod。对于无状态应用，推荐使用 Deployment 部署。\n- StatefulSet：用于管理有状态的应用程序。\n- DaemonSet：在节点上以守护进程的方式运行一个指定的 Pod 副本，例如监控节点、收集节点上的日志时，可使用 DaemonSet。\n- CronJob：按照预定的时间计划创建 Job，类似于 linux 的crontab。\n- Job：使用 Job 执行任务，执行完后结束。\n\n### ReplicaSet\n\nKubernetes 中，虽然一般使用 Deployment 来管理 Pod， 但 Deployment 中也是通过 ReplicaSet 来维护 Pod 的副本集合的，因此此处也对 ReplicaSet 进行简单介绍。\n\n在 ReplicaSet 的定义中，包含三部分：\n\n- selector： 标签选择器，用于指定哪些 Pod 归该 ReplicaSet 管理，通过 matchLabels 来与 Pod 的 label 匹配。\n- replicas： 期望的 Pod 副本数，指定该 ReplicaSet 应该维持多少个 Pod 副本，默认为1。\n- template： Pod 定义模板，ReplicaSet 使用该模板的定义来创建 Pod。\n\nReplicaSet 的示例定义文档如下所示，\n\n```yaml\napiVersion: apps/v1\nkind: ReplicaSet\nmetadata:\n  name: nginx\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n```\n\n\n\nReplicaSet 通过创建、删除 Pod 容器组来确保符合 selector 选择器的 Pod 数量等于 replicas 指定的数量。 ReplicaSet 创建的 Pod 中，都有一个字段 metadata.ownerReferences 用于标识该 Pod 从属于哪一个 ReplicaSet。可通过 kubectl get pod pod-name -o yaml 来查看 Pod 的 ownerReference。\n\nReplicaSet 通过 selector 字段的定义，识别哪些 Pod 应该由其管理， 不论该 Pod 是否由该 ReplicaSet 创建，即只要 selector 匹配， 通过外部定义创建的 Pod 也会被该 ReplicaSet 管理。因此需要注意 .spec.selector.matchLabels 与 .spec.template.metadata.labels 的定义一致， 且避免与其他控制器的 selector 重合，造成混乱。\n\nReplicaSet 不支持滚动更新，所以对于无状态应用，一般使用 Deployment来部署， 而不直接使用 ReplicaSet。ReplicaSet 主要是被用作 Deployment 中负责 Pod 创建、删除、更新的一种手段。\n\n### Deployment\n\nDeployment 对象包含 ReplicaSet 作为从属对象，并且可通过声明式、滚动更新的方式来更新 ReplicaSet 及其 Pod。ReplicaSet 现在主要是被用作 Deployment 中负责 Pod 创建、删除、更新的一种手段。使用 Deployment 时，无需关心由 Deployment 创建的 ReplicaSet，Deployment 将处理所有与之相关的细节。同时，Deployment 还能以“声明式”的方式管理 Pod 和 ReplicaSet （其本质是将一些特定场景的一系列运维步骤固化下来，以便快速准确无误的执行），并提供版本（revision）回退功能。\n\n## Deployment功能\n\n### 1.多副本\n\n```shell\nkubectl create deploy mynginx --image=nginx --replicas=3\n```\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: mynginx\nspec:\n  replicas: 3 # 定义三个副本\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n```\n\n### 2.扩缩容\n\n当目前的容器数量不足以支撑当前业务的并发量时，可以使用扩容的方式临时增加Pod的副本数量。当业务并发高峰期过去之后，可以减少Pod的副本数量，来减少资源的使用。\n\n```shell\nkubectl scale deployment mynginx --replicas=5 # 将副本数从3变成5\n```\n\n```shell\nkubectl edit deploy mynginx #以yaml文件方式打开\n将replicas: 5改为replicas: 3保存退出\n```\n\nKubernetes还支持自动扩缩容，为Deployment设置自动扩展。\n\n```shell\n# 设置自动扩展的最小副本数及最大副本数,CPU使用率达到80%就自动扩展\nkubectl autoscale deployment mynginx --min=10 --max=15 --cpu-percent=80\n```\n\n```yaml\napiVersion: autoscaling/v1\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: iot-server\nspec:\n  minReplicas: 1                   #最小pod数量\n  maxReplicas: 10                    #最大pod数量\n  scaleTargetRef:\n    apiVersion: v1\n    kind: Deployment          #需要扩容的对象类型\n    name: iot-server            #需要扩容的对象名称\n  targetCPUUtilizationPercentage: 90   #CPU平均使用率超过90%扩容\n```\n\n### 3.滚动更新\n\n当且仅当 Deployment 的 Pod template（.spec.template）字段中的内容发生变更时（例如标签或容器的镜像被改变），Deployment 的发布更新（rollout）才会被触发。Deployment 中其他字段的变化（例如修改 .spec.replicas 字段）将不会触发 Deployment 的发布更新。\n\n更新 Deployment 中 Pod 的定义（例如，发布新版本的容器镜像）。此时 Deployment 控制器将为该 Deployment 创建一个新的 ReplicaSet，并且逐步在新的 ReplicaSet 中创建 Pod，在旧的 ReplicaSet 中删除 Pod，以达到滚动更新的效果。\n\nk8s分批次有序地进行着滚动更新，直到把所有旧的副本全部更新到新版本。实际上，k8s是通过两个参数来精确地控制着每次滚动的pod数量：\n\n- maxSurge 滚动更新过程中运行操作期望副本数的最大pod数，但不能为0；也可以为百分数(eg：10%)。默认为25%。\n- maxUnavailable 滚动更新过程中不可用的最大pod数，但不能为0；也可以为百分数(eg：10%)。默认为25%。\n\n### 重要参数 maxSurge与maxUnavailable\n\n- maxSurge: 1 表示滚动升级时会先启动1个pod\n- maxUnavailable: 1 表示滚动升级时允许的最大Unavailable的pod个数\n- 由于replicas为3,则整个升级,pod个数在2-4个之间\n\n```shell\nkubectl set image deployment mynginx nginx=nginx:1.16.1 --record\nkubectl edit deploy mynginx\n# 两种方式均可\n```\n\n### 4.版本回退\n\n```shell\n# 查看历史版本\nkubectl rollout history deploy mynginx\n# 回滚到上一个版本\nkubectl rollout undo deploy mynginx\n# 查看rollout的状态\nkubectl rollout status deploy mynginx\n# 查看单个版本的详细信息\nkubectl rollout history deploy mynginx --revision=2\n# 回滚到指定版本\nkubectl rollout undo deploy mynginx --to-revision=1\n```\n\n## StatefulSet\n\n### 1.介绍\n\nRC、Deployment、DaemonSet都是面向无状态的服务，它们所管理的Pod的IP、名字，启停顺序等都是随机的，而StatefulSet是什么？顾名思义，有状态的集合，管理所有有状态的服务，比如MySQL、MongoDB集群等。\nStatefulSet本质上是Deployment的一种变体，在v1.9版本中已成为GA版本，它为了解决有状态服务的问题，它所管理的Pod拥有固定的Pod名称，启停顺序，在StatefulSet中，Pod名字称为网络标识(hostname)，还必须要用到共享存储。\n在Deployment中，与之对应的服务是service，而在StatefulSet中与之对应的headless service，headless service，即无头服务，与service的区别就是它没有Cluster IP，解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。\n除此之外，StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名，这个域名的格式为：\n\n```css\n$(podname).(headless server name)\nFQDN：$(podname).(headless server name).namespace.svc.cluster.local\n```\n\n### 2.特点\n\nPod一致性：包含次序（启动、停止次序）、网络一致性。此一致性与Pod相关，与被调度到哪个node节点无关；\n稳定的次序：对于N个副本的StatefulSet，每个Pod都在[0，N)的范围内分配一个数字序号，且是唯一的；\n稳定的网络：Pod的hostname模式为(statefulset名称)−(序号)；\n稳定的存储：通过VolumeClaimTemplate为每个Pod创建一个PV。删除、减少副本，不会删除相关的卷。\n\n### 3.组成部分\n\nHeadless Service：用来定义Pod网络标识( DNS domain)；\n\n在用Deployment时，每一个Pod名称是没有顺序的，是随机字符串，因此是Pod名称是无序的，但是在statefulset中要求必须是有序 ，每一个pod不能被随意取代，pod重建后pod名称还是一样的。而pod IP是变化的，所以是以Pod名称来识别。pod名称是pod唯一性的标识符，必须持久稳定有效。这时候要用到无头服务，它可以给每个Pod一个唯一的名称 。\n\nvolumeClaimTemplates ：存储卷申请模板，创建PVC，指定pvc名称大小，将自动创建pvc，且pvc必须由存储类供应；\n\n对于有状态的副本集都会用到持久存储，对于分布式系统来讲，它的最大特点是数据是不一样的，所以各个节点不能使用同一存储卷，每个节点有自已的专用存储，但是如果在Deployment中的Pod template里定义的存储卷，是所有副本集共用一个存储卷，数据是相同的，因为是基于模板来的 ，而statefulset中每个Pod都要自已的专有存储卷，所以statefulset的存储卷就不能再用Pod模板来创建了，于是statefulSet使用volumeClaimTemplate，称为卷申请模板，它会为每个Pod生成不同的pvc，并绑定pv，从而实现各pod有专用存储。这就是为什么要用volumeClaimTemplate的原因。\n\nStatefulSet ：定义具体应用，名为redis，有6个Pod副本，并为每个Pod定义了一个域名部署statefulset。\n\n## DaemonSet\n\nDaemonSet 确保全部（或者一些）Node 上运行一个 Pod 的副本。当有 Node加入集群时，也会为他们新增一个 Pod 。当有 Node 从集群移除时，这些 Pod也会被回收。删除 DaemonSet将会删除它创建的所有 Pod。DaemonSet在v1.6+之后也支持滚动更新，用法与Deployment相同。\n使用 DaemonSet 的一些典型用法：\n\n- 运行集群存储 daemon，例如在每个 Node 上运行 glusterd 、 ceph；\n- 在每个 Node 上运行日志收集 daemon，例如 fluentd 、 logstash；\n- 在每个 Node 上运行监控 daemon，例如 Prometheus Node Exporter、 collectd 、Datadog 代理、New Relic 代理，或 Ganglia gmond。\n\n```yaml\nvim daemonset.yaml \napiVersion: apps/v1\nkind: DaemonSet\nmetadata: \n  name: nginx-ds\nspec:\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx \n        image: nginx:1.14\n        imagePullPolicy: IfNotPresent\n        ports:\n        - name: http\n          containerPort: 80\n```\n\n## Job与Cronjob\n\n我们在工作中会遇到需要批量处理数据和分析的需求，也会有按时间来进行调度的工作，在k8s集群中，有Job和cronJob两中资源对象来映带我们的这种需要。\n\nJob负责处理任务，仅执行一次的任务，他保证批处理任务的一个或多个pod成功结束。而cronJob则就是在job上加上了时间调度，相当于定时任务。\n\n### Job批处理任务\n\n```yaml\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: job\nspec:\n  template:\n  backoffLimit: 6 # 默认重试6次后才认为执行失败\n  activeDeadlineSeconds: 100 # 重试工作的持续时间，优先级别高于backoffLimit\n    spec:\n      containers:\n      - name: job\n        image: busybox\n        command: [\"echo\",\"Hello World\"]\n        imagePullPolicy: IfNotPresent\n      restartPolicy: Never # 只有两种重启策略，Never、OnFailure不支持Always,失败状态会陷入失败死循环\n```\n\nJob有三种运行模式\n\n1. Non-parallel Jobs\n\n   通常一个Job只启动一个Pod，除非Pod异常才会重启该Pod。一旦此Pod正常结束，则Job结束。\n\n2. 固定parallel(并行)Jobs一个完成次数\n\n   .spec.completion指定一个非零的正值，当正常结束的Pod数量达到此值时Job结束。\n\n3. 具有工作队列的parallel(并行)Jobs\n\n   - 不指定 .spec.completions ,默认为 .spec.parallelism\n\n   - pod必须在彼此之间或外部服务之间进行协调，以确定每个pod应该如何处理。例如一个pod可以从工作队列中最多获取N批的批处理\n   - 每个pod都可以独立地确定其所有对等方是否都已完成，从而确定整个pod状态\n   - 当jobs中任何pod成功终止时，不会创建新的pod\n   - 所有pod成功终止，则job完成\n\n### cronJob定时任务\n\nCronJob其实就是在Job的基础上加上了时间调度，我们可以：在给定的时间点运行一个任务，也可以周期性地在给定时间点运行。这个实际上和我们Linux中的crontab就非常类似了。格式和crontab也是一样的。\n\n```yaml\napiVersion: batch/v1beta1\nkind: CronJob\nmetadata:\n  name: cj\nspec:\n  schedule: \"*/2 * * * *\"\n  jobTemplate:\n    metadata:\n      name: job\n    spec:\n      template:\n        metadata:\n          name: pod\n        spec:\n          containers:\n          - name: busybox\n            image: busybox\n            command: [\"echo\",\"hello\"]\n            imagePullPolicy: IfNotPresent\n          restartPolicy: OnFailure\n```","categoryId":10,"viewCount":1132,"categoryName":"Kubernetes","author":"球接子","authorAvatar":null,"tagIds":[16],"tagNames":["Kubernetes"]}}