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. GDOI 2022 普及组游记

    To LuoguDAY -1 期中考成绩下来了,全无了除了历史 (96) 和生物 (95) 还能看,剩下的-,语文 101.5 ,少错一道选择和断句就 107.5 了,居然比雌兔还低 数学少错一道选择 ...

  2. USB转串口参数配置功能

    当使用USB转串口芯片时,在部分场合下需要修改芯片内部的USB参数以满足其应用需要.常见如: 系统下使用多个USB转串口芯片,区分使用各芯片. 修改厂商ID.产品ID.厂商字符串,使用客户自有ID和信 ...

  3. Rust 从入门到精通01-简介

    1.rust 从哪里来 Rust语言在2006年作为 Mozilla 员工 Graydon Hoare 的私人项目出现,而 Mozilla 于 2009 年开始赞助这个项目.第一个有版本号的 Rust ...

  4. 转一篇MYSQL文章《数据库表设计,没有最好只有最适合》

    http://mp.weixin.qq.com/s/a8klpzM5iam0_JYSw7-U4g 我们在设计数据库的时候,是否会突破常规,找到最适合自己需求的设计方案,下面来举个例子: 常用的邻接表设 ...

  5. Javascript 构造函数、原型对象、实例之间的关系

    # Javascript 构造函数.原型对象.实例之间的关系 # 创建对象的方式 # 1.new object() 缺点:创建多个对象困难 var hero = new Object(); // 空对 ...

  6. 密码学系列之:PEM和PKCS7,PKCS8,PKCS12

    目录 简介 PEM PKCS7 PKCS8 PKCS12 总结 简介 PEM是一种常见的保存key或者证书的格式,PEM格式的文件一般来说后缀是以.pem结尾的.那么PEM到底是什么呢?它和常用的证书 ...

  7. Computational Protein Design with Deep Learning Neural Networks

    本文使用深度神经网络完成计算蛋白质设计去预测20种氨基酸概率. Introduction 针对特定结构和功能的蛋白质进行工程和设计,不仅加深了对蛋白质序列结构关系的理解,而且在化学.生物学和医学等领域 ...

  8. ETCD快速入门-03 常用命令

    3. ETCD 常用命令     etcdctl是一个命令行的客户端,它提供了一些命令,可以方便我们在对服务进行测试或者手动修改数据库内容.etcdctl与kubectl和systemctl的命令原理 ...

  9. Luogu1880 [NOI1995]石子合并 (区间DP)

    一个1A主席树的男人,沦落到褪水DP举步维艰 #include <iostream> #include <cstdio> #include <cstring> #i ...

  10. java-XML使用

    XML文件一.XML用途:指可扩展标记语言(EXtensible Markup Language),是独立于软件和硬件的信息传输工具,应用于 web 开发的许多方面,常用于简化数据的存储和共享.二.在 ...