目录
1. 调节发布策略,防止旧的deployment在新的deployment启动前销毁:
1.发现问题
如下图我们通过Git Lab的CI/CD完成最新的代码部署,但是当我们完成最后阶段的deploy的时候。访问服务,此时服务会无法访问。
这是会出现502的错误:
2.分析问题
为啥需要解决这个问题呢?
- 服务不可用会导致这时候的用户无法完成相应的业务,而且如果没有重试或者容错处理,可能产生一些脏数据,可能有的记录了错误日志的还需要人工处理。
- 还可能由于部分服务的不可用拖垮其他服务。
- 为了提升用户的体验感,真正的做到不停机更新,就必须要解决到此问题。
既然是发布的时候出错就可能是新旧服务切换的时候出了问题。
要么是旧服务关闭早了,或者是新服务还没有就绪。
3.解决问题
由于我们使用的是k8s对容器进行管理,所以查询了k8s关于在部署deployment时的一些参数配置。
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-deployment
spec:
selector:
matchLabels:
app: order
replicas: 3
template:
metadata:
labels:
app: order
spec:
containers:
- name: order-service
1. 调节发布策略,防止旧的deployment在新的deployment启动前销毁
通过 strategy 可以配置 pod 的替换策略,主要参数如下。
.spec.strategy.type
- 用于指定替换 pod 的策略类型。该参数可取值 Recreate 或 RollingUpdate,默认为 RollingUpdate。
- Recreate - K8s 会先删掉全部原有 pod 再创建新的 pod。该方式适用于新老版本互不兼容、无法共存的场景。但由于该方式会造成一段时间内服务完全不可用,在上述场景之外须慎用。
- RollingUpdate - K8s 会将 pod 分批次逐步替换掉,可用来实现服务热升级。
发现我们就是滚动发布的方式,已经不需要更改。那么就看看新的deployment发布的配置。
2.让新服务启动就绪后,再关闭旧的服务,访问新的服务
查阅了相关资料,发现只有配置ReadinessProbe探针才能做到消除502,让服务一直处于可用的状态。
配置探针
K8s 提供以下两类探针:
- ReadinessProbe - 默认情况下,一旦某个 pod 中的所有容器全部启动,k8s 就会认为该 pod 处于就绪状态,从而将流量发往该 pod。但某些应用启动后,还需要完成数据或配置文件的加载工作才能对外提供服务,因此通过容器是否启动来判断其是否就绪并不严谨。通过为容器配置就绪探针,能让 k8s 更准确地判断容器是否就绪,从而构建出更健壮的应用。K8s 保证只有 pod 中的所有容器全部通过了就绪探测,才允许 service 将流量发往该 pod。一旦就绪探测失败,k8s 会停止将流量发往该 pod。
- LivenessProbe - 默认情况下,k8s 会认为处于运行状态下的容器是可用的。但如果应用在出现问题或不健康时无法自动退出(例如发生严重死锁),这种判断就会出现问题。通过为容器配置活性探针,能让 k8s 更准确地判断容器是否正常运行。如果容器没有通过活性探测,kubelet 会将其停止,并根据重启策略决定下一步的动作。
探针的配置非常灵活,用户可以指定探针的探测频率、探测成功阈值、探测失败阈值等。各参数的含义和配置方法可参考文档 Configure Liveness and Readiness Probes。
样例为目标容器配置了就绪探针和活性探针:
- 就绪探针的 initialDelaySeconds 设置成 30,这是因为应用平均需要 30 秒时间完成初始化工作。
- 在配置活性探针时,需要保证容器有足够时间到达就绪状态。如果参数 initialDelaySeconds、periodSeconds、failureThreshold 设置得过小,可能造成容器还未就绪就被重启,以至于永远无法达到就绪状态。样例中的配置保证如果容器能在启动后的 80 秒内就绪就不会被重启,相对 30 秒的平均初始化时间有足够的缓冲。
- 就绪探针的 periodSeconds 设置成 10,failureThreshold 设置成 1。这样当容器异常时,大约 10 秒后就不会有流量发往它。
- 活性探针的 periodSeconds 设置成 20,failureThreshold 设置成 3。这样当容器异常时,大约 60 秒后就不会被重启。
4.问题总结
通过加上就绪探针readinessProbe的配置就可以在新的deployment真正启动,deployment能对外提供服务的时候,service再将流量转发过来,实现不停机更新的操作。
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 60
最后完整的k8s的service和deployment配置如下:
kind: Service
apiVersion: v1
metadata:
name: order-service
spec:
selector:
app: order
ports:
- protocol: TCP
port: 8080
targetPort: 8080
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-deployment
spec:
selector:
matchLabels:
app: order
replicas: 3
strategy:
type:
template:
metadata:
labels:
app: order
spec:
containers:
- name: order-service
image: code.darmi.com:5672/darmi/darmi-mall-service/order-service
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 15
periodSeconds: 60
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 60
nodeSelector:
environment: dev