目录
一、Replication Controller 与 ReplicaSet:Pod 副本数的守护者
1.1 Replication Controller:确保 Pod 副本数的基础机制
1.1.1 Replication Controller 实践示例
1.2 标签与标签选择器:Kubernetes 对象管理的核心机制
1.2.1 标签(Label)的定义与规范
1.2.2 标签选择器(Label Selector)的类型与用法
1.2.3 标签与标签选择器应用实例
1.3 ReplicaSet:下一代的复制控制器
1.3.1 ReplicaSet 配置示例
1.3.2 ReplicaSet 操作命令
二、无状态应用管理:Deployment 的强大功能
2.1 无状态服务的定义与特征
2.1.1 无状态服务的概念
2.1.2 无状态服务的核心特点
2.2 Deployment:无状态应用的最佳管理工具
2.2.1 Deployment 的应用场景
2.2.2 创建 Deployment 实践
2.3 Deployment 的高级操作:更新、回滚与扩缩容
2.3.1 更新 Deployment
2.3.2 回滚 Deployment
2.3.3 扩容 Deployment
2.3.4 删除 Deployment
三、有状态应用管理:StatefulSet 的独特能力
3.1 有状态服务的定义与特征
3.1.1 有状态服务的概念
3.1.2 有状态服务的核心特征
3.2 有状态服务的应用场景与挑战
3.3 无状态服务与有状态服务的对比分析
3.3.1 无状态服务的特点
3.3.2 有状态服务的特点
3.4 StatefulSet 实践:构建有状态的 Redis 集群
3.4.1 编写 StatefulSet 资源文件
3.4.2 创建与管理 StatefulSet
3.4.3 StatefulSet 扩缩容操作
3.4.4 StatefulSet 的删除方式
四、守护进程集 DaemonSet:节点级别的服务部署
4.1 DaemonSet 的定义与应用场景
4.2 DaemonSet 实践示例
4.2.1 定义 DaemonSet 配置文件
4.2.2 创建与管理 DaemonSet
五、CronJob:基于时间的周期性任务调度
5.1 CronJob 的定义与应用场景
5.2 CronJob 实践示例
5.2.1 编辑 CronJob 配置文件
5.2.2 创建与管理 CronJob
Replication Controller(复制控制器,RC)是 Kubernetes 中用于确保 Pod 副本数达到期望值的基础组件,其核心功能是保证一个或多个同类 Pod 始终处于可用状态。
当使用 Replication Controller 管理 Pod 时,它会持续监控集群中 Pod 的数量:如果存在的 Pod 数量大于设定值,Replication Controller 将终止额外的 Pod;如果数量不足,它会启动新的 Pod 以保证达到期望值。与手动创建 Pod 不同的是,用 Replication Controller 维护的 Pod 在失败、删除或终止时会自动替换。因此,即使应用程序只需要一个 Pod,也建议使用 Replication Controller 或其他方式进行管理。
从本质上讲,Replication Controller 类似于进程管理程序,但它并非监视单个节点上的各个进程,而是监视多个节点上的多个 Pod,实现了跨节点的应用可用性保障。
下面通过一个具体示例来演示 Replication Controller 的使用方法:
第一步:编辑 ReplicationController 配置文件
# replicationcontroller-nginx.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:1.7.9
ports:
- containerPort: 80
在这个配置文件中:
replicas: 3
表示期望创建 3 个 Pod 副本selector: app: nginx
定义了标签选择器,用于匹配需要管理的 Podtemplate
部分定义了 Pod 的模板,包括容器镜像、端口等配置第二步:创建 ReplicationController
kubectl apply -f replicationcontroller-nginx.yaml
创建完成后,可以通过以下命令查看 Pod 和 ReplicationController 的状态:
# 查看 Pod 状态
kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-9g78r 1/1 Running 0 11m
nginx-bbtqj 1/1 Running 0 11m
nginx-w28bq 1/1 Running 0 11m
# 查看 ReplicationController 状态
kubectl get rc
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 116s
第三步:验证自动恢复能力
删除一个 Pod 并立即查看状态,验证 ReplicationController 的自动恢复功能:
# 删除一个 Pod
kubectl delete pod nginx-9g78r -n default
# 查看 Pod 状态,可以看到新的 Pod 正在创建
kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-bbtqj 1/1 Running 0 12m
nginx-qqjs4 0/1 ContainerCreating 0 2s
nginx-w28bq 1/1 Running 0 12m
第四步:删除 ReplicationController
kubectl delete -f replicationcontroller-nginx.yaml
标签是附加在 Kubernetes 对象上的一组键值对,通过标签我们可以方便地筛选或排除一组对象。在集群中,应用部署或批处理程序部署通常是多维度的,为了实现对这些对象的管理,往往需要对某一特定维度的对象进行操作,而标签可以通过用户的意愿组织集群中的对象之间的结构,而不需要对集群进行修改。
标签的使用需要遵循以下规范:
kubernetes.io
,后用 / 将其与标签名分隔标签选择器是用于选择一组对象的工具(标签本身并不能唯一标识一个对象),APIServer 支持两种标签选择器:基于等式的标签选择器与基于集合的标签选择器。
基于等式的标签选择器:
使用 =、==、!= 三种操作符进行选择,前两个操作符含义相同,都代表相等,第三种代表不等。选择条件可以通过逗号叠加,例如 date=day1,name!=build
代表选择 date 值为 day1 且 name 值不为 build 的对象。
基于集合的标签选择器:
这种选择器可以同时选择一组对象,支持的操作符有 in、notin、exists,具体用法如下:
date in(day1,day2,day3)
name notin(build,pipline)
test
!test
基于集合的标签选择器也支持使用逗号分隔以同时叠加选择,相同意义上的选择条件在这两种选择方式之间是等价的。
基于等式的标签选择器示例:
selector:
component: redis
基于集合的标签选择器示例:
selector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
在这个示例中:
matchLabels
是 {key, value} 对的映射,单个 {key, value} 等价于 matchExpressions
中键为 "key"、运算符为 "in"、值数组仅包含 "value" 的元素matchExpressions
是 Pod 选择器需求的列表,有效的运算符包括 in、notin、exists 和 doesnotexistmatchLabels
和 matchExpressions
中的所有要求都必须满足才能匹配对象ReplicaSet(复制集,RS)是支持基于集合的标签选择器的下一代 Replication Controller,它主要用于 Deployment 协调创建、删除和更新 Pod。ReplicaSet 与 Replication Controller 的唯一区别是支持更灵活的标签选择器。
在实际应用中,虽然 ReplicaSet 可以单独使用,但一般建议使用 Deployment 来自动管理 ReplicaSet,除非自定义的 Pod 不需要更新或有其他特殊编排需求。
下面是一个 ReplicaSet 的配置实例:
# replicaset-example.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: guestbook
tier: frontend
spec:
containers:
- name: php-redis
image: nginx:1.7.9
resources:
requests:
cpu: 100m
memory: 100Mi
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
在这个配置中:
matchExpressions
是一个列表,可以包含多个匹配表达式{key: tier, operator: In, values: [frontend]}
是一个具体的匹配表达式,表示选择标签中包含键为 tier 且值为 frontend 的对象requests
代表容器启动请求的资源限制,分配的资源必须达到此要求创建 RS:
kubectl create -f replicaset-example.yaml
查看 Pod:
kubectl get pod
删除 RS:
kubectl delete -f replicaset-example.yaml
无状态服务(stateless service)是指对单次请求的处理不依赖其他请求的服务。也就是说,处理一次请求所需的全部信息,要么都包含在这个请求里,要么可以从外部获取到(例如数据库),服务器本身不存储任何与请求相关的状态信息。
更具体地说,无状态服务没有特殊状态,各个请求对于服务器来说统一无差别处理,请求自身携带了服务端所需的所有参数(服务端自身不存储跟请求相关的任何数据,不包括数据库存储信息)。如果在启动一个服务时,不依赖于该服务之前的运行状态,或者不依赖于其他服务,这个服务就是无状态服务。
无状态服务具有以下显著特点:
Deployment 是 Kubernetes 中用于管理 ReplicaSet 并为 Pod 和 RS 提供声明性更新的核心组件,它具有许多强大的新功能,在生产环境中通常使用 Deployment 替代直接使用 RS。
Deployment 主要用于部署公司的无状态服务,这是因为企业内部现在多以微服务架构为主,而微服务实现无状态化是最佳实践。利用 Deployment 的高级功能,可以轻松实现无缝迁移、自动扩容缩容、自动灾难恢复、一键回滚等重要功能。
无状态服务的特性决定了它非常适合使用 Deployment 管理:不会在本地存储持久化数据,多个服务实例响应一致,实例间无依赖关系,动态启停 Pod 不影响其他实例,这些特点都与 Deployment 的设计理念高度契合。
第一步:编写 Deployment 配置文件
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- name: nginx
containerPort: 80
配置文件中各关键字的含义:
replicas
:指定 Pod 的副本数selector
:定义 Deployment 如何找到要管理的 Pod,需与 template 的 label 标签对应template
:
app: nginx
:使用 label 标记 Podspec
:定义 Pod 的详细信息,包括容器名称、镜像、端口等第二步:创建 Deployment
kubectl create -f nginx-deployment.yaml
第三步:查看 Deployment 状态
# 查看 Deployment
kubectl get deploy
# 查看 Deployment 创建过程状态
kubectl rollout status deployment/nginx-deployment
# 查看对应的 ReplicaSet
kubectl get rs -l app=nginx
# 查看创建的 Pod
kubectl get pods --show-labels
通过 Deployment 部署应用后,如果需要对配置文件或镜像版本进行更新,修改后该 Deployment 会创建新的 ReplicaSet,并对管理的 Pod 进行滚动升级。
更新 Pod 的镜像:
# 更新为 nginx:1.9.1 并记录
kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record
# 继续更新为 nginx:1.12.0
kubectl set image deployment nginx-deployment nginx=1.12.0 --record
查看更新过程:
kubectl rollout status deployment.v1.apps/nginx-deployment
查看 ReplicaSet 变化:
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-6cf9b75cdd 0 0 0 3m57s
nginx-deployment-7569c477b6 0 0 0 3m8s
nginx-deployment-96bfc8b67 2 2 2 3m4s
当更新的版本不稳定或配置不合理时,可以对 Deployment 进行回滚操作。
多更新几次 Deployment:
kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record
kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record
查看更新历史:
kubectl rollout history deployment/nginx-deployment
查看某次更新详情:
kubectl rollout history deployment/nginx-deployment --revision=2
回滚到指定版本:
kubectl rollout undo deployment/nginx-deployment --to-revision=2
回滚到上次版本:
kubectl rollout undo deployment/nginx-deployment
# 调整副本数为 3
kubectl scale deployment.v1.apps/nginx-deployment --replicas=3
# 查看扩容结果
kubectl get pods
kubectl delete -f nginx-deployment.yaml
StatefulSet(有状态集,缩写为 sts)是 Kubernetes 中用于部署有状态且需要有序启动的应用程序的核心组件。在生产环境中,常用于部署 Elasticsearch 集群、MongoDB 集群、需要持久化的 RabbitMQ 集群、Redis 集群、Kafka 集群和 ZooKeeper 集群等有状态应用。
一个 StatefulSet 管理着基于相同容器规范的 Pod。与 Deployment 不同的是,StatefulSet 为每个 Pod 维护了一个唯一标识。这些 Pod 虽然根据相同规范创建,但不可互换,每个 Pod 都有一个持久的标识符,在重新调度时也会被保留,这是有状态服务管理的关键特性。
有状态服务具有以下显著特点:
有状态的 Pod 用于运行有状态应用,其在数据卷上存储的数据至关重要。对于 StatefulSet 来说,缩容操作需要谨慎处理,因为简单地减少 replicas 数值可能导致数据丢失,特别是在需要释放特定持久卷时,需要手动删除对应的持久卷声明。
有状态服务需要在本地存储持久化数据,典型的分布式数据库应用中,分布式节点实例之间存在依赖的拓扑关系,如主从关系。如果 Kubernetes 停止分布式集群中任一实例 Pod,就可能导致数据丢失或者集群崩溃。
有状态服务可以理解为需要数据存储功能的服务,或者指多线程类型的服务、队列等(如 MySQL 数据库、Kafka、Zookeeper 等)。在实际应用中,有状态服务常常用于实现事务处理。以商城购物为例,购买一件商品需要经过放入购物车、确认订单、付款等多个步骤,由于 HTTP 协议本身是无状态的,为了实现有状态服务,就需要通过一些额外的方案,如常见的 session,将用户挑选的商品(购物车)保存到 session 中,当付款时再从购物车里取出商品信息。
下面定义一个完整的 StatefulSet 资源文件,包括 Service 和 StatefulSet 两部分:
# redis-statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-svc
spec:
selector:
app: redis-sts
ports:
- port: 6379
protocol: TCP
targetPort: 6379
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-sts
spec:
serviceName: redis-svc
replicas: 2
selector:
matchLabels:
app: redis-sts
template:
metadata:
labels:
app: redis-sts
spec:
containers:
- image: redis:5-alpine
name: redis
ports:
- containerPort: 6379
在这个配置中:
kind: Service
定义了一个名为 redis-svc 的服务,用于暴露 Redis 端口kind: StatefulSet
定义了一个名为 redis-sts 的 StatefulSet,replicas: 2
表示部署 2 个 Pod 副本serviceName: redis-svc
将 StatefulSet 与服务关联,确保 Pod 有稳定的网络标识创建 StatefulSet:
kubectl create -f redis-statefulset.yaml
查看 StatefulSet 状态:
kubectl get sts
查看服务状态:
查看 Pod 状态:
kubectl get po -l app=redis-sts
NAME READY STATUS RESTARTS AGE
redis-sts-0 1/1 Running 0 5m38s
redis-sts-1 1/1 Running 0 4m55s
注意观察 Pod 名称,格式为 sts-name-序号
,序号越小创建越早,这解决了有状态应用中的启动顺序问题,例如可以让 redis-sts-0 作为 Redis 的主节点,redis-sts-1 作为从节点。
扩容操作:
# 将副本数修改为 3
kubectl scale sts redis-sts --replicas=3
# 查看结果
kubectl get pod
NAME READY STATUS RESTARTS AGE
redis-sts-0 1/1 Running 0 7m50s
redis-sts-1 1/1 Running 0 7m7s
redis-sts-2 1/1 Running 0 6s
缩容操作:
# 打开第二个终端,动态显示缩容流程
kubectl get pods -w -l app=redis-sts
# 在第一个终端修改副本数为 2
kubectl patch sts redis-sts -p '{"spec":{"replicas":2}}'
# 查看最终结果
kubectl get pods -l app=redis-sts
非级联删除:
使用非级联方式删除 StatefulSet 时,StatefulSet 的 Pod 不会被删除。
kubectl delete statefulset redis-sts --cascade=false
# 查看删除结果
kubectl get sts
# 查看 Pod,发现未被删除
kubectl get po
# 手动删除 Pod
kubectl delete po redis-sts-0
kubectl delete po redis-sts-1
级联删除:
使用级联方式删除 StatefulSet 时,StatefulSet 和它的 Pod 都会被删除。
# 先创建 StatefulSet
kubectl create -f redis-statefulset.yaml
# 级联删除
kubectl delete statefulset redis-sts
# 查看 Pod,已全部删除
kubectl get po
# 删除 Redis 服务
kubectl delete -f redis-statefulset.yaml
有时候我们需要在每个 Kubernetes 节点或符合条件的节点上都部署某个应用,这时就可以使用 Kubernetes 的 DaemonSet 来调度 Pod。DaemonSet 确保全部(或符合条件)的节点上运行一个 Pod 副本,当有新节点加入集群时,会自动为其部署一个 Pod,当节点从集群中移除时,这些 Pod 会被回收,删除 DaemonSet 将会删除它创建的所有 Pod。
DaemonSet 非常适合以下场景:
# daemonset-nginx.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: pod-controller
namespace: dev
labels:
controller: daemonset
spec:
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
创建命名空间和 DaemonSet:
kubectl create namespace dev
kubectl create -f daemonset-nginx.yaml
查看 DaemonSet:
kubectl get ds -n dev -owide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
pod-controller 3 3 3 3 3 3m8s nginx nginx:latest app=nginx-pod
查看 Pod 所在节点:
kubectl get pod -n dev -owide
删除 DaemonSet:
kubectl delete ds pod-controller -n dev
CronJob(计划任务,缩写为 cj)用于以时间为基准周期性地执行任务,这些自动化任务和运行在 Linux 系统上的 Cron 任务一样。CronJob 非常适合以下场景:
# cronjob-example.yaml
apiVersion: batch/v1 # 1.21 版本以上改为 batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:v1
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
这个案例中,schedule: "*/1 * * * *"
表示每分钟执行一次计划任务,任务会输出当前时间和 "Hello from the Kubernetes cluster" 信息。
创建 CronJob:
kubectl create -f cronjob-example.yaml
查看创建结果:
kubectl get cj
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 94s
查看生成的 Job 和 Pod:
kubectl get jobs
NAME COMPLETIONS DURATION AGE
hello-27743514 1/1 20s 74s
hello-27743515 0/1 14s 14s
查看 Pod 执行日志:
kubectl get pod
kubectl logs -f hello-27743522-crnf8
Sat Oct 10 8:02:16 UTC 2022
Hello from the Kubernetes cluster
删除 CronJob:
kubectl delete cronjob hello