在实际使用时,不会创建 Pod 运行应用,而是使用更高级的控制器进行调度,比如 ReplicaSet、 Deployment、 StatefulSet、DaemonSet 等。
1.1 无状态应用管理 Deployment
1.1.1 什么是 Deployment
Deployment 是一种用于定义 Pod 模板和控制 Pod 副本数量的资源对象。Deployment 可以确保指定数量的 Pod 始终在运行,并且可以实现滚动更新和回滚操作,以便进行应用程序的无缝更新和版本管理。一般用于部署公司的无状态服务,这个也是最常用的控制器,因为企业内部现在都是以微服务为主,而微服务实现无状态化也是最佳实践。
Deployment 的主要特点和功能:
- Pod 模板:
- Deployment 定义了一个 Pod 模板,其中包含容器镜像、环境变量、卷挂载等信息。根据这个模板,Deployment 会创建并管理多个 Pod 实例。
- 副本控制:
- Deployment 控制着 Pod 的副本数量,可以确保始终有指定数量的 Pod 在运行。如果某个 Pod 意外终止,Deployment 会自动创建新的 Pod 来替代。
- 滚动更新:
- 通过 Deployment,可以实现应用程序的滚动更新。您可以更新 Deployment 的 Pod 模板,然后 Deployment 会逐步替换现有的 Pod 实例,确保应用程序在更新过程中保持可用性。
- 回滚操作:
- 如果更新导致问题或错误,您可以使用 Deployment 进行回滚操作。Deployment 允许您回退到先前的版本,恢复应用程序的稳定状态。
- 扩展和收缩:
- 通过调整 Deployment 的副本数量,可以实现应用程序的水平扩展和收缩。根据负载情况,您可以增加或减少 Pod 的数量来满足需求。
1.1.2 创建 Deployment
1. 创建
创建一个 Kubernetes Deployment 的 YAML 文件:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
spec:
replicas: 2
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- image: nginx:1.22.1
name: nginx
ports:
- containerPort: 80 # 暴露的端口
在命令行中,使用 kubectl 命令来创建 Deployment:
kubectl apply -f nginx-deployment.yaml
2. 查看状态
使用 kubectl get 查看此 Deployment 的状态:
[root@master-01 deploy]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-dep 2/2 2 2 4m8s
- NAME:Deployment 的名称。
- READY:表示当前就绪的 Pod 数量与期望数量的比例,例如
2/2表示期望有 2 个 Pod 且都已就绪。 - UP-TO-DATE:当前更新的 Pod 数量,与期望数量一致,表示有多少个 Pod 已根据最新的配置更新。
- AVAILABLE:当前可用的 Pod 数量,表示可以接收流量的 Pod。
- AGE:Deployment 创建的时间,显示 Deployment 存在的时长。
使用 kubectl describe 查看 Deployment 的详细信息。可以用它来查看详细状态、事件、标签等信息。
[root@master-01 deploy]# kubectl describe deployment nginx-dep
Name: nginx-dep
Namespace: default
CreationTimestamp: Fri, 11 Oct 2024 22:40:17 +0800
Labels: app=nginx-dep
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx-dep
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx-dep
Containers:
nginx:
Image: nginx:1.22.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-dep-84cf9d78f9 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-dep-84cf9d78f9 to 2
Events 部分事件记录了资源状态的变化:
- Type:事件的类型,通常是
Normal或Warning。Normal表示正常的状态变化,而Warning表示可能存在问题或异常情况。 - Reason:事件的原因,描述发生了什么情况。例如,可以是
Scheduled(Pod 被调度到节点上)、Started(容器启动)、Failed(容器失败)等。 - Age:事件的时间,表示该事件自发生以来的时长。
- From:事件的来源,通常是生成事件的组件或控制器。例如,
kubelet表示该事件由节点的 kubelet 生成。 - Message:事件的详细信息,提供有关事件的具体描述,例如为什么 Pod 被驱逐,或者为什么容器失败等。
3. Deployment 控制 Pod
[root@master-01 deploy]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-dep 2/2 2 2 6m18s
[root@master-01 deploy]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-dep-84cf9d78f9 2 2 2 6m28s
[root@master-01 deploy]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-dep-84cf9d78f9-b5849 1/1 Running 0 6m32s
nginx-dep-84cf9d78f9-sz6br 1/1 Running 0 6m32s
- Deployment 创建和管理 ReplicaSet。
- ReplicaSet 管理 Pod,确保按照 Deployment 的要求运行相应数量的 Pod。
- Pod 是最终承载应用的单位。
1.1.3 更新 Deployment
通过 Deployment 部署应用后,经常会有 Deployment 文件的配置更改或者镜像版本迭代的需求,更改配置后该 Deployment 会创建新的 RepliaSet ,之后会对管理的 Pod 进行滚动升级。
注意事项:当且仅当 Deployment 的 Pod 模板更改时,才会触发 Deployment 的更新。
1. 创建新的 YAML 文件
我们更新 Deployment 的镜像为 nginx:1.24.1
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
spec:
replicas: 2
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- image: nginx:latest #新版本修改镜像,latest为最新版
name: nginx
ports:
- containerPort: 80 # 暴露的端口
2. 更新
使用 kubectl apply -f newfile 更新:
[root@master-01 deploy]# kubectl apply -f nginx-deploy-2.yaml
deployment.apps/nginx-dep configured
当然,也可以通过kubectl edit 直接对 Deployment 进行修改,但是不利于文件版本的管理。
3. 更新过程描述
[root@master-01 deploy]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-dep-77d74b887d 2 2 2 3m
nginx-dep-84cf9d78f9 0 0 0 3m51s
当触发一个更新后,会有新的 RepliaSet 产生,旧的 ReplicaSet 会被保存,可以从 AGE 看出新旧 ReplicaSet。
[root@master-01 deploy]# kubectl describe deployment nginx-dep |grep -i events -A 10
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 4m2s deployment-controller Scaled up replica set nginx-dep-84cf9d78f9 to 2
Normal ScalingReplicaSet 3m11s deployment-controller Scaled up replica set nginx-dep-77d74b887d to 1
Normal ScalingReplicaSet 3m9s deployment-controller Scaled down replica set nginx-dep-84cf9d78f9 to 1
Normal ScalingReplicaSet 3m9s deployment-controller Scaled up replica set nginx-dep-77d74b887d to 2
Normal ScalingReplicaSet 3m8s deployment-controller Scaled down replica set nginx-dep-84cf9d78f9 to 0
通过 describe 可以看出:
-
最初,ReplicaSet
nginx-dep-84cf9d78f9的副本数被增加到 2。 -
执行更新后,ReplicaSet
nginx-dep-77d74b887d的副本数被增加到 1。 -
之后,ReplicaSet
nginx-dep-84cf9d78f9的副本数减少到 1。 -
接着,ReplicaSet
nginx-dep-77d74b887d的副本数再次增加到 2。 -
最后,ReplicaSet
nginx-dep-84cf9d78f9的副本数减少到 0,这意味着所有相关的 Pod 已被终止,所有 Pod 已被更新为新版本。
4. 更新过程中暂停和继续
在应用更新的过程中,我们可以随时暂停更新,执行一些验证操作,如果确认没问题,再继续更新。
-
暂停更新:使用
kubectl rollout pause deployment <deployment-name>可以临时停止正在进行的滚动更新。这使你可以在不影响当前运行状态的情况下,检查和修改 Pod 配置或其他资源。 -
进行检查和验证:在暂停状态下,可以检查当前 Pod 的状态、日志和事件,确认应用的运行状况,或者进行必要的修改。
-
恢复更新:如果确认一切正常,可以使用
kubectl rollout resume deployment <deployment-name>来恢复更新,继续进行之前的滚动更新过程。
1.1.4 回滚 Deployment
当更新的版本不稳定或配置不合理时,可以对其进行回滚操作。
为了模拟实际环境,我们在进行几次更新(每次更新修改镜像)。
1. 查看历史信息
使用 kubectl rollout history 查看更新历史:
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep
deployment.apps/nginx-dep
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
4 <none>
可以使用 --revision 指定某次更新的版本号查看详细信息:
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep --revision=3
deployment.apps/nginx-dep with revision #3
Pod Template:
Labels: app=nginx-dep
pod-template-hash=6647547bb
Containers:
nginx:
Image: bitnami/nginx
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep --revision=4
deployment.apps/nginx-dep with revision #4
Pod Template:
Labels: app=nginx-dep
pod-template-hash=67d7895dcb
Containers:
nginx:
Image: nginx/nginx-ingress
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
2. 回滚到上一个版本
使用 kubectl rollout undo 即可:
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep
deployment.apps/nginx-dep
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
4 <none>
[root@master-01 deploy]# kubectl rollout undo deployment nginx-dep
deployment.apps/nginx-dep rolled back
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep
deployment.apps/nginx-dep
REVISION CHANGE-CAUSE
1 <none>
2 <none>
4 <none>
5 <none>
每次 Deployment 更新都会生成一个新的修订号(revision number)。而修订号在 Kubernetes 中是一个递增的整数。回滚操作不会生成新的修订号,因此在回滚后,你将看到更新历史中原有的修订号。即 1234 变成 1245,就是代表从4版本回滚到3版本。
3. 回滚到指定版本
使用 --to-reversion 可以回滚到任意版本:
[root@master-01 deploy]# kubectl rollout undo deployment nginx-dep --to-revision=1
deployment.apps/nginx-dep rolled back
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep
deployment.apps/nginx-dep
REVISION CHANGE-CAUSE
2 <none>
4 <none>
5 <none>
6 <none>
7 <none>
4. 添加更新描述
kubectl rollout history 的版本列表好像有点太简单了呢?只有一个版本更新序号,而另一列 CHANGE-CAUS 总是显示成 <none> ,能不能加上说明信息,当然是只可以的,只需要在 Deployment 的 YAML 文件中 metadata.annotations 里加上一个新的字段kubernetes.io/change-cause 即可。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
annotations:
kubernetes.io/change-cause: version=v9
spec:
replicas: 2
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- image: rancher/nginx #新版本修改镜像,latest为最新版
name: nginx
ports:
- containerPort: 80 # 暴露的端口
[root@master-01 deploy]# kubectl rollout history deployment nginx-dep
deployment.apps/nginx-dep
REVISION CHANGE-CAUSE
4 <none>
5 <none>
6 <none>
7 <none>
8 version=v9
1.1.5 Deployment 扩缩容
Deployment 扩缩容是指增加或减少正在运行的 Pod 副本数量,以满足不同的负载需求。以下是如何进行扩缩容的步骤:
1. 扩容(增加副本数)
-
使用
kubectl scale命令
可以直接使用命令增加副本数。例如,将nginx-dep的副本数增加到 5:kubectl scale deployment nginx-dep --replicas=5 -
使用
kubectl edit命令
通过编辑 Deployment,修改spec.replicas的值:kubectl edit deployment nginx-dep然后修改
spec.replicas为所需的副本数。 -
更新 YAML 文件
如果你有 Deployment 的 YAML 文件,可以在其中修改spec.replicas,然后运行:kubectl apply -f <your-deployment-file>.yaml
2. 缩容(减少副本数)
缩容的步骤与扩容类似,主要是将 --replicas 参数改为所需的较小值。
3. 注意事项
- 确保在扩缩容时考虑到应用的性能和资源限制。
- 确保集群中的节点有足够的资源来支持新增的副本。
4. 动态扩容容方案 HPA
这部分内容放在 09- Kubernetes 高级调度中。
1.1.6 更新 Deployment 的注意事项
1. 历史版本清理策略
在默认情况下,revision 保留10个旧的 ReplicaSet ,其余的将在后台进行垃圾回收(也就是说保留10个版本),可以在 .spec.revisionHistoryLimit 设置版本数量。
2. 更新策略
.spec.strategy.type 是 Kubernetes Deployment 中用于定义更新策略的字段。它决定了如何处理 Pod 的更新,主要有以下两种类型:
RollingUpdate:这是默认的更新策略。它允许逐个替换旧的 Pod,以确保在更新过程中始终有可用的 Pod。Recreate:这种策略首先会终止所有旧的 Pod,然后再创建新的 Pod。
.spec.strategy.rollingUpdate.maxUnavailable 是 Kubernetes Deployment 中的一个字段,用于定义在滚动更新期间,允许不可用的 Pod 的最大数量或比例。默认为25%,可以设置为数字或百分比。
.spec.strategy.rollingUpdate.maxSurge 是 Kubernetes Deployment 中的一个字段,用于定义在滚动更新期间,允许额外创建的 Pod 的最大数量或比例。默认情况下,maxSurge的值为25%。例如,如果你的副本数为4,maxSurge设置为1,则在滚动更新期间,可以同时创建新旧 5个Pod。
3. Ready 策略
.spec.minReadySeconds 是 Kubernetes Deployment 中的一个字段,用于指定 Pod 在被视为就绪之前,必须处于运行状态的最短时间(以秒为单位)。默认为0,即一旦被创建就视为可用,通常和容器探针联用。
附录 Deployment YAML文件案例
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-dep
name: nginx-dep
annotations:
kubernetes.io/change-cause: version=v9
spec:
replicas: 2
selector:
matchLabels:
app: nginx-dep
template:
metadata:
labels:
app: nginx-dep
spec:
containers:
- image: rancher/nginx:latest
name: nginx
ports:
- containerPort: 80
resources:
requests:
cpu: "100m" # 请求 100m CPU
memory: "256Mi" # 请求 256Mi 内存
limits:
cpu: "200m" # 限制最大使用 200m CPU
memory: "512Mi" # 限制最大使用 512Mi 内存
readinessProbe:
httpGet:
path: / # 根据你的应用设置路径
port: 80
initialDelaySeconds: 5 # 探针首次被执行之前的延迟时间(s)
periodSeconds: 10 # 针每次执行之间的间隔时间(s)
livenessProbe:
httpGet:
path: /health # 根据你的应用设置健康检查路径
port: 80
initialDelaySeconds: 15
periodSeconds: 20
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 在更新期间,最多允许一个 Pod 不可用
maxSurge: 1 # 在更新期间,最多允许多出一个 Pod
revisionHistoryLimit: 10 # 保留最近的 10 个版本
1.2 守护进程集 DaemonSet
1.2.1 什么是 DaemonSet
DaemonSet (缩写为 ds )是 Kubernetes 中一种 Pod 控制器,与Deployment和 ReplicaSet 等控制器不同,DaemonSet 不会根据副本数来管理Pod的数量,而是确保在每个节点上都运行一个Pod实例。
DaemonSet非常适合在每个节点上运行系统级别的任务:
- 网络应用(如 kube-proxy),必须每个节点都运行一个 Pod,否则节点就无法加入Kubernetes 网络。
- 监控应用(如 Prometheus-exporter),必须每个节点都有一个 Pod 用来监控节点的状态,实时上报信息。
- 日志应用(如 Filebeat),必须在每个节点上运行一个 Pod,才能够搜集容器运行时产生的日志数据。
- 安全应用,同样的,每个节点都要有一个 Pod 来执行安全审计、入侵检查、漏洞扫描等工作。
1.2.2 创建 DaemonSet
创建一个 DaemonSet 和 Deployment 类似,需要先编写一个 YAML 文件,比如创建一个 node-exporter 的 DaemonSset:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter-ds
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
containers:
- name: node-exporter
image: bitnami/node-exporter:1.6.1
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
我们比较一下Daemonset和Deployment的YAML就会看到,DaemonSet 在 spec 里没有 replicas 字段,这是它与Deployment 的一个关键不同点,意味着它不会在集群里创建多个 Pod 副本。
kubectl apply -f exporter-ds.yaml
1.2.3 DaemonSet 的管理
DaemonSet 的创建、更新和回滚操作与 Deployment 都是相似的。
1.3 有状态应用管理 StatefulSet
有状态应用是指那些在运行过程中需要保留和管理状态信息的应用。这种状态信息可能包括用户数据、会话信息、或者其他需要在不同请求之间持久化的数据。有状态应用通常依赖于外部存储(如数据库、文件系统等)来存储这些信息,以便在服务重启或扩展时能够恢复状态。比如 Redis、MySQL 这样的数据库,它们的“状态”就是在内存或者磁盘上产生的数据,是应用的核心价值所在,如果不能够把这些数据及时保存再恢复,那绝对会是灾难性的后果。
1.3.1 什么是 StatefulSet
StatefulSet (缩写为 sts),是 Kubernetes 中的一种控制器类型,用于管理有状态应用程序的部署和运行。与 Deployment 控制器不同,StatefulSet 控制器为每个 Pod 分配一个唯一的标识符,并且对这些 Pod 进行有序部署和扩展。这使得 StatefulSet 特别适用于需要稳定的持久化存储、网络标识或稳定的网络主机名的应用程序,如数据库、消息队列等。
StatefulSet 的一些特点和优势:
-
稳定的网络标识和主机名: StatefulSet 为每个 Pod 提供了稳定的标识符,其名称基于其在 StatefulSet 中的索引。这使得应用程序可以依赖于特定的网络标识和主机名,有助于实现有状态应用程序的稳定性。
-
有序部署和扩展: StatefulSet 保证它管理的 Pod 按照定义的顺序进行部署和扩展,这对于需要有序启动或者有序扩展的应用程序非常重要,例如数据库集群。
-
持久化存储: StatefulSet 可以与持久卷 (Persistent Volume) 结合使用,为每个 Pod 提供稳定的、持久的存储。
1.3.2 创建 StatefulSet
以下是一个 StatefulSet 的YAML 文件示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv-0
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/redis
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv-1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/redis
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-sts
spec:
serviceName: redis-hd-svc
replicas: 2
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: redis-pv
mountPath: /data
volumeClaimTemplates:
- metadata:
name: redis-pv
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: redis-hd-svc
spec:
clusterIP: None # 无头服务
selector:
app: redis
ports:
- name: redis-port # 给端口设置一个名称
port: 6379
targetPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-svc
spec:
selector:
app: redis
ports:
- name: redis-port # 给端口设置一个名称
port: 6379
targetPort: 6379
在写 Service 对象的时候要小心一些,metadata.name 必须和 StatefulSet 里的 serviceName 相同,selector 里的标签也必须和 StatefulSet 里的一致。
注意事项:本案例使用本地存储的 pv 作为 sts 的数据持久化的存储卷,这样做就会使得 sts 管理的 pod 调度到哪个节点,哪个节点上就会创建一个 pv 存储卷。
虽然 sts 为了保持一些持久性存储(如 PV)的稳定性以及保留一些应用程序级别的状态,确实提供了一些机制来尽量确保在 Pod 被删除或重新调度时,它们会尽可能地调度到原来的节点上。但并不保证在所有情况下都能将 Pod 调度到原来的节点上,这可能受到节点资源的限制、调度器的策略以及其他集群中的因素影响。而一旦 pod 调度到其他的节点,绑定一个新节点的 pv,就会读取不到之前 pv 的数据,不利于数据的管理和使用,也不符合 sts 作为有状态应用管理器的初衷。生产环境更推荐使用易于管理的网络存储,如 Ceph。
1.3.3 StatefulSet 的管理
StatefulSet 的创建、更新和回滚操作与 Deployment 都是相似的,这里不在赘述。
1.3.4 StatefulSet 的特性
1. 有序部署
StatefulSet 管理的 Pod 具有唯一的、有序的名称。通过这种顺序编号,Kubernetes 确保 Pod 按照指定的顺序启动和终止,解决了有状态应用在启动和升级过程中的依赖关系问题。例如,redis-sts-0 会在 redis-sts-1 之前启动,这样可以确保应用的依赖性得到满足。
[root@master-01 ~]# kubectl get sts
NAME READY AGE
redis-sts 2/2 17m
[root@master-01 ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-sts-0 1/1 Running 0 17m 10.20.171.31 worker-01 <none> <none>
redis-sts-1 1/1 Running 0 17m 10.20.171.32 worker-01 <none> <none>
2. 网络标识
对比 Deployment 、DaemonSet ,StatefulSet 中存在一个 serviceName 字段。这个字段用来指定与 StatefulSet 关联的 Headless Service,以便为 StatefulSet 的 Pods 提供网络标识。
在 StatefulSet 中,由于每个 Pod 拥有唯一且固定的名称,因此可以为每个 Pod 分配一个稳定的域名,格式为“Pod 名. 服务名. 命名空间.svc.cluster.local” 。这使得在网络通信中能够更方便地访问每个 Pod。例如,对于名为 redis-sts 的 StatefulSet(前提是创建并绑定了 Service),Pod redis-sts-0 的域名就是redis-sts-0.redis-hd-svc.default.svc.cluster.local。
[root@master-01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.112.0.1 <none> 443/TCP 200d
redis-headless-svc ClusterIP None <none> 6379/TCP 3m25s
[root@master-01 ~]# kubectl describe svc redis-headless-svc
Name: redis-headless-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=redis
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: redis-port 6379/TCP
TargetPort: 6379/TCP
Endpoints: 10.20.171.31:6379,10.20.171.32:6379
Session Affinity: None
Events: <none>
[root@master-01 ~]# kubectl describe svc redis-svc
Name: redis-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=redis
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.100.16.52
IPs: 10.100.16.52
Port: redis-port 6379/TCP
TargetPort: 6379/TCP
Endpoints: 10.244.171.31:6379,10.244.171.32:6379
Session Affinity: None
Events: <none>
[root@master-01 ~]# kubectl exec -it redis-sts-0 -- sh
/data # nslookup redis-sts-0.redis-hd-svc.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: redis-sts-0.redis-hd-svc.default.svc.cluster.local
Address: 10.244.171.31
/data # nslookup redis-sts-1.redis-hd-svc.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: redis-sts-1.redis-hd-svc.default.svc.cluster.local
Address: 10.244.171.32
/data #
什么是无头服务
Service 原本的目的是负载均衡,应该由它在 Pod 前面来转发流量,但是对 StatefulSet 来说,这项功能反而是不必要的,因为 Pod 已经有了稳定的域名,外界访问服务就不应该再通过 Service 这一层了。所以,从安全和节约系统资源的角度考虑,我们可以在 Service 里添加一个字段 clusterIP: None ,告诉 Kubernetes 不必再为这个对象分配 IP 地址。这种类型的 Service 对象也被称为 Headless Services (无头服务 )。
5. 实现数据持久化
StatefulSet 有个特定的字段 volumeClaimTemplates ,用于定义持久卷声明(PersistentVolumeClaim),以便为每个 Pod 创建独立的存储,以支持有状态应用。
1.4 运行离线任务 Job
“离线业务”类型的应用通常只针对内部用户,例如日志分析、数据建模、视频转码等场景。尽管这些任务计算量很大,但它们会在一段时间后完成,特点是必定会退出,不会无期限运行。因此,离线业务的调度策略与在线业务大相径庭,需考虑运行超时、状态检查、失败重试和结果获取等管理事项。
离线业务可分为两类:一类是“临时任务”,完成后即结束,下次有需求时再重新安排;另一类是“定时任务”,可以按预定周期定时运行,且无需频繁干预。
在 Kubernetes 中,“临时任务”对应控制器 Job ,而“定时任务”对应控制器CronJob。通过这两个对象,可以高效调度和管理任意离线业务。
1.4.1 创建 Job
1. 定义 Job
apiVersion: batch/v1
kind: Job
metadata:
name: sleep-job
spec:
activeDeadlineSeconds: 30
backoffLimit: 2
completions: 4
parallelism: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: echo-job
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- sleep $(($RANDOM % 10 + 1)) && echo done
- activeDeadlineSeconds,设置 Pod 运行的超时时间。
- backoffLimit,设置 Pod 的失败重试次数。
- completions,Job 完成需要运行多少个 Pod,默认是 1 个。
- parallelism,它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源。
这个配置文件定义了一个 Job,该 Job 会创建 4 个 Pod,每次并行运行 2 个 Pod,每个 Pod 中的容器将随机休眠一段时间后输出 "done"。如果有任何 Pod 在 30 秒内无法完成,它们将被终止;失败的 Pod 最多会重试 2 次。
2. 创建 Job
在命令行使用以下命令,创建 Job:
kubectl apply -f job.yaml
3. 状态
[root@master-01 ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
sleep-job 4/4 18s 65s
[root@master-01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
sleep-job-8xzhc 0/1 Completed 0 57s
sleep-job-9bdvn 0/1 Completed 0 67s
sleep-job-jh986 0/1 Completed 0 60s
sleep-job-r6dlr 0/1 Completed 0 67s
[root@master-01 ~]#
以下是对 Kubernetes Job 和 Pod 状态的解释:
-
Job 状态:
- NAME: Job 的名称是
sleep-job。 - COMPLETIONS:
4/4表示该 Job 期望完成的任务数量是 4,并且所有 4 个任务都已成功完成。 - DURATION: Job 总共运行的时间为 18 秒。
- AGE: Job 已经存在的时间为 65 秒。
- NAME: Job 的名称是
-
Pod 状态:
- NAME: 列出与 Job 相关的 Pods 名称。
- READY:
0/1表示每个 Pod 只包含一个容器,而该容器的状态是“已完成”,所以“就绪”状态为 0。 - STATUS:
Completed表示这些 Pods 已经成功完成它们的任务。 - RESTARTS:
0表示 Pods 没有重启过。 - AGE: Pods 已存在的时间,分别为 57 秒到 67 秒。
总体来说,这些输出表明你的 Job sleep-job 已成功执行了 4 次,并且所有相关的 Pods 都已经完成了它们的任务。
1.4.2 创建 CronJob
1. 定义 Cronjob
apiVersion: batch/v1
kind: CronJob
metadata:
name: echo-hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: echo-cj
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/echo"]
args: ["hello", "world"]
schedule 字段定义了调度周期,它使用的是标准的 Cron 语法,指定分钟、小时、日、月、周,和 Linux 上的 crontab 是一样的。像在这里我就指定每分钟运行一次。
2. 创建 CronJob
kubectl apply -f cj.yaml
3. 状态
[root@master-01 ~]# kubectl get cj
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
echo-hello */1 * * * * False 0 22s 3m
[root@master-01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
echo-hello-28815277-4gfjh 0/1 Completed 0 60s
echo-hello-28815278-n2qlk 0/1 ContainerCreating 0 0s
根据你提供的输出,以下是对当前 CronJob 和 Pods 状态的解释:
-
CronJob 状态:
- NAME: CronJob 名称为
echo-hello。 - SCHEDULE: 每分钟运行一次。
- SUSPEND:
False表示 CronJob 处于激活状态。 - ACTIVE:
0表示当前没有活动的 Job。 - LAST SCHEDULE:
32s表示上一次调度发生在 32 秒前。 - AGE: CronJob 已存在 4 分钟 10 秒。
- NAME: CronJob 名称为
-
Pod 状态:
- NAME: 列出与 CronJob 相关的 Pods 名称。
- READY: 所有 Pods 状态为
0/1,表示它们已完成但不再运行。 - STATUS: 所有 Pods 状态均为
Completed,表示任务已成功完成。 - RESTARTS:
0表示这些 Pods 没有重启过。 - AGE: Pods 的存在时间,分别为 2 分 34 秒、94 秒和 34 秒。
总结来说,echo-hello CronJob 在预定时间内成功创建并完成了多个 Pods,目前没有正在运行的活动 Job。
评论区