1 滚动更新的定义和目标
滚动更新的含义
一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新。
滚动更新的好处
最大好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性。
根据 yaml 创建资源, apply 可以重复执行,create 不行
kubectl create -f deploy.yml
kubectl apply -f deploy.yml --record
注意 当deploy.yml 是上次发布的内容没有更改时,使用kubectl apply无法进行更新发布。比如镜像使用的是latest标签时。
我们在发布deployment时,如果使用了如下的发布方式 或者 参数配置不正确时,会发现 服务会挂掉一会儿,用户会访问不了。
kubectl delete --ignore-not-found=true -f deploy.yml
kubectl create -f deploy.yml
原因是
pod被删除或者 容器启动后,到服务真正工作起来,中间会有一段时间无法正常访问,但 k8s 却认为服务是正常就绪状态。
本篇文章主要解决这个问题,实现 平滑的发布,发布更新服务过程中保证服务一直可用,用户零感知。
2 设置滚动更新
2.1 服务准备
我们有一个api服务deploy.yaml如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: familytree-api
namespace: default
spec:
selector:
matchLabels:
app: familytree-api
replicas: 3
template:
metadata:
labels:
app: familytree-api
spec:
containers:
- name: familytree-api
image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:1.0.0
imagePullPolicy: Always
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 4
memory: 4Gi
env:
- name: VERSION
value: 1.0.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: familytree-api-service
namespace: default
spec:
selector:
app: familytree-api
ports:
- protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: familytree-api-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefix
spec:
rules:
-
host: api.test.com
http:
paths:
- path: /api/nowater
backend:
serviceName: familytree-api-service
servicePort: 8080
---
服务中包含url路由接口可返回版本号和当前hostname
访问路由
app.router.add_get('/api/nowater/version', service.version_print)
实现代码如下:
async def version_print(request):
version = config["version"]
hostname = socket.gethostname()
try:
print("打印版本 "+version+" hostname " + hostname)
return web.json_response({'version': version, "hostname": hostname})
except Exception as e:
return web.json_response({'msg': e.value}, status=500)
使用命令发布服务
kubectl create -f deploy.yml
查看部署列表
kubectl get deployments | grep familytree-api
查看正在运行的pod
kubectl get pods | grep familytree-api
查看正在运行的pod使用的镜像
kubectl get deployment -o wide | grep familytree-api
输出如下:
[zzq@host3 ~]$ kubectl get deployment -o wide | grep familytree-api
familytree-api 3 3 3 0 4m familytree-api 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:1.0.0 app=familytree-api
通过pod描述,查看服务的当前映像版本
kubectl describe pods familytree-api-7c6fd4bb75-5qtr5
访问服务url
[zzq@host3 ~]$ curl http://api.test.com/api/nowater/version
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
2.2 进行滚动升级
方式一 将yaml中的镜像版本修改为升级版本–推荐
image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0
环境变量也修改为2.0.0
env:
- name: VERSION
value: 2.0.0
然后使用apply命令重新发布服务
kubectl apply -f deploy.yml --record
记得一定需要带有 --record,否则没有版本的信息记录,不利于回滚定位。
方式二 使用命令
kubectl set image deployments/familytree-api familytree-api=123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0
2.3 查看是否升级成功
查看状态:
kubectl rollout status deployment/familytree-api
Waiting for rollout to finish: 1 out of 3 new replicas have been updated..
deployment "familytree-api" successfully rolled out
暂停升级
kubectl rollout pause deployment <deployment>
继续升级
kubectl rollout resume deployment <deployment>
升级结束后,继续查看rs的状态:
kubectl get rs
根据AGE我们可以看到离我们最近的当前状态是:3,和我们的yaml文件是一致的,证明升级成功了。用describe命令可以查看升级的全部信息:
kubectl describe deployment familytree-api
输出为
[zzq@host3 ~]$ kubectl describe deployment familytree-api
Name: familytree-api
Namespace: default
CreationTimestamp: Mon, 23 Sep 2019 18:12:43 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision=2
kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"kubernetes.io/change-cause":"kubectl apply --filename=./deploy/deploy-prod.yml ...
kubernetes.io/change-cause=kubectl apply --filename=./deploy/deploy-prod.yml --record=true
Selector: app=familytree-api
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=familytree-api
Containers:
familytree-api:
Image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0
Port: 8080/TCP
Host Port: 0/TCP
Limits:
cpu: 4
memory: 4Gi
Requests:
cpu: 1
memory: 1Gi
Environment:
VERSION: 2.0.0
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: familytree-api-c6fbb4499 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 20m deployment-controller Scaled up replica set familytree-api-66f79b747c to 3
Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set familytree-api-c6fbb4499 to 1
Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set familytree-api-66f79b747c to 2
Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set familytree-api-c6fbb4499 to 2
Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set familytree-api-66f79b747c to 1
Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set familytree-api-c6fbb4499 to 3
Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set familytree-api-66f79b747c to 0
访问服务url
[zzq@host3 ~]$ curl http://api.test.com/api/nowater/version
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
3 设置服务存活探针和服务健康检查探针以及相应参数
使用上面的发布步骤并不能保证 服务完全平滑。
因为k8s不能判断 一个的服务是否已经可用,只要pod正常启动就会判断成 可用。
但是pod启动后并不代表服务可用,比如java的程序 可能还需要启动spring boot框架,去连接数据库等待。
这样就会导致 短暂的 服务不可用。
3.1 服务不可用的示例
比如我们一直访问准备好的version版本查询接口如下:
while :; do curl http://api.test.com/api/nowater/version; sleep 1; done
然后进行版本更新发布
kubectl apply -f deploy.yml --record
输出如下:
[zzq@host3 ~]$ while :; do curl http://api.test.com/api/nowater/version; sleep 1; done
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
我们可以发现镜像版本已经更新到2.0.0
我们可以在2.0.0镜像中加入延迟启动服务,也就是说,会先sleep 20s,然后才去启动app服务。
这就模拟了在服务启动过程中,虽然pod已经是存在的状态,但是并没有真正提供服务。
可以看到,由于延迟启动,api并没有真正做好准备提供服务,此时流量已经发到后端,导致服务不可用的状态
3.2 解决方案–探针检测
在实际生产环境中会遇到这样那样的问题,比如:容器里面应用挂了或者说新启动的容器里面应用还没有就绪等等,所以说就需要进行探测来检验容器是否满足需求。
那么一般的检测分为几种,比如:进程检测、业务检测。
进程检测呢很好理解,也就是说通过检测容器进程来验证容器内应用是否存活。
Kubelet会定期通过Docker Daemon获取所有Docker进程的运行情况,如果发现某个Docker容器未正常运行,则重新启动该容器进程。目前,进程级的健康检查都是默认启用的。
业务检测呢也好理解,有些人会问,有了进程检测不就挺好的么,为什么要进行业务检测?
因为在很多实际场景下,仅仅使用进程级健康检查还远远不够。有时,从Docker的角度来看,容器进程依旧在运行;但是如果从应用程序的角度来看,假设应用代码处于死锁状态的话,那每次调度到这个容器的时候永远都无法正常响应用户的业务。比如对于使用java web服务的应用来说,并不是简单地说tomcat启动成功就可以对外提供服务的,还需要等待spring容器初始化,数据库连接连接上等等。
为了解决以上问题,Kubernetes引人了一个在容器内执行的活性探针(liveness probe)的概念,以支持用户自己实现应用业务级的健康检查。这些检查项由Kubelet代为执行,以确保用户的应用程序正确运转,至于什么样的状态才算“正确”,则由用户自己定义。
Kubernetes支持3种类型的应用健康检查动作,分别为HTTP Get、Container Exec和TCP Socket。exec的方式比较通用的,因为不是每个服务都有http服务,但每个服务都可以在自己内部定义健康检查的job,定期执行,然后将检查结果保存到一个特定的文件中,外部探针就不断的查看这个健康文件就OK了。
介绍完存活性探针(liveness probe)之后我们来看看就绪探针(readiness probe),就绪探针是来确定容器是否已经就绪可以接受访问,只有当Pod中的容器都处于就绪状态时kubelet才会认定该Pod处于就绪状态,至于什么样的状态才算 ”就绪”,还是由用户自己定义。该状态的作用就是控制哪些Pod可以作为service的后端,如果Pod处于非就绪状态,那么它们将会被从service的load balancer中移除,防止 流量分发到 异常的pod中。
4 存活性探针(liveness probe)和就绪探针(readiness probe)的区别
readinessProbe检查成功与否,决定这个pod是否会被加入到Service的load balancer列表中,即是否给它分配访问的流量,并不影响Pod本身的生命周期
如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活探针; kubelet 将根据Pod的restartPolicy自动执行正确的操作。
如果您希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针,并指定restartPolicy为Always或OnFailure。
如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与存活探针相同,但是spec中的就绪探针的存在意味着Pod将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量。
两种探测的配置方法完全一样,支持的配置参数也一样,既可单独探测又可结合者一起执行。
LivenessProbe:用于判断容器是否存活(running状态),如果LivenessProbe探针探测到容器不健康,则kubelet杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,则kubelet认为该容器的LivenessProbe探针返回的值永远是“Success”。
ReadinessProbe:用于判断容器是否启动完成(ready状态),可以接收请求。如果ReadinessProbe探针检测到失败,则Pod的状态被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Endpoint。
4.1 存活性探测
livenessProbe:存活性探测,最主要是用来探测pod是否需要重启–决定把pod删除重新创建
在spec的containers中增加
与image同级
exec探针:
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
http探针:
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
tcp探针:
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
参数说明
说法1:
initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒。
periodSeconds:执行探测的频率。默认是10秒,最小1秒。
timeoutSeconds:探测超时时间。默认1秒,最小1秒。
successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。
failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。
说法2:
initialDelaySeconds: 表示容器启动之后延迟多久进行liveness探测
timeoutSeconds:每次执行探测的超时时间
periodSeconds:探测的周期时间
successThreshold:最少连续几次探测成功的次数,满足该次数则认为success。
failureThreshold:最少连续几次探测失败的次数,满足该次数则认为fail作
举例:
initialDelaySeconds: 5 #告诉kubelet在第一次执行probe之前要的等待5秒钟
periodSeconds: 10 #kubelet要每隔10秒执行一次liveness probe 检查
timeoutSeconds: 2 #超长时长,默认为1s,最小值也为1s
failureThreshold: 3 #处于成功状态时,探测操作至少连续多少次的失败才被视为检测不通过,默认为3,最小为1
探针检测命令是在容器中执行 cat /tmp/healthy 命令。
如果命令执行成功,将返回0,kubelet就会认为该容器是活着的并且很健康。如果返回非0值,kubelet就会杀掉这个容器并重启它。
4.2 就绪性探测
readinessProbe:就绪性探测,用来探测pod是否已经能够提供服务–决定是否参与分配流量
在spec的containers中增加
与image同级
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
periodSeconds: 10
或者
readinessProbe:
httpGet:
path: /api/nowater/version
port: 8080
httpHeaders:
- name : X-Custom-Header
value: Awesome
initialDelaySeconds: 5
periodSeconds: 10
periodSeconds 规定kubelet要每隔10秒执行一次readinessProbe 检查。
initialDelaySeconds 告诉kubelet在第一次执行probe之前要的等待5秒钟。
探针检测命令是检查tcp连接 端口80 是否畅通。
也可以检查某个http 请求是否返回成功码。
如果返回一个成功的返回码,kubelet就会认定该容器服务是可用的。
如果返回失败的返回码,kubelet将该pod改为not ready,将会被从service的load balancer中移除。
注意:任何大于200小于400的返回码都会认定是成功的返回码。其他返回码都会被认为是失败的返回码。
由于设置了readinessProbe,虽然pod已经启动起来了,但是并不会立即投入使用,会出现了 READY: 0/1 的情况
并且有pod出现了一直持续Terminating状态,因为滚动更新的限制,至少要保证有pod可用
再查看curl的状态,image的版本平滑更新到2.0.0,没有出现报错的状况
[zzq@host3 ~]$ while :; do curl http://api.test.com/api/nowater/version; sleep 1; done
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
{"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
----------
4.3 调整参数设置
在spec下面添加滚动升级策略:
与template同级
minReadySeconds: 5
strategy:
# indicate which strategy we want for rolling update
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
minReadySeconds:
这个值默认是0,Kubernetes会假设该容器启动起来后就可以提供服务了,会导致用户访问异常
这里需要估一个比较合理的值,从容器启动到应用正常提供服务
如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了
如果没有设置该值,在某些极端情况下可能会造成服务不正常运行
maxSurge:
升级过程中最多可以比原先设置多出的POD数量
例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。
maxUnavaible:
升级过程中最多有多少个POD处于无法提供服务的状态
当maxSurge不为0时,该值也不能为0
例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态。
4.4 格式如下
4.5 回滚
查看Deployment的升级历史:
kubectl rollout history deployment nginx-deploy
查看指定版本的升级历史
kubectl rollout history deployment nginx-deploy --revision=3
假如现在要直接回退到当前版本的前一个版本:
kubectl rollout undo deployment nginx-deploy
deployment "nginx-deploy" rolled back
当然也可以用revision回退到指定的版本:
kubectl rollout undo deployment nginx-deploy --to-revision=2
deployment "nginx-deploy" rolled back
现在可以用命令查看Deployment现在的状态了。
5 k8s滚动更新的原理
部署(Deployment)自动创建副本集(ReplicaSet),副本集根据参数策略可以精确地控制每次替换的Pod数量,从而可以很好的实现滚动更新。具体来说,k8s每次使用一个新的副本控制器(replication controller)来替换已存在的副本控制器,从而始终使用一个新的Pod模板来替换旧的pod模板。
大致步骤如下:
1、创建一个新的replication controller。
2、增加或减少pod副本数量,直到满足当前批次期望的数量。
3、删除旧的replication controller。
5.1 部署概况
使用命令查看部署概况
kubectl get deployment
上图包含的几个滚动发布过程标量,说明如下:
DESIRED 最终期望处于READY状态的副本数
CURRENT 当前的副本总数
UP-TO-DATE 当前完成更新的副本数
AVAILABLE 当前可用的副本数
5.2 部署详情
使用命令查看部署详情
kubectl describe deployment familytree-api
从上图可以看到,k8s精确地控制着整个发布过程,滚动进行,直到所有副本全部更新。其实,k8s提供了两个参数maxSurge和maxUnavailable来精确地控制每次滚动的pod数量,如下:
maxSurge 滚动更新过程中运行操作期望副本数的最大pod数,可以为绝对数值(eg:5),但不能为0;也可以为百分数(eg:10%)。默认为25%。
maxUnavailable 滚动更新过程中不可用的最大pod数,可以为绝对数值(eg:5),但不能为0;也可以为百分数(eg:10%)。默认为25%。
如果未指定这两个可选参数,则k8s使用默认配置,如下:
kubectl get deployment familytree-api -o yaml
剖析部署helloworldapi的标准输出:
当前的副本总数 = 3 + 3 * 25% = 4,所以CURRENT为4。
当前可用的副本数 = 3 - 3 * 25% = 2,所以AVAILABLE为2。
整个滚动过程是通过控制两个副本集来完成的,新的副本集:familytree-api-c6fbb4499;旧的副本集: familytree-api-66f79b747c 。
理想状态下的滚动过程:
创建了一个新的副本集,并为其分配1个新版本的pod,使副本总数达到4,一切正常。
通知旧副本集,销毁1个旧版本的pod,使可用副本总数保持到2,一起正常。
当1个副本销毁成功后,通知新副本集,再新增1个新版本的pod,使副本总数达到4,一切正常。
只要销毁成功,新副本集,就会创造新的pod,一直循环,直到旧的副本集pod数量为0。
有时整个滚动过程也是不理想的,不符合上述的规律,会有一些混乱。
但
k8s最终都会使服务全部更新到期望状态,始终保持最大的副本总数和可用副本总数的不变性
6 deployment的常用命令和参数说明
查看部署状态
kubectl rollout status deployment/review-demo --namespace=scm
kubectl describe deployment/review-demo --namespace=scm
或者这种写法
kubectl rollout status deployments review-demo --namespace=scm
kubectl describe deployments review-demo --namespace=scm
升级
kubectl set image deployment/review-demo review-demo=library/review-demo:0.0.1 --namespace=scm
或者
kubectl edit deployment/review-demo --namespace=scm
编辑.spec.template.spec.containers[0].image的值
终止升级
kubectl rollout pause deployment/review-demo --namespace=scm
继续升级
kubectl rollout resume deployment/review-demo --namespace=scm
回滚
kubectl rollout undo deployment/review-demo --namespace=scm
查看deployments版本
kubectl rollout history deployments --namespace=scm
回滚到指定版本
kubectl rollout undo deployment/review-demo --to-revision=2 --namespace=scm
升级历史
kubectl describe deployment/review-demo --namespace=scm
Name: review-demo
Namespace: scm
CreationTimestamp: Tue, 31 Jan 2017 16:42:01 +0800
Labels: app=review-demo
Selector: app=review-demo
Replicas: 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
OldReplicaSets: <none>
NewReplicaSet: review-demo-2741031620 (3/3 replicas created)
Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 1
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 2
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 2
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 1
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 3
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 0
deployment文件
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: review-demo
namespace: scm
labels:
app: review-demo
spec:
replicas: 3 #
minReadySeconds: 60 #滚动升级时60s后认为该pod就绪
strategy:
rollingUpdate: ##由于replicas为3,则整个升级,pod个数在2-4个之间
maxSurge: 1 #滚动升级时会先启动1个pod
maxUnavailable: 1 #滚动升级时允许的最大Unavailable的pod个数
template:
metadata:
labels:
app: review-demo
spec: terminationGracePeriodSeconds: 60 ##k8s将会给应用发送SIGTERM信号,可以用来正确、优雅地关闭应用,默认为30秒
containers:
- name: review-demo
image: library/review-demo:0.0.1-SNAPSHOT
imagePullPolicy: IfNotPresent
livenessProbe: #kubernetes认为该pod是存活的,不存活则需要重启
httpGet: path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60 ## equals to the maximum startup time of the application + couple of seconds
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe: #kubernetes认为该pod是启动成功的
httpGet: path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 30 ## equals to minimum startup time of the application timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
resources: # keep request = limit to keep this container in guaranteed class requests:
cpu: 50m
memory: 200Mi
limits:
cpu: 500m
memory: 500Mi
env:
- name: PROFILE
value: "test"
ports:
- name: http
containerPort: 8080
几个重要参数说明
maxSurge与maxUnavailable
maxSurge: 1 表示滚动升级时会先启动1个pod
maxUnavailable: 1 表示滚动升级时允许的最大Unavailable的pod个数
由于replicas为3,则整个升级,pod个数在2-4个之间
terminationGracePeriodSeconds
k8s将会给应用发送SIGTERM信号,可以用来正确、优雅地关闭应用,默认为30秒。
如果需要更优雅地关闭,则可以使用k8s提供的pre-stop lifecycle hook 的配置声明,将会在发送SIGTERM之前执行。
livenessProbe与readinessProbe
livenessProbe是kubernetes认为该pod是存活的,不存在则需要kill掉,然后再新启动一个,以达到replicas指定的个数。
readinessProbe是kubernetes认为该pod是启动成功的,这里根据每个应用的特性,自己去判断,可以执行command,也可以进行httpGet。比如对于使用java web服务的应用来说,并不是简单地说tomcat启动成功就可以对外提供服务的,还需要等待spring容器初始化,数据库连接连接上等等。对于spring boot应用,默认的actuator带有/health接口,可以用来进行启动成功的判断。
其中readinessProbe.initialDelaySeconds可以设置为系统完全启动起来所需的最少时间,livenessProbe.initialDelaySeconds可以设置为系统完全启动起来所需的最大时间+若干秒。
这几个参数配置好了之后,基本就可以实现近乎无缝地平滑升级了。对于使用服务发现的应用来说,readinessProbe可以去执行命令,去查看是否在服务发现里头应该注册成功了,才算成功。
参考:
原文链接:https://blog.csdn.net/zzq900503/article/details/101221899