ReplicaSet
是kubernetes中的一种副本控制器,简称rs
,主要作用是控制由其管理的pod,使pod副本的数量始终维持在预设的个数。它的主要作用就是保证一定数量的Pod能够在集群中正常运行,它会持续监听这些Pod的运行状态,在Pod发生故障时重启pod,pod数量减少时重新运行新的 Pod副本。官方推荐不要直接使用ReplicaSet,用Deployments取而代之,Deployments是比ReplicaSet更高级的概念,它会管理ReplicaSet并提供很多其它有用的特性,最重要的是Deployments支持声明式更新,声明式更新的好处是不会丢失历史变更。所以Deployment控制器不直接管理Pod对象,而是由 Deployment 管理ReplicaSet,再由ReplicaSet负责管理Pod对象。
Replication Controller(简称 RC)可确保 Pod 副本数达到期望值,也就是 RC 定义的数量。 换句话说,Replication Controller 可确保一个 Pod 或一组同类 Pod 总是可用。
如果存在的 Pod 大于设定的值,则 Replication Controller 将终止额外的 Pod。如果太小, Replication Controller 将启动更多的 Pod 用于保证达到期望值。与手动创建 Pod 不同的是,用 Replication Controller 维护的 Pod 在失败、删除或终止时会自动替换。因此即使应用程序只需要 一个 Pod,也应该使用 Replication Controller 或其他方式管理。Replication Controller 类似于进程 管理程序,但是 Replication Controller 不是监视单个节点上的各个进程,而是监视多个节点上的 多个 Pod。
Deployment一般用于部署公司的无状态服务,这个也是最常用的控制器,因为企业内部现在都是以微服务为主,而微服务实现无状态化也是最佳实践,可以利用Deployment的高级功能做到无缝迁移、自动扩容缩容、自动灾难恢复、一键回滚等功能
使用Deployment而不直接创建ReplicaSet是因为Deployment对象拥有许多ReplicaSet没有的特性,例如滚动升级和回滚。使用Deployment来管理ReplicaSet,然后在用ReplicaSet来管理pod
一个Kubernetes集群,包含多个节点。中间是一名开发者,他在笔记本电脑上编写一个deployment的YAML文件。YAML文件定义了一个简单的nginx deployment,指定了replicas数为3。
然后这名开发者使用kubectl apply命令将deployment YAML文件应用到Kubernetes集群中。图片右边显示了这个deployment创建的过程:
首先deployment controller根据replicas数创建了3个pod。这3个pod分布在集群的不同节点上。
每个pod里都运行了一个nginx容器。deployment controller会确保一直维持3个pod处于运行状态。
如果有pod死掉,deployment会自动创建新的pod来替代;如果节点死掉,deployment会将pod重新调度到其他节点。
这样deployment可以提供一个稳定的pod数量,实现应用的高可用。
命令创建
kubectl create deployment nginx --image=nginx
文件声明
从 Kubernetes 1.16 版本开始,彻底废弃了其他的 APIVersion,只能使用 apps/v1, 1.16 以下的版本可以使用 extension 等。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.12
ports:
- containerPort: 80
示例解析:
1. nginx-deployment:Deployment的名称;
2. replicas: 创建Pod的副本数;
3. selector:定义Deployment如何找到要管理的Pod,与template的label(标签)对应,apiVersion 为apps/v1必须指定该字段;
4. template字段包含以下字段:
- app: nginx使用label(标签)标记Pod;
- spec:表示Pod运行一个名字为nginx的容器
- image:运行此Pod使用的镜像;
- Port:容器用于发送和接收流量的端口。
使用 kubectl create 创建此 Deployment:
# kubectl create -f dp-nginx.yaml
deployment.apps/nginx-deployment created
使用 kubectl get 或者 kubectl describe 查看此 Deployment 的状态:
# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 0/3 3 0 8s
➢ NAME:集群中Deployment的名称;
➢ READY:Pod就绪个数和总副本数;
➢ UP-TO-DATE:显示已达到期望状态的被更新的副本数;
➢ AVAILABLE:显示用户可以使用的应用程序副本数,当前为0,说明目前还没有达到期望的Pod;
➢ AGE:显示应用程序运行的时间。
可以使用 rollout 命令查看整个 Deployment 创建的状态:
# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out
当 rollout 结束时,再次查看此 Deployment,可以看到 AVAILABLE 的数量和 yaml 文件中定义的 replicas 相同:
# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 10m
查看此 Deployment 当前对应的 ReplicaSet:
# kubectl get rs -l app=nginx
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c689d88bb 3 3 3 12m
➢ DESIRED:应用程序副本数;
➢ CURRENT:当前正在运行的副本数;
当 Deployment 有过更新,对应的 RS 可能不止一个,可以通过-o yaml 获取当前对应的 RS 是哪个,其余的 RS 为保留的历史版本,用于回滚等操作。
查看此 Deployment 创建的 Pod,可以看到 Pod 的 hash 值 5c689d88bb 和上述 Deployment 对应的 ReplicaSet 的 hash 值一致:
# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-5c689d88bb-6b95k 1/1 Running 0 13m app=nginx,pod-template-hash=5c689d88bb
nginx-deployment-5c689d88bb-9z5z2 1/1 Running 0 13m app=nginx,pod-template-hash=5c689d88bb
nginx-deployment-5c689d88bb-jc8hr 1/1 Running 0 13m app=nginx,pod-template-hash=5c689d88bb
当且仅当 Deployment 的 Pod 模板(即.spec.template)更改时,才会触发 Deployment 更新,例如更改内存、CPU 配置或者容器的 image。
假如更新 Nginx Pod 的 image 使用 nginx:latest,并使用–record 记录当前更改的参数,后期回滚时可以查看到对应的信息:
# kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record
deployment.extensions/nginx-deployment image updated
当然也可以使用 edit 命令直接编辑 Deployment,效果相同:
# kubectl edit deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment edited
同样可以使用 kubectl rollout status 查看更新过程:
# kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish:
1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish:
2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish:
2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish:
2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish:
1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish:
1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
可以看出更新过程为新旧交替更新,首先新建一个 Pod,当 Pod 状态为 Running 时,删除一个旧的 Pod,同时再创建一个新的 Pod。当触发一个更新后,会有新的 ReplicaSet 产生,旧的 ReplicaSet 会被保存,查看此时 ReplicaSet,可以从 AGE 或 READY 看出来新旧 ReplicaSet:
# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5c689d88bb 0 0 0 34m
nginx-deployment-6987cdb55b 3 3 3 5m14s
通过 describe 查看 Deployment 的详细信息:
# kubectl describe deploy nginx-deployment
Name: nginx-deployment
Namespace: default
...
OldReplicaSets:
NewReplicaSet: nginx-deployment-6987cdb55b (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 36m deployment-controller Scaled up replica set nginx-deployment-5c689d88bb to 3
Normal ScalingReplicaSet 7m16s deployment-controller Scaled up replica set nginx-deployment-6987cdb55b to 1
Normal ScalingReplicaSet 5m18s deployment-controller Scaled down replica set nginx-deployment-5c689d88bb to 2
Normal ScalingReplicaSet 5m18s deployment-controller Scaled up replica set nginx-deployment-6987cdb55b to 2
Normal ScalingReplicaSet 4m35s deployment-controller Scaled down replica set nginx-deployment-5c689d88bb to 1
Normal ScalingReplicaSet 4m34s deployment-controller Scaled up replica set nginx-deployment-6987cdb55b to 3
Normal ScalingReplicaSet 3m30s deployment-controller Scaled down replica set nginx-deployment-5c689d88bb to 0
在 describe 中可以看出,第一次创建时,它创建了一个名为 nginx-deployment-5c689d88bb 的 ReplicaSet,并直接将其扩展为 3 个副本。更新部署时,它创建了一个新的 ReplicaSet,命名为 nginx-deployment-6987cdb55b,并将其副本数扩展为 1,然后将旧的 ReplicaSet 缩小为 2,这样至少可以有 2 个 Pod 可用,最多创建了 4 个 Pod。以此类推,使用相同的滚动更新策略向上和向下扩展新旧 ReplicaSet,最终新的 ReplicaSet 可以拥有 3 个副本,并将旧的 ReplicaSet 缩小为 0。
当更新了版本不稳定或配置不合理时,可以对其进行回滚操作,假设我们又进行了几次更新 (此处以更新镜像版本触发更新,更改配置效果类似):
# 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 查看更新历史:
# kubectl rollout history deployment/nginx-deployment
REVISION CHANGE-CAUSE
1
2 kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
3 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
4 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
查看 Deployment 某次更新的详细信息,使用–revision 指定某次更新版本号:
# kubectl rollout history deployment/nginx-deployment --revision=3
deployment.apps/nginx-deployment with revision #3
Pod Template:
Labels: app=nginx
pod-template-hash=645959bf6b
Annotations: kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
Containers:
nginx:
Image: dotbalo/canary:v1
Port: 80/TCP
Host Port: 0/TCP
Environment:
Mounts:
Volumes:
如果只需要回滚到上一个稳定版本,使用 kubectl rollout undo 即可:
# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment
再次查看更新历史,发现 REVISION5 回到了 canary:v1:
# kubectl rollout history deployment/nginx-deployment
REVISION CHANGE-CAUSE
1
2 kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
4 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
5 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
如果要回滚到指定版本,使用–to-revision 参数:
# kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment.extensions/nginx-deployment
当公司访问量变大,或者有预期内的活动时,三个 Pod 可能已无法支撑业务时,可以提前对其进行扩展。
使用 kubectl scale 动态调整 Pod 的副本数,比如增加 Pod 为 5 个:
# kubectl scale deployment.v1.apps/nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled
查看 Pod,此时 Pod 已经变成了 5 个:
# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-5f89547d9c-5r56b 1/1 Running 0 90s
nginx-deployment-5f89547d9c-htmn7 1/1 Running 0 25s
nginx-deployment-5f89547d9c-nwxs2 1/1 Running 0 99s
nginx-deployment-5f89547d9c-rpwlg 1/1 Running 0 25s
nginx-deployment-5f89547d9c-vlr5p 1/1 Running 0 95s
上述演示的均为更改某一处的配置,更改后立即触发更新,大多数情况下可能需要针对一个资源文件更改多处地方,而并不需要多次触发更新,此时可以使用 Deployment 暂停功能,临时禁用更新操作,对 Deployment 进行多次修改后在进行更新。
使用 kubectl rollout pause 命令即可暂停 Deployment 更新:
# kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused
然后对 Deployment 进行相关更新操作,比如先更新镜像,然后对其资源进行限制(如果使用的是 kubectl edit 命令,可以直接进行多次修改,无需暂停更新,kubectl set 命令一般会集成在 CICD 流水线中):
# kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated
# kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.apps/nginx-deployment resource requirements updated
通过 rollout history 可以看到没有新的更新:
# kubectl rollout history deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1
5 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
7 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
8 kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
进行完最后一处配置更改后,使用 kubectl rollout resume 恢复 Deployment 更新:
# kubectl rollout resume deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment resumed
可以查看到恢复更新的 Deployment 创建了一个新的 RS(ReplicaSet 缩写):
# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-57895845b8 5 5 4 11s
可以查看 Deployment 的 image(镜像)已经变为 nginx:1.9.1
# kubectl describe deploy nginx-deployment
Name: nginx-deployment
Namespace: default
...
Annotations: deployment.kubernetes.io/revision: 9
kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
Selector: app=nginx
Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Here are some key points about updating Deployments formatted as Markdown:
历史版本清理策略:
在默认情况下,revision 保留 10 个旧的 ReplicaSet,其余的将在后台进行垃圾回收,可以在 .spec.revisionHistoryLimit
设置保留 ReplicaSet 的个数。当设置为 0 时,不保留历史记录。
更新策略:
.spec.strategy.type==Recreate
,表示重建,先删掉旧的Pod再创建新的Pod;.spec.strategy.type==RollingUpdate
,表示滚动更新,可以指定maxUnavailable
和maxSurge
来控制滚动更新过程;
.spec.strategy.rollingUpdate.maxUnavailable
,指定在回滚更新时最大不可用的Pod数量,可选字段,默认为25%,可以设置为数字或百分比,如果maxSurge
为0,则该值不能为0;.spec.strategy.rollingUpdate.maxSurge
可以超过期望值的最大Pod数,可选字段,默认为25%,可以设置成数字或百分比,如果maxUnavailable
为0,则该值不能为0。Ready 策略:
.spec.minReadySeconds
是可选参数,指定新创建的 Pod 应该在没有任何容器崩溃的情况下视为 Ready(就绪)状态的最小秒数,默认为 0,即一旦被创建就视为可用,通常和容器探针连用。
StatefulSet(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余Spring Boot应用可以直接通过Eureka的Headless Service即可进行注册。
StatefulSet 的运行机制可以概括如下:
StatefulSet会确保部署的Pod按照定义的顺序逐个启动,例如web-0先启动,web-1后启动。
StatefulSet为每个Pod创建一个唯一的标识,这个标识跟Pod重启无关。
StatefulSet会确保一个Pod启动运行后,才会启动下一个Pod。
当Pod被删除时,StatefulSet不会自动重新创建该Pod,需要手动重建该Pod。
StatefulSet会自动为每个Pod创建和绑定一个PersistentVolume,如果Pod被重新调度到其他Node上,该Volume也会跟随它迁移。
StatefulSet支持滚动更新,可以控制更新的过程。
StatefulSet可以扩容或缩容Pod的副本数。
总的来说,StatefulSet通过唯一的Pod标识、启动顺序、稳定的网络标识等来维护有状态的应用,即使Pod被重新调度也可以保证应用状态的一致性。
下面详细介绍StatefulSet的一些关键特性:
稳定唯一的网络标识:每个Pod都会有一个稳定唯一的网络标识,格式为 ( s t a t e f u l s e t n a m e ) − (statefulset name)- (statefulsetname)−(ordinal),即web-0,web-1等。
启动顺序:Pod是按照{0,1,2}的顺序启动的,当web-0运行起来才会启动web-1,web-2。
按序终止:当删除Pod时,它会按照逆序进行终止,即web-2先停止,web-1再停止,web-0最后停止。
存储卷稳定:每个Pod绑定一个PVC,如果Pod被重启,存储卷还会重新挂载,数据不会丢失。
滚动更新:支持版本滚动更新,可以控制更新过程。
通过这些机制,StatefulSet可以很好地维护有状态应用的高可用。
和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod。不同的是,StatefulSet为每个Pod维护了一个粘性标识。而StatefulSet创建的Pod一般使用HeadlessService(无头服务)进行Pod之前的通信和普通的Service的区别在于Headless Service没有clusterlP,它使用的是Endpoint进行互相通信,Headless一般的格式为:
statefulSetName-fo…N-1.serviceName.namespace.svc.cluster.local
serviceName为HeadlessService的名字,创建StatefulSet时,必须指定HeadlessService名称;
0…N-1为Pod所在的序号,从0开始到N-1:
statefulSetName为StatefulSet的名字:
namespace为服务所在的命名空间;
.cluster.local为ClusterDomain(集群域)。
定义一个简单的 StatefulSet 的示例如下:
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:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
其中:
➢ kind: Service定义了一个名字为Nginx的Headless Service,创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似,因为没有指定Namespace(命名空间),所以默认部署在default;
➢ kind: StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2。
◆ 在 StatefulSet 中必须设置Pod选择器(.spec.selector)用于匹配其标签(.spec.template.metadata.labels)。在 1.8 版本之前,如果未配置该字段(.spec.selector),将被设置为默认值,在 1.8 版本之后,如果未指定匹配 Pod Selector,则会导致 StatefulSet 创建错误。
当 StatefulSet 控制器创建 Pod 时,它会添加一个标签 statefulset.kubernetes.io/pod-name,该标签的值为 Pod 的名称,用于匹配 Service。
创建 StatefulSet:
# kubectl create -f sts-web.yaml
# 也可以使用-n 部署到其他 namespace
service/nginx created
statefulset.apps/web created
查看创建的资源:
# kubectl get sts
NAME DESIRED CURRENT AGE
web 2 2 12s
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 7d2h
nginx ClusterIP None 80/TCP 16s
# kubectl get po -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2m5s
web-1 1/1 Running 0 115s
StatefulSet 管理的 Pod 部署和扩展规则如下:
StatefulSet 的 pod.Spec.TerminationGracePeriodSeconds
(终止 Pod 的等待时间)不应该指定为 0,设置为 0 对 StatefulSet 的 Pod 是极其不安全的做法,优雅地删除 StatefulSet 的 Pod 是非常有必要的,而且是安全的,因为它可以确保在 Kubelet 从 APIServer 删除之前,让 Pod 正常关闭。
当创建上面的 Nginx 实例时,Pod 将按 web-0、web-1、web-2 的顺序部署 3 个 Pod。在 web-0 处于 Running 或者 Ready 之前,web-1 不会被部署,相同的,web-2 在 web-1 未处于 Running 和 Ready 之前也不会被部署。如果在 web-1 处于 Running 和 Ready 状态时,web-0 变成 Failed(失败)状态,那么 web-2 将不会被启动,直到 web-0 恢复为 Running 和 Ready 状态。
如果用户将 StatefulSet 的 replicas 设置为 1,那么 web-2 将首先被终止,在完全关闭并删除 web-2 之前,不会删除 web-1。如果 web-2 终止并且完全关闭后,web-0 突然失败,那么在 web-0 未恢复成 Running 或者 Ready 时,web-1 不会被删除。
和 Deployment 类似,可以通过更新 replicas 字段扩容/缩容 StatefulSet,也可以使用 kubectl scale、kubectl edit 和 kubectl patch 来扩容/缩容一个 StatefulSet。
(1) 扩容
# kubectl scale sts web --replicas=5
statefulset.apps/web scaled
查看扩容后 Pod 的状态:
# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2m58s
web-1 1/1 Running 0 2m48s
web-2 1/1 Running 0 116s
web-3 1/1 Running 0 79s
web-4 1/1 Running 0 53s
也可使用以下命令动态查看:
kubectl get pods -w -l app=nginx
(2) 缩容
首先打开另一个终端动态查看缩容的流程:
# kubectl get pods -w -l app=nginx
在另一个终端将副本数改为 3(此处演示的为 patch 命令,patch 比 edit 和 scale 稍复杂):
# kubectl scale sts web --replicas=3
statefulset.apps/web scaled
# kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched
此时可以看到第一个终端显示 web-4 和 web-3 的 Pod 正在被有序的删除(或终止)。
(1) OnDelete 策略
OnDelete 更新策略实现了传统(1.7版本之前)的行为,它也是默认的更新策略。当我们选择这个更新策略并修改StatefulSet的 .spec.template
字段时,StatefulSet 控制器不会自动更新Pod,必须手动删除Pod才能使控制器创建新的Pod。
(2) RollingUpdate策略
RollingUpdate(滚动更新)更新策略会自动更新一个StatefulSet中的所有的Pod,采用与序号索引相反的顺序进行滚动更新。
# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched
然后改变容器的镜像触发滚动更新:
# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"dotbalo/canary:v1"}]'
statefulset.apps/web patched
在更新过程中可以使用 kubectl rollout status sts/
来查看滚动更新的状态。
比如我们定义一个分区"partition":3,可以使用 patch 或 edit 直接对 StatefulSet 进行设置:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 5
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"new-image"}]'
此时,序号大于或等于分区的Pod(3、4、5等)会被滚动更新到新版本
序号小于分区的Pod(0、1、2)不会被更新,仍然是旧版本
可以逐步将分区减小到0,以此将所有Pod更新到新版本
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":1}}}}'
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
通过这种分段的方式,可以实现类似金丝雀发布的效果,先在一部分实例上发布新版本,观察是否有问题再逐步扩大范围。
主要注意分区序号是与Pod的序号索引相比较,确定哪些Pod会被更新。这样可以精细控制更新的范围和顺序。
删除StatefulSet有两种方式,即级联删除和非级联删除。
(1) 非级联删除
使用 kubectl delete sts xxx 删除 StatefulSet 时,只需提供–cascade=false 参数,就会采用非级联删除,此时删除 StatefulSet 不会删除它的 Pod:
# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 16m
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 11m
# kubectl delete statefulset web --cascade=false # 采用非级联删除
statefulset.apps "web" deleted
# kubectl get sts # 查看此时 sts 已经被删除
No resources found.
# kubectl get po # 该 StatefulSet 管理的 Pod 并未被删除
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 16m
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 11m
由于此时删除了 StatefulSet,它管理的 Pod 变成了“孤儿”Pod,因此单独删除 Pod 时,该 Pod 不会被重建:
# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 16m
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 11m
# kubectl delete po web-0
pod "web-0" deleted
# kubectl get po
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 18m
web-2 1/1 Running 0 12m
再次创建 sts:
# kubectl apply -f sts-web.yaml
statefulset.apps/web created
# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 32s
web-1 1/1 Running 0 19m
(2) 级联删除
省略 --cascade=false
参数即为级联删除,会删除 StatefulSet 和它的 Pod。
也可以使用 -f
指定创建 StatefulSet 和 Service 的 yaml 文件,直接删除 StatefulSet 和 Service(此文件将 StatefulSet 和 Service 写在了一起)。
# kubectl delete statefulset web
statefulset.apps "web" deleted
# kubectl get po
No resources found.
# kubectl delete -f sts-web.yaml
service "nginx" deleted
Error from server (NotFound): error when deleting "sts-web.yaml":
statefulsets.apps "web" not found # 因为 StatefulSet 已经被删除,所以会提示该StatefulSet 不存在
DaemonSet(守护进程集,缩写为ds)和守护进程类似,它在符合匹配条件的节点上均部署一个Pol。当有新节点加入集群时,也会为它们新增一个Pod,当节点从集群中移除时,这些Pod也会被回收,删除DaemonSet将会删除它创建的所有Pod。
运行集群存储daemon(守护进程),例如在每个节点上运行Glusterd、Ceph等;
在每个节点运行日志收集daemon,例如Fluentd、Logstash;
在每个节点运行监控daemon,比如Prometheus Node Exporter、Collectd、Datadog代理、New Relic代理或 Ganglia gmond。
Here are the key points about DaemonSets formatted in Markdown:
创建一个 DaemonSet 和 Deployment 类似,比如创建一个 nginx 的 DaemonSet:
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: nginx
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.15.12
imagePullPolicy: IfNotPresent
name: nginx
(1)必需字段
和其他所有 Kubernetes 配置一样,DaemonSet 需要 apiVersion、kind 和 metadata 字段,同时也需要一个.spec 配置段。
(2)Pod 模板
.spec 唯一需要的字段是.spec.template。.spec.template 是一个 Pod 模板,它与 Pod 具有相同的配置方式,但它不具有 apiVersion 和 kind 字段。
除了 Pod 必需的字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签。
(3)Pod Selector
.spec.selector 字段表示 Pod Selector,它与其他资源的.spec.selector 的作用相同。
.spec.selector 表示一个对象,它由如下两个字段组成:
(4)指定节点部署 Pod
如果指定了.spec.template.spec.nodeSelector,DaemonSet Controller 将在与 Node Selector(节点选择器)匹配的节点上创建 Pod,比如部署在磁盘类型为 ssd 的节点上(需要提前给节点定义标签 Label):
nodeSelector:
disktype: ssd
比如创建一个 nginx:
# kubectl create -f nginx-ds.yaml
此时会在每个节点创建一个 Pod:
# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-6ssvl 1/1 Running 0 56s
nginx-8ddgd 1/1 Running 0 36s
nginx-cfx5d 1/1 Running 0 9s
nginx-k48bt 1/1 Running 0 46s
nginx-p84ng 1/1 Running 0 11s
使用 -o wide
可以查看 Pod 所在的节点时:
# kubectl get po -o wide
这里是关于更新和回滚 DaemonSet 的内容格式化后的 Markdown:
如果添加了新节点或修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加 Pod,同时删除不能匹配的节点上的 Pod。
在 Kubernetes 1.6 以后的版本中,可以在 DaemonSet 上执行滚动更新,未来的 Kubernetes版本将支持节点的可控更新。
DaemonSet 滚动更新可参考:https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/
DaemonSet 更新策略和 StatefulSet 类似,也有 OnDelete 和 RollingUpdate 两种方式。
查看上一节创建的 DaemonSet 更新方式:
# kubectl get ds nginx-ds -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'
RollingUpdate
命令式更新,和之前 Deployment、StatefulSet 方式一致
kubectl edit ds/
kubectl patch ds/ -p=
更新镜像
kubectl set image ds/= --record=true
查看更新状态
kubectl rollout status ds/
列出所有修订版本
kubectl rollout history daemonset
回滚到指定 revision
kubectl rollout undo daemonset --to-revision=
DaemonSet 的更新和回滚与 Deployment 类似,此处不再演示。
HPA全称是 Horizontal Pod Autoscaler,也就是对k8s的workload的副本数进行自动水平扩缩容(scale)机制,也是k8s里使用需求最广泛的一种Autoscaler机制,在开始详细介绍HPA之前,先简单梳理下k8s autoscale的整个大背景。
◆ HPA v1为稳定版自动水平伸缩,只支持CPU指标
◆ V2为beta版本,分为v2beta1(支持CPU、内存和自定义指标)
◆ v2beta2(支持CPU、内存、自定义指标Custom和额外指标ExternalMetrics)
从最基本的角度来看,Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例。
期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)]
扩容
如果计算出的扩缩比例接近 1.0, 将会放弃本次扩缩, 度量指标 / 期望指标接近1.0。
缩容
冷却/延迟: 如果延迟(冷却)时间设置的太短,那么副本数量有可能跟以前一样出现抖动。默认值是 5 分钟(5m0s)–horizontal-pod-autoscaler-downscale-stabilization
必须安装metrics-server或其他自定义metrics-server 不能扩容无法缩放的对象,比如DaemonSet
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hap-nginx
spec:
maxReplicas: 10 # 最大扩容到10个节点(pod)
minReplicas: 1 # 最小扩容1个节点(pod)
metrics:
- resource:
name: cpu
target:
averageUtilization: 40 # CPU 平局资源使用率达到40%就开始扩容,低于40%就是缩容
# 设置内存
# AverageValue:40
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hap-nginx
主要参数解释如下:
while true; do wget -q -O http://192.168.10.10 > /dev/null; done
进入apache官网 http://httpd.apache.org/ 下载apache即可,或者直接通过yum安装apache都行,这里选择最简单的方式yum安装
yum install httpd -y
复制
开始压测
ab -n 100000 -c 800 http://http://192.168.10.10
#-c:并发数
#-n:总请求数
ization: 40 # CPU 平局资源使用率达到40%就开始扩容,低于40%就是缩容
# 设置内存
# AverageValue:40
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hap-nginx
主要参数解释如下:
while true; do wget -q -O http://192.168.10.10 > /dev/null; done