k8s 中 Pod 的控制器

前言

Pod 是 Kubernetes 集群中能够被创建和管理的最小部署单元。所以需要有工具去操作和管理它们的生命周期,这里就需要用到控制器了。

Pod 控制器由 master 的 kube-controller-manager 组件提供,常见的此类控制器有 Replication Controller、ReplicaSet、Deployment、DaemonSet、StatefulSet、Job 和 CronJob 等,它们分别以不同的方式管理 Pod 资源对象。

Replication Controller

RC 是 k8s 集群中最早的保证 Pod 高可用的 API 对象。它的作用就是保证集群中有指定数目的 pod 运行。

当前运行的 pod 数目少于指定的数目,RC 就会启动新的 pod 副本,保证运行 pod 数量等于指定数目。

当前运行的 pod 数目大于指定的数目,RC 就会杀死多余的 pod 副本。

直接上栗子

cat <<EOF >./pod-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
EOF

在新版的 Kubernetes 中建议使用 ReplicaSet (RS)来取代 ReplicationController。

ReplicaSet 跟 ReplicationController 没有本质的不同,只是名字不一样,但 ReplicaSet 支持集合式 selector。

关于 ReplicationController 这里也不展开讨论了,主要看下 ReplicaSet。

ReplicaSet

RS 是新一代 RC,提供同样的高可用能力,区别主要在于 RS 后来居上,能支持支持集合式 selector。

副本集对象一般不单独使用,而是作为 Deployment 的理想状态参数使用。

下面看下 Deployment 中是如何使用 ReplicaSet 的。

Deployment

一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力,每一个 Deployment 都对应集群中的一次部署。

一般使用 Deployment 来管理 RS,可以用来创建一个新的服务,更新一个新的服务,也可以用来滚动升级一个服务。

滚动升级一个服务,滚动升级一个服务,实际是创建一个新的 RS,然后逐渐将新 RS 中副本数增加到理想状态,将旧 RS 中的副本数减小到 0 的复合操作;这样一个复合操作用一个 RS 是不太好描述的,所以用一个更通用的 Deployment 来描述。

举个栗子

cat <<EOF >./nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels: # 这里定义需要管理的 pod,通过 Pod 的标签进行匹配
app: nginx
template:
metadata:
labels: # 运行的 pod 的标签
app: nginx
spec:
containers: # pod 中运行的容器
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
EOF

部署

$ kubectl apply -f nginx-deployment.yaml -n study-k8s
deployment.apps/nginx-deployment created $ study-k8s kubectl describe deployment nginx-deployment -n study-k8s
Name: nginx-deployment
Namespace: study-k8s
CreationTimestamp: Mon, 26 Sep 2022 09:06:16 +0800
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 1 available | 2 unavailable
StrategyType: RollingUpdate # 默认是滚动更新
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge # 滚动更新的策略,最大 25% 不可用,最大 25% 增加
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.14.2
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing True ReplicaSetUpdated
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-66b6c48dd5 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 3s deployment-controller Scaled up replica set nginx-deployment-66b6c48dd5 to 3

可以看到 Deployment 中默认的更新方式滚动更新,并且默认的滚动更新的策略是 最大 25% 不可用,最大 25% 增加。

更新 Deployment

1、直接更新

$ kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.20.1 -n study-k8s

# 或者  

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.20.1 -n study-k8s

2、对 Deployment 执行 edit 操作

$ kubectl get deployment -n study-k8s
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18m $ kubectl edit deployment -n study-k8s
# 修改对应的镜像版本,保存即可 spec:
containers:
- image: nginx:1.20.3
imagePullPolicy: IfNotPresent
name: nginx

3、直接编辑部署的 YAML 文件,然后重新 Apply

$ kubectl apply -f nginx-deployment.yaml -n study-k8s
deployment.apps/nginx-deployment configured $ kubectl get pods -n study-k8s
NAME READY STATUS RESTARTS AGE
nginx-deployment-6bcf8f4884-dxxxg 1/1 Running 0 38s
nginx-deployment-6bcf8f4884-plbkh 0/1 ContainerCreating 0 13s
nginx-deployment-cc4b758d6-lzlxl 1/1 Running 0 7m25s
nginx-deployment-cc4b758d6-r5rkb 1/1 Running 0 7m11s

回滚 deployment

了解了如何更新 deployment,那么当部署出现问题,如果回滚呢,下面来详细介绍下

查看之前部署的版本

$ kubectl rollout history deployment/nginx-deployment -n study-k8s
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
4 <none>
5 <none>
6 <none>
7 image updated to 1.21.1

REVISION:就是之前部署的版本信息;

CHANGE-CAUSE:变动的备注信息。

$ kubectl apply -f nginx-deployment.yaml -n study-k8s --record

加上 --record,或者每次部署完之后,使用

$ kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="image updated to 1.21.1" -n study-k8s

CHANGE-CAUSE 信息就会被记录

查看历史版本的详细详细

$ kubectl rollout history deployment/nginx-deployment --revision=6 -n study-k8s
deployment.apps/nginx-deployment with revision #6
Pod Template:
Labels: app=nginx
pod-template-hash=d985dd8bf
Containers:
nginx:
Image: nginx:1.20.3
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>

回滚

# 回滚到上一个版本
$ kubectl rollout undo deployment/nginx-deployment -n study-k8s # 回滚到指定的版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=5 -n study-k8s

缩放 Deployment

$ kubectl scale deployment/nginx-deployment --replicas=10 -n study-k8s

$  kubectl get pods -n study-k8s
NAME READY STATUS RESTARTS AGE
nginx-deployment-66b6c48dd5-5scbj 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-7nmtp 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-f5xsg 1/1 Running 0 12m
nginx-deployment-66b6c48dd5-fnpnb 1/1 Running 0 12m
nginx-deployment-66b6c48dd5-gg4ng 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-qd5z7 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-qqh4m 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-xww49 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-zndlh 1/1 Running 0 44s
nginx-deployment-66b6c48dd5-zp45g 1/1 Running 0 12m

关于使用 deployment 实现 k8s 中的几种部署策略,可参见Kubernetes 部署策略详解

StatefulSet

StatefulSet 用来管理有状态的应用。

在 Pods 管理的基础上,保证 Pods 的顺序和一致性。与 Deployment一样,StatefulSet 也是使用容器的 Spec 来创建Pod,与之不同 StatefulSet 创建的 Pods 在生命周期中会保持持久的标记(例如Pod Name)。

StatefulSet 适用于具有以下特点的应用:

1、稳定的、唯一的网络标识符;

2、稳定的、持久的存储;

3、有序的、优雅的部署和扩缩;

4、有序的、自动的滚动更新。

那么什么是有状态服务什么是无状态服务呢?

无状态服务

无状态服务不会在本地存储持久化数据。多个服务实例对于同一个用户请求的响应结果是完全一致的。这种多服务实例之间是没有依赖关系,比如web应用,在k8s控制器 中动态启停无状态服务的pod并不会对其它的pod产生影响。

有状态服务

有状态服务需要在本地存储持久化数据,典型的是分布式数据库的应用,分布式节点实例之间有依赖的拓扑关系。

比如,主从关系。 如果 K8S 停止分布式集群中任 一实例 pod,就可能会导致数据丢失或者集群的 crash。

来个栗子

cat <<EOF >./pod-statefulSet.yaml

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 # 必须匹配 .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # 默认值是 1
template:
metadata:
labels:
app: nginx # 必须匹配 .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
EOF

DaemonSet

DaemonSet:主要是用来保证集群中的每个节点只运行一个 Pod,且保证只有一个 Pod,这非常适合一些系统层面的应用,例如日志收集、资源监控等,这类应用需要每个节点都运行,且不需要太多实例,一个比较好的例子就是 Kubernetes 的 kube-proxy。

当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。

DaemonSet 的应用场景:

1、在每个节点上运行集群守护进程;

2、在每个节点上运行日志收集守护进程;

3、在每个节点上运行监控守护进程。

来个栗子

cat <<EOF >./nginx-daemonset.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-daemonset
labels:
app: nginx-daemonset
spec:
selector:
matchLabels:
app: nginx-daemonset
template:
metadata:
labels:
app: nginx-daemonset
spec:
containers:
- name: nginx-daemonset
image: nginx:alpine
resources:
limits:
cpu: 250m
memory: 512Mi
requests:
cpu: 250m
memory: 512Mi
imagePullSecrets:
- name: default-secret
EOF

这样就能在每个节点中部署一个 Pod 了,不过 DaemonSet 也支持通过 label 来选择部署的目标节点

cat <<EOF >./nginx-daemonset.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-daemonset
labels:
app: nginx-daemonset
spec:
selector:
matchLabels:
app: nginx-daemonset
template:
metadata:
labels:
app: nginx-daemonset
spec:
nodeSelector: # 节点选择,当节点拥有nodeName=node7时才在节点上创建Pod
nodeName: node7
containers:
- name: nginx-daemonset
image: nginx:alpine
resources:
limits:
cpu: 250m
memory: 512Mi
requests:
cpu: 250m
memory: 512Mi
imagePullSecrets:
- name: default-secret
EOF

Job 和 CronJob

Job 和 CronJob 是负责处理定时任务的。

两者的区别主要在于:

Job 负责处理一次性的定时任务,即仅需执行一次的任务;

CronJob 是基于时间的 Job,就类似于 Linux 系统的 crontab 文件中的一行,在指定的时间周期运行指定的 Job。

首先来创建一个 Job

cat <<EOF >./job-demo.yaml

apiVersion: batch/v1
kind: Job
metadata:
name: job-demo
spec:
template:
metadata:
name: job-demo
spec:
restartPolicy: Never
containers:
- name: counter
image: busybox
command:
- "bin/sh"
- "-c"
- "echo hello"
EOF

运行

$ kubectl apply -f job-demo.yaml

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
job-demo-8qrd9 0/1 Completed 0 40s
$ study-k8s kubectl get job
NAME COMPLETIONS DURATION AGE
job-demo 1/1 36s 45s
$ kubectl logs -f job-demo-8qrd9
hello

再来看下 CronJob

cat <<EOF >./cronJob-demo.yaml

apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello
restartPolicy: OnFailure
EOF

通过 kubectl get jobs --watch 就能查看 CronJob 的调度

$ kubectl get jobs --watch
NAME COMPLETIONS DURATION AGE
hello-1664449860 1/1 2s 4s
hello-1664449920 0/1 0s
hello-1664449920 0/1 0s 0s
hello-1664449920 1/1 2s 2s

总结

关于 pod 中的几个控制器最常用的就是 Deployment 和 ReplicaSet;

使用 Deployment 来管理 RS,来实现服务的部署,更新和滚动升级;

StatefulSet 主要用来管理无状态应用;

DaemonSet:主要是用来保证集群中的每个节点只运行一个 Pod,且保证只有一个 Pod,这非常适合一些系统层面的应用,例如日志收集、资源监控等,这类应用需要每个节点都运行,且不需要太多实例,一个比较好的例子就是 Kubernetes 的 kube-proxy;

Job 和 CronJob 是负责处理定时任务的;

Job 负责处理一次性的定时任务,即仅需执行一次的任务;

CronJob 是基于时间的 Job,就类似于 Linux 系统的 crontab 文件中的一行,在指定的时间周期运行指定的 Job。

参考

【Deployments】https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/

【Kubernetes 部署策略详解】https://www.qikqiak.com/post/k8s-deployment-strategies/

【StatefulSet 和 Deployment 区别及选择方式】https://blog.csdn.net/nickDaDa/article/details/90401635

【K8S: 有状态 vs 无状态服务】https://zhuanlan.zhihu.com/p/390440336

【StatefulSet】https://support.huaweicloud.com/basics-cce/kubernetes_0015.html

【k8s 中 Pod 的控制器】https://boilingfrog.github.io/2022/09/30/k8s中Pod控制器/

k8s 中 Pod 的控制器的更多相关文章

  1. K8s中Pod健康检查源代码分析

    了解k8s中的Liveness和Readiness Liveness: 表明是否容器正在运行.如果liveness探测为fail,则kubelet会kill掉容器,并且会触发restart设置的策略. ...

  2. k8s中pod内dns无法解析的问题

    用k8s创建了pod,然后进入pod后,发现在pod中无法解析www.baidu.com,也就是出现了无法解析外面的域名的问题.经过高人指点,做个小总结.操作如下. 一,将CoreDNS 的Confi ...

  3. Jenkins和Gitlab CI/CD自动更新k8s中pod使用的镜像说明

    Jenkins 使用Jenkins的话,完成的工作主要有如下步骤: 1.从Gogs或Gitlab仓库上拉取代码 2.使用Maven编译代码,打包成jar文件 3.根据jar文件使用相对应的Docker ...

  4. k8s中pod的yaml文件全面解读

    apiVersion: v1 #必选,版本号,例如v1,版本号必须可以用 kubectl api-versions 查询到 . kind: Pod #必选,Pod metadata: #必选,元数据 ...

  5. k8s中pod的容器日志查看命令

    如果容器已经崩溃停止,您可以仍然使用 kubectl logs --previous 获取该容器的日志,只不过需要添加参数 --previous. 如果 Pod 中包含多个容器,而您想要看其中某一个容 ...

  6. 延申三大问题中的第二个问题处理---收集查看k8s中pod的控制台日志

    1.不使用logstash 2.步骤: 2.1 先获取一个文件的日志 2.2 再获取多个文件的日志 2.3 批量获取文件日志 pod日志文件路径 [root@worker hkd-eureka]# p ...

  7. K8S中POD节点状态ContainerCreating原因排查

    现象: # kubectl get pods -n kube-system |grep dashboard kubernetes-dashboard-6685cb584f-dqkwk 0/1 Cont ...

  8. k8s中ingress,service,depoyment,pod如何关联

    k8s中pod通过label标签名称来识别关联,它们的label  name一定是一样的.ingress,service,depoyment通过selector 中app:name来关联 1.查询发布 ...

  9. k8s 中的 Pod 细节了解

    k8s中Pod的理解 基本概念 k8s 为什么使用 Pod 作为最小的管理单元 如何使用 Pod 1.自主式 Pod 2.控制器管理的 Pod 静态 Pod Pod的生命周期 Pod 如何直接暴露服务 ...

随机推荐

  1. Dubbo源码(三) - 服务导出(生产者)

    前言 本文基于Dubbo2.6.x版本,中文注释版源码已上传github:xiaoguyu/dubbo 在了解了Dubbo SPI后,我们来了解下Dubbo服务导出的过程. Dubbo的配置是通过Du ...

  2. 在.NET 6.0中配置WebHostBuilder

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 在阅读第4章"使用Kestrel配置和定制HTTPS"时,您可 ...

  3. python打开文件、文件夹窗口、终端窗口

    简介 在一些项目中,我们会需要在生成完文件后打开某些文件或者文件夹窗口,这就需要使用到内置的文件打开方式了. 打开文件或文件夹 Windows import os import subprocess ...

  4. luoguP4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (线段树-权值-动态开点,树链剖分)

    中学毕业了,十七号就要前往武汉报道.中学的终点是武汉大学,人生的终点却不是,最初的热情依然失却,我还是回来看看这分类排版皆惨淡的博客吧,只是是用来保存代码也好.想要换一个新博客,带着之前的经验能把它整 ...

  5. Vue 3-150行代码实现新国标红绿灯效果案例

    昨天刷视频,都是关于新国标红绿灯的,看大家议论纷纷,下班就用150行代码通过Vue组件实践红绿模拟演示,视频也跟大家展示过了.今天接着更新图文版本,大家跟着优雅哥通过该案例实操模拟一下. 不过新国标红 ...

  6. 如何在 HTML 中调整图像大小?

    了解在 HTML 中调整图像大小的不同技术.何时应避免在浏览器端调整大小,以及在 Web 上操作和提供图像的正确方法. 如果您的图像不适合布局,您可以在 HTML 中调整其大小.在 HTML 中调整图 ...

  7. Qt QBarSeries简易柱状图教程

    博客园最强Qt QBarSeries简易柱状图教程 前情提要 每个人的绘图需求不同,此篇教程也是根据需求来改的.我的需求大概如下所示. 通过信号槽的方式接收signals来刷新柱状图,所以每次触发信号 ...

  8. 并发与并行,同步和异步,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang并发编程之GoroutineEP13

    如果说Go lang是静态语言中的皇冠,那么,Goroutine就是并发编程方式中的钻石.Goroutine是Go语言设计体系中最核心的精华,它非常轻量,一个 Goroutine 只占几 KB,并且这 ...

  9. C语言:多功能计算器程序说明书

    好家伙,3000字终于写完了 一.题目:多功能科学计算器 二.内容: (1)概述或引言 开发环境为Visual C++ 目前已实现的功能: (1)解二元一次方程.一元二次方程 (2)进行矩阵相加.相减 ...

  10. Vmware虚拟主机启动卡死问题解决

    记录一次虚拟主机开机卡死,黑屏,无法操作的问题 一.问题现象 1.在vmware上新建数台主机后,第一次启动都正常,部分主机出现关机后再开机(或直接重启)卡死的情况: 2.在vmware上右键菜单栏均 ...