Kubernetes Pod 调度基础
目录
一、Replication Controller 和 ReplicaSet
1、Replication Controller(复制控制器,RC)
(1)编辑ReplicationController文件
(2)创建ReplicationController
(3)删除一个pod并立即查看pod状态
(4)删除ReplicationController
2、标签与标签选择器
(1)标签
(2)标签选择器
基于等式的选择器
基于集合的选择器
(3)标签与标签选择器举例
3、ReplicaSet
RS 与 RC 的核心区别
(1)编辑ReplicaSet文件
(2)创建RS
二、无状态应用管理Deployment
1、什么是无状态
2、无状态服务特点
3、无状态服务的应用场景
4、创建Deployment
(1)编写Deployment
(2)使用kubectl create创建此Deployment
(3)查看Deployment的状态
(4)使用rollout查看整个Deployment的创建过程状态
(5)查看这个Deployment对应的RS
(6)查看此Deployment创建的pod
2、更新Deployment
(1)更新pod的image
(2)查看更新过程
(3)此时的RS 有新的和旧的
(4)通过describd查看deployment的详细信息
3、回滚deployment
(1)多更新几次deployment
(2)查看更新历史
(3)查看某次更新的详情
(4)回滚到指定版本
(5)回滚上次版本
4、扩容deployment
(1)调整pod的副本数
5、删除Deployment
三、有状态应用管理StatefulSet
1、有状态服务的定义
2、有状态服务的特征
3、有状态服务的应用场景
4、无状态服务和有状态服务的比较
5、编写statefulSet资源文件
(1)定义一个statefulSet资源文件
(2)创建statefulSet
(3)查看statefilset状态
(4)查看群集状态
6、statefulset扩容
(1)扩容,将副本数修改为3
7、缩容
(1)打开第二个终端,动态显示缩容流程
(2)再原来第一个终端修改副本数为2
(3)在第一个终端上查看最终结果
8、非级联删除statefulset
(1)采用非级联删除
(2)查看管理的pod
(3)删除pod
9、级联删除statefulset
(1)先创建出statefulset
(2)级联删除
(3)删除redis服务
四、守护进程集DaemonSet
1、什么是DaemonSet
2、定义一个DaemonSet
3、创建DaemonSet
4、查看DaemonSet
5、查看pod所在的节点
五、CronJob
1、创建CronJob
(1)编辑Cronjob文件
(2)创建Cronjob
(3)查看创建结果
(4)查看生成的pod,并查看pod 的执行日志
(5)删除Cronjob
一、Replication Controller 和 ReplicaSet
1、Replication Controller(复制控制器,RC)
- 确保 Pod 副本数达到期望值,保障应用高可用性
- 自动处理 Pod 的失败、删除或终止,实时补充新 Pod
- 功能类似进程管理程序,但作用于多个节点的 Pod 集合
(1)编辑ReplicationController文件
vim replicationcontroller-nginx.yaml
apiVersion: v1
kind: ReplicationController
metadata:name: nginx
spec:replicas: 3selector:app: nginxtemplate:metadata:name: nginxlabels:app: nginxspec:containers:- name: nginximage: nginx:1.7.9ports:- containerPort: 80
(2)创建ReplicationController
kubectl apply -f replicationcontroller-nginx.yaml[root@k8s-master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-b9b75 1/1 Running 0 50s 10.244.58.196 k8s-node02 <none> <none>
nginx-hm67q 1/1 Running 0 50s 10.244.85.194 k8s-node01 <none> <none>
nginx-l8g5v 1/1 Running 0 50s 10.244.85.193 k8s-node01 <none> <none>[root@k8s-master ~]# kubectl get rc
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 2m56s
(3)删除一个pod并立即查看pod状态
kubectl delete pod nginx-hm67qkubectl get pod
(4)删除ReplicationController
kubectl delete -f replicationcontroller-nginx.yaml
2、标签与标签选择器
(1)标签
标签:标识 Kubernetes 对象的键值对,用于对象筛选与组织
语法规则:
- Key 必须唯一,长度 ≤ 63 字符,由字母 / 数字开头结尾,可包含
-
、_
、.
- 前缀可选,需符合 DNS 子域名格式(如
kubernetes.io/
)- Value 非空时长度 ≤ 63 字符,规则同 Key
(2)标签选择器
基于等式的选择器
- 操作符:
=
、==
(相等)、!=
(不等)- 示例:
date=day1,name!=build
(选择 date=day1 且 name≠build 的对象)
基于集合的选择器
- 操作符:
in
、notin
、exists
- 示例:
date in (day1,day2,day3)
name notin (build,pipline)
test
(存在 test 标签)!test
(不存在 test 标签)
(3)标签与标签选择器举例
基于等式的标签选择器
selector:component: redis
基于集合的标签选择器
selector:matchLabels:component: redismatchExpressions:- {key: tier, operator: In, values: [cache]}- {key: environment, operator: NotIn, values: [dev]}
3、ReplicaSet
RS 与 RC 的核心区别
- RS 是下一代 RC,支持基于集合的标签选择器
- 主要用于 Deployment 协调 Pod 的创建、删除与更新
- 建议通过 Deployment 管理 RS,而非单独使用
(1)编辑ReplicaSet文件
vim replicaset-example.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:name: frontendlabels:app: guestbooktier: frontend
spec:# modify replicas according to your casereplicas: 3selector:matchLabels:tier: frontendmatchExpressions:- {key: tier, operator: In, values: [frontend]}template:metadata:labels:app: guestbooktier: frontendspec:containers:- name: php-redisimage: nginx:1.7.9resources:requests:cpu: 100mmemory: 100Mienv:- name: GET_HOSTS_FROMvalue: dns# If your cluster config does not include a dns service, then to# instead access environment variables to find service host# info, comment out the 'value: dns' line above, and uncomment the# line below.# value: envports:- containerPort: 80
- matchExpressions 是一个列表,其中可以包含多个匹配表达式。这里的例子只包含了一个表达式。
- - 表示列表中的一个条目。
- {key: tier,operator: In,values: [frontend]} 这是一个具体的匹配表达式,它包含以下几个部分:
- key:标签键(label key),这里是 tier。
- operator:匹配操作符,在这里为 In,表示“在..之中”
- values:匹配值列表,这里只有一个值[frontend]。
- requests:代表容器启动请求的资源限制,分配的资源必须要达到此要求
- limits:代表最多可以请求多少资源
这个匹配表达式的含义是:“选择那些在其标签中包含键为 tier 并且该键对应的值为 frontend 的
对象。”
例如如下写法:
matchExpressions:- {key: tier,operator: In,values: ["frontend"]}- {key: environment,operator: In,values: ["production","staging"]}
CPU 的计量单位叫毫核(m)。一个节点的 CPU 核心数量乘以 1000,得到的就是节点总的 CPU 总数量。如,一个节点有两个核,那么该节点的 CPU 总量为 2000m。该容器启动时请求 100/2000 的核心(5%)。
(2)创建RS
ku create -f replicaset-example.yaml [root@k8s-master ~]# ku get pod
NAME READY STATUS RESTARTS AGE
frontend-2brrj 1/1 Running 0 8s
frontend-9sfkg 1/1 Running 0 8s
frontend-grrnj 1/1 Running 0 8s
nginx-b9b75 1/1 Running 0 38m
nginx-lnmgz 1/1 Running 0 25m
nginx-vq762 1/1 Running 0 34m[root@k8s-master ~]# ku get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
frontend-2brrj 1/1 Running 0 21s 10.244.85.195 k8s-node01 <none> <none>
frontend-9sfkg 1/1 Running 0 21s 10.244.58.199 k8s-node02 <none> <none>
frontend-grrnj 1/1 Running 0 21s 10.244.85.196 k8s-node01 <none> <none>
删除
kubectl delete -f replicaset-example.yaml
二、无状态应用管理Deployment
1、什么是无状态
无状态服务(stateless service)对单次请求的处理,不依赖其他请求,也就是说,处理一次请求所需的全部信息,要么都包含在这个请求里,要么可以从外部获取到(比如说数据库),服务器本身不存储任何信息。这种服务叫做无状态服务。
无状态服务:就是没有特殊状态的服务,各个请求对于服务器来说统一无差别处理,请求自身携带了所有服务端所需要的所有参数(服务端自身不存储跟请求相关的任何数据,不包括数据库存储信息)
如果在启动一个服务时,不依赖于该服务之前的运行状态,或者不依赖于其他服务,这个服务就是无状态服务;反之,就是有状态服务。
2、无状态服务特点
(1)数据方面:无状态服务不会在本地存储持久化数据,多个实例可以共享相同的持久化数据
(2)结果方面:多个服务实例对于同一个用户请求的响应结果是完全一致的
(3)关系方面:这种多服务实例之间是没有依赖关系
(4)影响方面:在k8s 控制器中动态启停无状态服务的 pod 并不会对其它的 pod 产生影响
(5)示例方面:nginx实例,tomcat 实例,web 应用
(6)资源方面:相关的k8s 资源有:Replicaset、Replicationcontroller、Deployment
(7)创建方式:Deployment 被设计用来管理无状态服务的 pod
每个 pod 完全一致,原因如下:
- 无状态服务内的多个 Pod 创建的顺序是没有顺序的
- 无状态服务内的多个 Pod 的名称是随机的
- pod 被重新启动调度后,它的名称与 IP 都会发生变化
- 无状态服务内的多个 Pod 背后是共享存储的
(8)扩缩容方式:随机缩容
由于是无状态服务,所以这些控制器创建的 pod 序号都是随机值。并且在缩容也是随机,并不会明确缩容某一个 pod。因为所有实例得到的返回值都是一样,所以缩容任何一个 pod 都可以。
3、无状态服务的应用场景
Deployment 用来管理 RS,并为 Pod 和 RS 提供声明性更新,以及许多其他的新的功能,生产环境中使用 Deployment 替代 RS。
Deployment 一般用于部署公司的无状态服务,因为企业内部现在都是以微服务为主,微服务实现无状态化也是最佳实践。可以利用 Deployment 的高级功能做到无缝迁移、自动扩容缩容、自动灾难恢复、键回滚等功能。
无状态服务不会在本地存储持久化数据。多个服务实例对于同一个用户请求的响应结果是完全一致的。这种多服务实例之间是没有依赖关系,比如 web 应用,在 k8s 控制器中动态启停无状态服务的 pod 并不会对其它的 pod 产生影响。
Deployment 被设计用来管理无状态服务的 pod,每个 pod 完全一致
无状态服务内的多个 Pod 创建的顺序是没有顺序的。
无状态服务内的多个 Pod 的名称是随机的.pod 被重新启动调度后,它的名称与 IP 都会发生变化。
无状态服务内的多个 Pod 背后是共享存储的。
4、创建Deployment
(1)编写Deployment
vim nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:name: nginx-deployment
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.7.9ports:- name: nginxcontainerPort: 80
replicas:pod 的副本数
selector:定义 Deployment 如何找到要管理的 Pod,与 template 的 label 标签对应
template:
- app:nginx 使用 label 标记 pod
- spec:定义 pod 的详细信息
- name: nginx 表示 pod 运行一个名字为 nginx 的容器
- image:运行此 pod 使用的镜像
- port:容器用于发送和接收流量的端口
(2)使用kubectl create创建此Deployment
kubectl create -f nginx-deployment.yaml
(3)查看Deployment的状态
kubectl get deploy
(4)使用rollout查看整个Deployment的创建过程状态
kubectl rollout status deployment/nginx-deployment
(5)查看这个Deployment对应的RS
kubectl get rs -l app=nginx
(6)查看此Deployment创建的pod
kubectl get pods --show-labels
2、更新Deployment
通过 Deployment 部署应用后,如果需要对 Deployment 文件的配置文件或者镜像版本进行更新,更改后该 Deployment 会创建新的 Repliccaset,之后会对管理的 Pod 进行滚动升级。
(1)更新pod的image
kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --recordkubectl set image deployment nginx-deployment nginx=nginx:1.12.0 --record
(2)查看更新过程
kubectl rollout status deployment.v1.apps/nginx-deployment
(3)此时的RS 有新的和旧的
kubectl get rs
(4)通过describd查看deployment的详细信息
kubectl describe deploy nginx-deployment
3、回滚deployment
当更新的版本不稳定或者配置不合理时,可以对其进行回滚操作。
(1)多更新几次deployment
kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record
kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record
(2)查看更新历史
kubectl rollout history deployment/nginx-deployment
注:最后的一个版本是当前版本
(3)查看某次更新的详情
kubectl rollout history deployment/nginx-deployment --revision=2
(4)回滚到指定版本
kubectl rolloyt undo deployment/nginx-deployment --to-revision=2
查看回滚结果:
kubectl rollout history deployment/nginx-deployment
(5)回滚上次版本
kubectl rollout undo deployment/nginx-deployment
查看回滚结果:
kubectl rollout history deployment/nginx-deployment
4、扩容deployment
(1)调整pod的副本数
kubectl scale deployment.v1.apps/nginx-deployment --replicas=3
查看扩容结果:
kubectl get pods
5、删除Deployment
kubectl delete -f nginx-deployment.yaml
三、有状态应用管理StatefulSet
1、有状态服务的定义
Statefulset(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序。比如在生产环境中,可以部署 Elasticsearch 集群、MongoD8 集群或者需要持久化的 RabbitMQ 集群、Redis 集群、Kafka 集群和 ZooKeeper 集群等。
一个 StatefulSet 管理着基于相同容器规范的 Pod。与 Deployment 不同的是,StatefulSet 为每个 Pod 维护了一个标识。这些 Pod 是根据相同规范创建的,但是不可互换,每个 Pod 都有一个持久的标识符,在重新调度时也会被保留。
2、有状态服务的特征
(1)数据方面:有状态服务需要在本地存储持久化数据,典型的应用是分布式数据库
(2)结果方面:实例之间,请求结果可能存在不一致
(3)关系方面:分布式节点实例之间有依赖的拓扑关系,比如主从关系。
(4)影响方面:如果 K8S 停止分布式集群中任一实例 pod,就可能会导致数据丢失或者集群的 crash(崩溃)
(5)示例方面:mysq1数据库、kafka、zookeeper、Redis 主从架构
(6)资源方面:statefulset
(7)创建方式:statefulset 管理
Stateful 管理有状态的应用,Pod 有如下特征:
- 唯一性:每个 Pod 会被分配一个唯一序号,
- 顺序性:Pod 启动,更新,销毁是按顺序进行.
- 稳定的网络标识:Pod 主机名,DNS地址不会随着 Pod 被重新调度而发生变化。
- 稳定的持久化存储:Pod 被重新调度后,仍然能挂载原有的PV,从而保证了数据的完整性和一致性
3、有状态服务的应用场景
有状态的 pod 是用来运行有状态应用的,所以其在数据卷上存储的数据非常重要,在 statefulset缩容时删除这个声明将是灾难性的,特别是对于 statefulset 来说,缩容就像减少其 replicas 数值一样简单。基于这个原因,当需要释放特定的持久卷时,需要手动删除对应的持久卷声明。
有状态服务需要在本地存储持久化数据,典型的是分布式数据库的应用,分布式节点实例之间有依赖的拓扑关系,比如,主从关系,如果 K8s 停止分布式集群中任一实例 pod,就可能会导致数据丢失或者集群的 crash(崩溃)。
有状态服务可以说是需要数据存储功能的服务、或者指多线程类型的服务,队列等。(mysq1 数据库、kafka、zookeeper等)。
有状态服务常常用于实现事务(并不是唯一办法,下文有另外的方案)。举一个常见的例子,在商城里购买一件商品。需要经过放入购物车、确认订单、付款等多个步骤。由于 HTTP 协议本身是无状态的,所以为了实现有状态服务,就需要通过一些额外的方案。比如最常见的 session,将用户挑选的商品(购物车),保存到 session 中,当付款的时候,再从购物车里取出商品信息。
4、无状态服务和有状态服务的比较
维度 | 无状态服务 | 有状态服务 |
---|---|---|
状态依赖 | 不依赖自身状态,数据可维护在内存中 | 依赖局部状态数据,需持久化或从其他节点恢复 |
请求处理 | 任意实例可处理任何请求 | 特定请求只能由特定节点处理 |
数据存储 | 不存储状态数据,支持水平扩展 | 存储状态数据,扩展需系统参与状态迁移 |
数据闭环 | 单一数据闭环 | 多个数据闭环,需考虑一致性 |
架构类型 | 单体架构集群 | 分布式架构 |
5、编写statefulSet资源文件
(1)定义一个statefulSet资源文件
vim redis-statefulset.yaml
apiVersion: v1
kind: Service
metadata:name: redis-svcspec:selector:app: redis-stsports:- port: 6379protocol: TCPtargetPort: 6379apiVersion: apps/v1
kind: StatefulSet
metadata:name: redis-stsspec:serviceName: redis-svcreplicas: 2selector:matchLabels:app: redis-ststemplate:metadata:labels:app: redis-stsspec:containers:- image: redis:5-alpinename: redisports:- containerPort: 6379
注:
kind:Service 定义了一个名字为redis-svc 的服务。
kind:statefulset 定义了一个名字为redis-sts的statefulset,replicas 表示部署 Pod的副本数。
(2)创建statefulSet
kubectl create -f redis-statefulset.yaml
(3)查看statefilset状态
kubectl get sts
(4)查看群集状态
kubectl get service[root@k8s-master ~]# kuectl get pod -l app=redis-sts
NAME READY STATUS RESTARTS AGE
redis-sts-0 1/1 Running 0 14s
redis-sts-1 1/1 Running 0 12s
-l:指定标签(label)
注意 NAME 列,名称是 sts 的 name-序号,这里序号越小则说明创建的越早从 AGE 列也可以看出来,这就解决了有状态应用中的启动顺序问题,比如可以让 redis-sts-0作为redis 的主节点,redis-sts-1作为从节点
6、statefulset扩容
(1)扩容,将副本数修改为3
kubectl scale sts redis-sts --replicas=3
[root@k8s-master ~]# ku get pod
NAME READY STATUS RESTARTS AGE
redis-sts-0 1/1 Running 0 3m2s
redis-sts-1 1/1 Running 0 3m
redis-sts-2 1/1 Running 0 5s
7、缩容
(1)打开第二个终端,动态显示缩容流程
kubectl get pods -w -l app=redis-sts
-w:动态监听所有的pod
(2)再原来第一个终端修改副本数为2
kubectl patch sts redis-sts -p '{"spec":{"replicas":2}}'
注:此时可以查看第二个终端上的变化
(3)在第一个终端上查看最终结果
kubectl get pods -l app=redis-sts
8、非级联删除statefulset
删除 statefulset 有两种方式:级联删除和非级联删除。
使用非级联方式删除 statefulset 时,statefulset 的Pod 不会被删除。使用级联方式删除Statefulset 时,statefulset 和它的 Pod 都会被删除:
(1)采用非级联删除
kubectl delete statefulset redis-sts --cascade=false
查看删除结果:
kubectl get sts
(2)查看管理的pod
kubectl get pod
发现pod 并没有被删除
(3)删除pod
kubectl delete pod redis-sts-0
kubectl delete pod redis-sts-1
9、级联删除statefulset
(1)先创建出statefulset
kubectl create -f redis-statefulset.yaml
(2)级联删除
kubectl dalete statefulset redis-sts
查看
kubectl get pod
两个pod 全都没了
(3)删除redis服务
kubectl delete -f redis-statefulset.yaml
四、守护进程集DaemonSet
1、什么是DaemonSet
有时候我们需要在每个 Kubernetes 节点或符合条件的节点上都部署某个应用,那么就可以使用Kubernetes 的 Daemonset 调度 Pod。Daemonset 确保全部(或符合条件)的节点上运行一个 Pod 副本.当有新的节点加入集群时,也会为他们新增一个 Pod,当节点从集群中移除时,这些 Pod 会被回收,删除Daemonset 将会删除它创建的所有的 Pod。
2、定义一个DaemonSet
vim daemonset-nginx.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:name: pod-controllernamespace: devlabels:controller: daemonset
spec:selector:matchLabels:app: nginx-podtemplate:metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.7.9ports:- name: nginx-portcontainerPort: 80protocol: TCP
3、创建DaemonSet
kubect create namespace devkubect create -f daemonset-nginx.yaml
4、查看DaemonSet
[root@k8s-master ~]# kubectl get ds -n dev -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
pod-controller 2 2 2 2 2 <none> 63s nginx nginx:1.7.9 app=nginx-pod
5、查看pod所在的节点
[root@k8s-master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pod-controller-cjqjm 1/1 Running 0 94s
pod-controller-kvscd 1/1 Running 0 94s
五、CronJob
Cronjob(计划任务,缩写为cj)用于以时间为基准的周期性地执行任务,这些自动化任务和运行在 Linux 系统上的 cronJob 一样。
1、创建CronJob
(1)编辑Cronjob文件
vim cronjob-example.yaml
apiVersion: batch/v1 #1.21版本以上 改为batch/v1
kind: CronJob
metadata:name: hello
spec:schedule: "*/1 * * * *"jobTemplate:spec:template:spec:containers:- name: helloimage: busybox:v1args:- /bin/sh- -c- date; echo Hello from the Kubernetes clusterrestartPolicy: OnFailure
这个案例会在每分钟执行一次计划任务,并输出当前时间和“Hello from the Kubernetes cluster。
(2)创建Cronjob
kubectl create -f cronjob-example.yaml
(3)查看创建结果
[root@k8s-master ~]# ku get cj
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 16s
等待一会后可以查看生成的pod
kubectl get jobs
(4)查看生成的pod,并查看pod 的执行日志
ku get pod[root@k8s-master ~]# ku logs -f hello-29188998-jhkpj
Tue Jul 1 03:18:01 UTC 2025
Hello from the Kubernetes cluster
(5)删除Cronjob
kubectl delete cronjob hello