目录
- 一. Deployment 基础解释
- RC RS 解释
- 二. Deployment 的更新机制
- 版本回滚
- 滚动升级
- 三. 资源限制与动态扩缩容
- 安装 Metrics-server
- HPA (动态扩缩容)
- 五. 蓝绿部署与金丝雀部署
- 六 Deployment总结
一. Deployment 基础解释
- 官方文档
- 前面部署时我们编写过Deployment 的yaml,什么是Deployment :
- 在k8s中可以直接使用pod,或者service部署应用,也可使用工作负载来部署应用,简单来说工作负载就是运行在k8s上的一个完整应用(内部可能包含多个pod,多个服务容器),这些相当于一个状态机,用来控制pod的具体状态和行为
- Deployment 类型的工作负载又有什么特点:用于创建和更新无状态的应用程序,可以实现Pod的滚动更新和回滚
- 通过Deployment部署应用时可以设置的期望状态,设置副本集,设置pod模板,底层会管理一个ReplicaSets ,实现了异常恢复,滚动更新等功能,也可以说结合 ReplicaSets 为pod提供声明式的更新能力
- 自己理解:
- , 在使用角度上我认为是编写pod模板,设置pod的期望状态,例如通过replicas指定pod副本数,k8s监听pod实际状态,通过Deployment进而管理一组pod,实现异常恢复,滚动更新等功能
- 创建Deployment yaml示例
apiVersion: apps/v1
kind: Deployment #资源类型,指定为Deployment
metadata:
name: nginx-deployment #当前Deployment的名字(不要有大写)
labels: #标签
app: nginx
spec: #期望状态
replicas: 3 #副本数,默认是1(pod期望数量)
selector: #选择器(当前Deployment可以控制选择器根据标签选中的所有pod)
matchLabels: #匹配标签
app: nginx #选择app: nginx标签
template: #编写pod模板
metadata: #pod的元数据
labels: #设置当前pod的标签 要与上面选择器选中的标签对应
app: nginx
spec:
containers: #设置镜像
- name: nginx #容器名称
image: nginx:1.14.2 #镜像
ports:
- containerPort: 80 #指定端口
- 当通过Deployment 部署一个应用以后,执行"kubectl get all|grep 部署名称"去获取对应的资源时,分别能拿到
- 通过Deployment部署的pod资源
- 通过Deployment部署的deployment资源
- 通过Deployment部署的replicaset副本资源(简称为RS资源)
- 假设在部署时设置"spec.replicas"为4,再去获取对应资源时,会发现其它资源不变,replicaset副本中显示4,总结就是Deployment 部署应用时, Deployment 控制ReplicasSet资源, ReplicasSet控制Pod的副本数RS(replicaset)控制器用来控制副本数
RC RS 解释
- RC: ReplicasController: 副本控制器
- RS: ReplicasSet: 副本集
- 两者之间的关系: RS副本集是RC副本控制器的进阶版,在新版的Kubernetes中建议使用ReplicaSet (RS)来取代ReplicationController。ReplicaSet跟ReplicationController没有本质的不同,只是名字不一样,但ReplicaSet支持集合式selector,可以写表达式可以编写复杂的选择器,支持"matchLabels"以外还支持"matchExpressions"匹配,如下:
## RS支持复杂选择器
matchExpressions:
- key: pod-name
value: [aaaa,bbb]
# In, NotIn, Exists and DoesNotExist
# In: value: [aaaa,bbb]必须存在,表示key指定的标签的值是这个集合内的
# NotIn value: [aaaa,bbb]必须存在,表示key指定的标签的值不是这个集合内的
# Exists # 只要有key指定的标签即可,不用管值是多少
# DoesNotExist # 只要Pod上没有key指定的标签,不用管值是多少
operator: DoesNotExist
- Deployment的版本回退,异常恢复,滚动升级,底层都是基于ReplicasSet实现的,虽然ReplicasSet强大,但是我们也不直接写RS;都是直接写Deployment的, ** Deployment会自动创建RS,Deployment每次的滚动更新都会产生新的RS,Deployment 控制RS资源,RS用来控制副本数**
# 指定api版本为apps/v1
apiVersion: apps/v1
# 指定资源类型为ReplicaSet
kind: ReplicaSet
# 指定资源的元数据,包括名称,标签,注解等
metadata:
# 指定资源的名称为frontend
name: frontend
# 指定资源的规格,包括副本数,选择器,模板等
spec:
# 指定期望的Pod副本数为3
replicas: 3
# 指定选择器,用于匹配和管理Pod
selector:
# 指定选择器的匹配规则,根据标签进行匹配
matchLabels:
# 指定只匹配标签为tier: frontend的Pod
tier: frontend
# 指定Pod模板,用于创建Pod
template:
# 指定Pod模板的元数据,包括标签,注解等
metadata:
# 指定Pod模板的标签为tier: frontend
labels:
tier: frontend
# 指定Pod模板的规格,包括容器,卷,网络等
spec:
# 指定Pod模板的容器列表
containers:
# 指定一个容器
- name: nginx # 指定容器的名称为nginx
image: registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17 # 指定容器的镜像为registry.cn-beijing.aliyuncs.com/google_registry/nginx:1.17
imagePullPolicy: IfNotPresent # 指定容器的镜像拉取策略为IfNotPresent,即如果本地已有镜像则不拉取
ports: # 指定容器的端口列表
- name: httpd # 指定一个端口
containerPort: 80 # 指定端口的容器内部端口号为80
- 你是怎么理解Deployment和ReplicasSet的
- 我是这样理解的: 我们不需要手动部署ReplicasSet副本集,可以找一个自动部署的ReplicasSet输出为yaml文件查看,内部保存了部署当前pod设置的一些期望状态,例如指定副本数,选择器等相关信息
- 在通过Deployment部署应用时,可以设置pod模板,指定spec期望状态,设置副本集等信息
- Deployment除了会根据Pod模板来创建相应数量的Pod应用以外,还会根据设置的期望状态,生成一个新的RS对象,会将Deployment中设置的labels标签和selector选择器复制到RS对象中,还会在RS对象中记录一个哈希值作为版本号,
- 由于ReplicasSet中记录了当前部署的期望状态,运行过程中就可以通过ReplicasSet来保证一组Pod的数量和状态,
- 后续如果更新Deployment会生成新的RS新的哈希版本号,通过不同版本的RS实现滚动更新,滚回等版本控制
二. Deployment 的更新机制
- 例如我们编写Deployment yaml部署指定服务,在后续集成的过程中,需要对部署的应用升级,例如修改yaml中image镜像进行版本升级,注意: 只有 Deployment 的 Pod 模板(即 .spec.template)发生改变时,例如模板的标签或容器镜像被更新,才会触发 Deployment 上线更新。 其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作
- 概述k8s中是怎么通过Deployment中的ReplicasSet实现异常恢复,滚动更新,异常回滚的
- 异常恢复: 在通过Deployment部署应用时,可以设置spec期望状态信息,设置pod模板,设置选择器标签,Deployment在部署应用的过程中会根据当前设置的期望状态,标签等信息创建ReplicaSet副本集,并设置副本集的版本,这个RS中就记录了当前应用要保持的状态。异常恢复是由ReplicaSetController控制器来完成的,ReplicaSetController控制器会定期从APIServer获取ReplicaSet对象的期望状态和实际状态,然后根据两者的差异来进行相应的操作,例如实际状态中Pod的数量少于期望值,那么ReplicaSet控制器会创建新的Pod来补足缺失
- 滚动更新: 注意只有Deployment的Pod模板(即 .spec.template)发生改变时,例如模板的标签或容器镜像被更新,才会触发Deployment上线更新,Deployment针对版本更新回退提供了revisionHistoryLimit 历史版本记录, maxSurge级过程中允许多出的副本数,与maxUnavaible升级过程中不对外提供服务的副本数,strategy升级策略等设置,在Deployment更新时会根据当前Deployment中的期望状态,标签等信息生成新的RS副本集,然后根据更新策略逐步将旧版本的Pod替换为新版本的Pod,注意滚动更新是由DeploymentController控制器来完成的,和探针配合完成的
- 版本回滚: 在创建Deployment会生成RS, 在更新Deployment时会根据当前Deployment生成新的RS,每个RS都有版本号,内部都保存了当时部署时所设置的状态等信息,在版本回滚时找到对应的RS,根据这个RS拉起pod即可,版本回滚也是由Deployment控制器来完成的
- 更新相关命令示例:(更新,版本查看,回滚等等)
#更新指定容器镜像: kubectl set image deployment资源名 容器名=镜像名
kubectl set image deployment.apps/nginx-deployment php-redis=tomcat:8 --record
#或者直接修改定义也行(打开指定yaml手动修改,退出并保存)
kubectl edit deployment.v1.apps/nginx-deployment
#查看状态
kubectl rollout status deployment.v1.apps/nginx-deployment
################查看历史并回滚####################################
#查看更新历史-看看我们设置的历史总记录数是否生效
kubectl rollout history deployment.v1.apps/nginx-deployment
#注意点如果想通过上面的命令查看历史记录,那么在每次更新后要执行以下命令进行记录
kubectl apply -f 文件名.yaml --record
#回滚
kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
###############累计更新##############
#暂停记录版本
kubectl rollout pause deployment.v1.apps/nginx-deployment
#多次更新操作
##比如更新了资源限制
kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
##比如更新了镜像版本
kubectl set image deployment.apps/nginx-deployment php-redis=tomcat:8
##在继续操作多次
##看看历史版本有没有记录变化
kubectl rollout history deployment.v1.apps/nginx-deployment
#让多次累计生效与(可以与paused配合使用,paused设置为true表示暂停升级,通过该命令设置升级生效)
kubectl rollout resume deployment.v1.apps/nginx-deployment
版本回滚
# 使用kubectl rollout history命令查看deployment部署记录
kubectl rollout history deployment/test-java-tomcat
# 查看特定版本的详细信息,加上revision=<N>参数
kubectl rollout history deployment/test-java-tomcat --revision=3
# 回滚到ngin-deploymment上一个部署版本
kubectl rollout undo deployment/test-java-tomcat
# 使用--to-revision回滚到指定部署版本
kubectl rollout undo deployment/test-java-tomcat --to-revision=2
滚动升级
- 什么是滚动更新: 对于多实例服务,滚动更新采用对各个实例逐批次进行单独更新而非同一时刻对所有实例进行全部更新,来达到不中断服务的更新升级方式,在部署应用时提供了strategy属性,可以设置为Recreate重新创建或RollingUpdate滚动更新,如果使用重新创建,则是将旧版本全部杀死,然后新建,使用滚动更新时达到不中断服务的更新升级方式
- 滚动升级中几个比较重要的属性
- revisionHistoryLimit: k8s升级时历史版本记录,Deployment revision history存储在它控制的ReplicaSets中。默认在etcd中保存记录10个,如果删除的旧的RepelicaSet,或将该值设置为0,Deployment就无法再回退到指定版本
- strategy: 升级策略,枚举值为Recreate重新创建或RollingUpdate滚动升级,重新创建会先杀死所有旧版本然后升级,推荐使用滚动升级
- minReadySeconds: 新pod等待就绪时间,默认情况下服务启动完成就认为升级生效对外提供服务,可以设置成30秒,防止pod启动了但是服务还没准备好导致系统不可用
- maxSurge: 升级过程中最多可以比原先设置多出的pod数量, 例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。
- maxUnavaible: 升级过程中最多有多少个POD处于无法提供服务的状态,当maxSurge不为0时,该值也不能为0,最好和maxSurge保持一致。例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态,可以保证有足够的pod(或者认为是足够的性能)提供服务
- progressDeadlineSeconds: 升级版本时超时时间,默认600s,超过这个时间整个升级未完成,则认为失败
- paused: 暂停升级, 默认false
- 设置示例
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: test-java-tomcat
spec:
replicas: 2
minReadySeconds: 20
strategy: #升级策略
# indicate which strategy we want for rolling update
type: RollingUpdate #Recreate重新创建或RollingUpdate滚动更新
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: test-java-tomcat
spec:
terminationGracePeriodSeconds: 10
containers:
- name: test-java-tomcat
image: harbor.example.com/test/cm_self_profit_api:latest
ports:
- containerPort: 8090
name: web
volumeMounts:
- name: app-logs
mountPath: /usr/local/tomcat8/logs
- image: harbor.example.com/ops/filebeat-7.10.2:1.0
imagePullPolicy: Always
name: filebeat
volumeMounts:
- name: app-logs
mountPath: /logs
- name: filebeat-config
mountPath: /etc/filebeat
volumes:
- name: app-logs
emptyDir: {}
- name: filebeat-config
configMap:
name: test-java-tomcat-filebeat-config
---
apiVersion: v1
kind: Service
metadata:
name: test-java-tomcat
spec:
type: NodePort
ports:
- port: 8090
targetPort: 8090
nodePort: 30019
selector:
app: test-java-tomcat
- Deployment 更新底层实现原理:
- 在上面已经知道Deployment 通过RS副本资源控制器控制副本数
- Deployment针对版本更新回退提供了: revisionHistoryLimit 历史版本记录, maxSurge级过程中允许多出的副本数,与maxUnavaible升级过程中不对外提供服务的副本数等设置属性
- 在我们使用Deployment滚动更新时,并不是所有pod全部升级直接替换,例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD, 新升级的pod等待minReadySeconds时间后表示就绪才会下掉旧pod,然后依次替换其它pod,并且当maxSurge不为0时,maxUnavaible也不能为0,推荐与maxSurge保持一致。例如:maxUnavaible=1,整个升级过程中最多会有1个POD处于无法服务的状态,可以保证有足够的pod(或者认为是足够的性能)提供服务
- 每更新一次,就会创建一个RS副本资源,不同的RS控制不同版本的副本数,这些RS副本资源通过revisionHistoryLimit 进行记录,当我们进行版本回退,或者修改yaml中更新版本属性后拿到与某个旧版本的hash,则启用对应版本的RS副本提供服务,revisionHistoryLimit 默认10个, 注意当该值为0时表示不进行历史记录,则无法版本回退
- 上面提到的通过maxSurge与maxUnavailable组合起来实现的功能就叫做比例缩放
三. 资源限制与动态扩缩容
- 在部署应用服务时,可以通过resource Limits限制服务的cpu,内存等资源占用情况,例如在deployment设置pod模板位置,或者直接pod yaml中
- resources.limits.cpu:设置Pod可以使用的最大CPU或内存资源量
- resources: 另外一个没有limits的表示设置Pod 启动时所需的最小资源量
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: my-image
resources:
limits:
cpu: "1" # 设置 CPU 的限制为 1 个核心
memory: "512Mi" # 设置内存的限制为 512 MiB
requests:
cpu: "0.5" # 表示设置申请的 CPU 资源预期为 0.5 个核心
memory: "256Mi" # 表示设置申请的内存资源预期为 256 MiB
- 默认情况下如果只限制了资源,没有设置动态扩缩容,可能会出现
- OOM错误:如果 Pod 的内存使用超过了设置的资源限制,可能会导致 Pod 内存不足,最终触发 OOM 错误。此时,Pod 可能会被 Kubernetes 自动重启,但如果问题持续存在,将会反复重启或处于失败状态。
- CPU 资源耗尽:如果 Pod 的 CPU 使用超过了设置的资源限制,会导致 CPU 资源不足。这可能导致应用程序的响应时间变慢或请求失败,甚至可能导致 Pod 的死锁或无法正常工作。
- 系统稳定性下降:当资源超过限制时,其他正常运行的 Pod 和节点上可能受到影响,系统的整体稳定性可能会下降。例如,节点上的其他应用程序可能会受到资源竞争的影响,导致性能下降或不可用。
- 优先级和质量控制:如果没有自动扩缩容机制,当资源限制超过时,Kubernetes 可能无法根据需求调整 Pod 的数量,导致某些任务或用户请求无法得到响应。这可能会影响应用程序的可用性和用户体验。
- 在资源限制成名k8s中还存在一个qosClass属性,用来控制资源竞争问题,可以设置为如下三种值
- Guaranteed保证型:Pod 具有明确的资源请求和限制,其资源使用是受保证的。当集群资源不足时,这些 Pod 不会被抢占或终止。
- Burstable可突发型:Pod 具有资源请求,但没有明确的资源限制。这些 Pod 可以在资源充足时突发使用更多的资源,但在资源紧张时可能会被抢占。
- BestEffort尽力型:Pod 没有明确的资源请求和限制,它们将尽量使用集群中的空闲资源。但在资源紧张时,这些 Pod 可能会受到限制或被抢占。
- 除了可以限制cpu,内存等资源外,还可以通过pv, pvc限制存储资源,还可以通过NetworkPolicy控制网络隔离设限制入站出站请求,通过Ingress,或kube-ratelimiter或Istio实现流量控制
- k8s也可以通过监控资源情况实现动态扩缩容,但是需要确保集群中运行着 Metrics Server 或其他支持指标(如 Prometheus)的监控解决方案
- Metrics Server 是 Kubernetes 提供资源利用情况度量的核心组件之一。它收集和聚合了集群中的资源指标数据,如 CPU 和内存使用率等
- Prometheus 是一种基于时间序列的开源监控系统,它可以收集和存储各种资源指标数据
安装 Metrics-server
- HorizontalPodAutoscaler 动态扩缩容又称为Pod的水平自动缩放,官方文档
- 需要先安装Metrics,注意安装版本,具体参考官方文档
- 在Metrics官方文档中获取到部署Metrics的yaml文件(注意版本)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: metrics-server
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rbac.authorization.k8s.io/aggregate-to-view: "true"
name: system:aggregated-metrics-reader
rules:
- apiGroups:
- metrics.k8s.io
resources:
- pods
- nodes
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: metrics-server
name: system:metrics-server
rules:
- apiGroups:
- ""
resources:
- pods
- nodes
- nodes/stats
- namespaces
- configmaps
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: metrics-server
name: metrics-server-auth-reader
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: metrics-server
name: metrics-server:system:auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: metrics-server
name: system:metrics-server
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
ports:
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: metrics-server
strategy:
rollingUpdate:
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: metrics-server
spec:
containers:
- args:
- --cert-dir=/tmp
- --kubelet-insecure-tls # 添加该设置,表示不验证CA证书使用非安全登入协议(默认没有)
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
image: registry.cn-hangzhou.aliyuncs.com/images/metrics-server:v0.4.3 #原文件中metrics-server可能拉取不到,修改为正确的镜像获取地址(注意版本)
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 10
name: metrics-server
ports:
- containerPort: 4443
name: https
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /readyz
port: https
scheme: HTTPS
periodSeconds: 10
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
volumeMounts:
- mountPath: /tmp
name: tmp-dir
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-cluster-critical
serviceAccountName: metrics-server
volumes:
- emptyDir: {}
name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
labels:
k8s-app: metrics-server
name: v1beta1.metrics.k8s.io
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: kube-system
version: v1beta1
versionPriority: 100
- 将获取到用来安装Metrics的yaml添加到k8s中,执行"kubectl apply -f 文件名称.yaml"命令安装应用即可
- 执行"kubcetl get pod -A" 查看Metrics-server是否安装完成
- 执行"kubcetl top nodes --use -protocol -buffers"命令查看当前k8s所有节点cup,内存使用状况
- 执行"kubectl top pods --use -protocol -buffers" 查看所有pod 占用cup,内存情况
- 此时Metrics-server已经安装运行完毕,登入k8s的Dashboard 可视化平台,也可以看到所有资源占用情况
HPA (动态扩缩容)
- HorizontalPodAutoscaler 动态扩缩容又称为Pod的水平自动缩放,官方文档
- 上面安装Metrics-server完毕后已经可以监控到所有资源的占用情况
- 在k8s上有专门设置动态扩缩容的资源hpa
- 参考官网部署服务演示示例
- 部署了一个pod,名为php-apache, 副本数为1, resources下设置Cpu占用大小,
- 编写"kind: Service"将创建的服务封装为负载均衡网络对外暴露
- 编写"kind: HorizontalPodAutoscaler " 设置 hpa 动态扩缩容
- 解释: 在"kind: HorizontalPodAutoscaler "设置hpa扩缩容,当监控的目标资源cpu使用率超过50%时则扩容,使用率低于50%时则缩容,最大可扩容副本数为maxReplicas个,缩容时最小保存副本数为minReplicas
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/php-hpa:latest
ports:
- containerPort: 80
resources: #设置占用
limits:
cpu: 500m
requests:
cpu: 200m
---
#封装负载均衡网络
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
---
##hpa配置 hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef: #将要扩展的目标引用
apiVersion: apps/v1
kind: Deployment #目标类型
name: php-apache #目标名称
targetCPUUtilizationPercentage: 50 #旧的设置方式,限制根据cup占有率进行扩缩容,超过50%则扩容,低于50%则缩容
maxReplicas: 10 #最大副本数,最大可扩容到的副本数量
minReplicas: 1 #最小副本数,缩容时最小保存副本数
- 也可以使用命令行方式创建"HorizontalPodAutoscaler"设置hpa扩缩容
#对deployment资源,名为php-apache的设置扩缩容,判断cpu-percent=50占用超过50m扩容min个,最大可扩容为max个
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
- Hpa动态扩缩容在"autoscaling/v2 API" 版本中发生了很多变化 ,支持根据cpu内存使用率,也支持根据pod接收请求数量,参考官方文档中的"基于多项度量指标和自定义度量指标自动扩缩"
- targetCPUUtilizationPercentage 字段在新版本中被名为 metrics 的数组所取代, CPU利用率这个度量指标是一个 resource metric资源度量指标,因为它表示容器上指定资源的百分比,还可以指定资源度量指标使用绝对数值,而不是百分比,需要将 target.type 从 Utilization 替换成 AverageValue,同时设置 target.averageValue 而非 target.averageUtilization 的值
- 并且支持 Pod 度量指标,与资源度量指标非常相像,只是它们仅支持 target 类型为 AverageValue
- 支持对象 Object 度量指标
- 如果指定了多个上述类型的度量指标,HorizontalPodAutoscaler 将会依次考量各个指标,计算每一个指标所提议的副本数量,然后最终选择一个最高值
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache # HPA 对象的名称
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache # 要自动扩展的 Deployment 的名称
minReplicas: 1 # 最小 Pod 副本数
maxReplicas: 10 # 最大 Pod 副本数
metrics:
- type: Resource # 使用资源指标进行自动缩放
resource:
name: cpu # 关注的资源名称为 CPU
target:
type: Utilization # 使用平均利用率作为阈值类型
averageUtilization: 50 # 设置 CPU 使用率的目标阈值为 50%,超过该阈值则扩容,小于该阈值则缩容
- type: Resource
resource:
name: memory #关注的资源名称为内存
target:
type: Utilization # 使用平均利用率作为阈值类型
averageUtilization: 80 # 设置内存使用率的目标阈值为 80%,超过该阈值则扩容,小于该阈值则缩容
- type: Pods
pods:
metricName: http_requests # 使用 http_requests 指标进行扩缩容
targetAverageValue: "1000" # 目标平均每秒请求数为 1000
status:
observedGeneration: 1 # 观察到的 HPA 创建的世代数
lastScaleTime: <some-time> # 上次扩容或缩容操作的时间戳
currentReplicas: 1 # 当前的 Pod 副本数
desiredReplicas: 1 # 期望的 Pod 副本数
currentMetrics:
- type: Resource # 当前的资源指标类型为 CPU
resource:
name: cpu # 当前关注的资源名称为 CPU
current:
averageUtilization: 0 # 当前的 CPU 平均利用率为 0%
averageValue: 0 # 当前的 CPU 平均值为 0
五. 蓝绿部署与金丝雀部署
- 滚动发布的缺点:
- 不能直接控制新老版本的存活时间,新版本只要发布就绪成功,会直接下掉所有老版本
- 不能精确控制新老版本间的流量划分,只能通过新老版本pod比例来控制
- 蓝绿部署: 在实际开发中线上运行的旧版本pod服务我们称为绿版本,而新发布的我们称为蓝版本,发版更新时不是直接下掉绿色的旧版本,而是先将蓝色新版本发布成功,只允许少量请求访问蓝色新版本,做到一定程度的灰度,当蓝色版本经过少了请求验证成功后再由蓝色新版本替换掉绿色的旧版本
- 金丝雀部署借鉴的是煤矿工人就带着真正的金丝雀寻找气体泄漏点,先用金丝雀探测是否有泄漏,如果有则不进入矿井,或者该离开矿井了
- 了解金丝雀部署前先复习一下封装Service负载均衡网络,对外暴露服务访问地址,在部署服务时,通常情况下需要针对指定部署服务封装Service,通过Service中的选择器选中指定一个或一组pod标签,代理这些选中的pod,在访问这些pod时,通过service进行负载均衡将请求打到指定的pod上
- 金丝雀部署基于封装Service时,使用选择器根据标签选中pod的实现的,详细流程:
- Deployment部署服务pod, 设置副本数,设置pod标签,标签可以后缀版本号例如"v1"
- 通过新建一个Deployment的方式进行版本更新,新建的Deployment拉取 新版本的镜像,设置副本数,设置pod标签,注意标签前缀与旧版本的前缀相同,标签后缀为"v2",此时旧版本,新版本共存
- 由于Service使用选择器,根据pod标签选中pod代理,那么原service就可以同时选中新旧两个版本的pod,新旧版本同时对外提供服务,可以通过新版Deployment中的副本数控制调整新旧版本流量划分
- 当通过第二个Deployment部署的新版本验证成功后,直接下掉旧版本的pod即可,或者Service选中pod的选择器中修改选中标签为"前缀+v版本号"选中指定版本
- 一个简单的封装service示例
#封装负载均衡网络
apiVersion: v1
kind: Service
metadata:
name: demo-canary
namespace: default
spec:
selector:
app: demo-canary #选中标签(根据pod标签选中一组pod,注意部署新老版本pod时的标签设置)
type: NodePort #service使用的类型
ports:
- name: demo-canary
nodePort: 31666 #机器上开的,给浏览器访问的端口
port: 81 #当前service对外暴露端口号
targetPort: 80 #pod的访问端口,
protocol: TCP
#上面几个端口的访问流程: 浏览器访问nodePort指定的端口,
#该端口会映射访问到当前service对外暴露的端口port也就是81,
#通过service这个端口可以映射访问到pod上的80端口targetPort
- 滚动发布中还存在的缺点:(引入蓝绿部署,金丝雀部署等)
- 不能直接控制新老版本的存活时间,新版本只要发布就绪成功,会直接下掉所有老版本
- 不能精确控制新老版本间的流量划分,只能通过新老版本pod比例来控制
- 切换过程中,可能会出现访问到 v1 的情况
- 什么是蓝绿部署,金丝雀部署
- 蓝绿部署: 在更新过程中要下线的旧pod服务称为绿版本,新发布的称为蓝版本,发版更新时不直接下掉绿色的旧版本,而是先将蓝色新版本发布成功,只允许少量请求访问蓝色新版本,做到一定程度的灰度,当蓝色版本经过少了请求验证成功后再由蓝色新版本替换掉绿色的旧版本
- 金丝雀部署: 一小部分用户或流量被导向到新版本,而大部分用户或流量仍然访问旧版本。这样可以对新版本进行实时监测,并在发现问题时迅速回滚。通过逐渐增加新版本的流量比例,可以确保新版本稳定可靠,而不会对整个系统产生重大影响
- k8s中如何实现的蓝绿部署:
- 通过deployment部署运行的pod应用,打上绿色标签
- 更新时,通过deployment再次部署一条新的pod应用,打上蓝色标签
- 编写service根据标签选中指定版本进行暴露,例如更新前service选中绿色标签的pod对外暴露,当新版本的蓝色服务启动成功后修改service标签选中新的蓝色标签pod对外暴露
- 蓝绿部署的缺点:虽然可以通过service选中指定版本进行暴露的方式实现用户无感知平滑过渡,但是需要提供两个版本的服务环境浪费资源,如果不提供两个版本的环境,更新版本时只能确认发布成功进行切换,无法验证内部代码逻辑是否有问题
- 金丝雀部署是怎么实现的,金丝雀部署基于封装Service时,使用选择器根据标签选中pod的实现的,详细流程:
- Deployment部署服务pod, 设置副本数,设置pod标签,标签可以后缀版本号例如"v1"
- 通过新建一个Deployment的方式进行版本更新,新建的Deployment拉取新版本的镜像,设置副本数,设置pod标签,注意标签前缀与旧版本的前缀相同,标签后缀为"v2",此时旧版本,新版本共存
- 由于Service使用选择器,根据pod标签选中pod代理,那么原service就可以同时选中新旧两个版本的pod,同时对外提供服务,
- 当通过第二个Deployment部署的新版本验证成功后,直接下掉旧版本的pod即可,或者Service选中pod的选择器中修改选中标签为"前缀+v版本号"选中指定版本,
- 注意如果控制流量,例如通过新版Deployment中的副本数控制调整新旧版本流量划分,例如旧版本的副本为数为4.新版本的是1,就表示80%请求打到老服务上,20%打到新服务上,这种情况下如果新版本验证成功进行实际切换时就要考虑副本数的问题了,可以直接修改旧版本的镜像地址,直接通过滚动更新上线
- 金丝雀部署缺点:(进而引出Ingress实现的蓝绿部署,金丝雀部署
- 在一个时刻会同时有两个版本对外提供服务,资源浪费
- 虽然可以通过不同版本的Deployment中的pod副本数来控制流量分发比例,也只是根据比例控制的,无法做到百分百触达
- 现版本验证成功后,如何与老版本进行实际的切换也需要根据实际情况考虑,也就是上一个问题第5步骤中提到的
六 Deployment总结
- 首先参考129节