1.1 前言
在微服务时代,我们直接关闭一个pod,那这部分流量就无法得到正确处理,会影响部分用户.通常来说网关或者注册中心会将我们的服务保持一个心跳,过了心跳超时之后会自动摘除我们的服务,但是有一个问题就是超时时间可能是30秒也可能是60秒,虽然不会影响我们的系统,但是会产生用户轻微抖动。
如果我们在停止前执行一条命令,通知网关或者注册中心这台主机进行下线,那么注册中心就会标记这台主机已经下线,不进行流量转发,用户就不会有任何影响,这就是优雅停止,将滚动更新影响最小化
1.2 PreStop
这里以Nacos
为例
Nacos
目前支持临时实例使用心跳上报方式维持活性,发送心跳的周期默认是 5 秒,Nacos
服务端会在 15 秒没收到心跳后将实例设置为不健康,
在 30 秒没收到心跳时将这个临时实例摘除。这里要注意30秒这个时间
nacos 服务手动下线方法
curl -X PUT "http://192.168.0.10:8848/nacos/v1/ns/instance?serviceName=java-test&clusterName=DEFAULT&groupName=test&ip=10.10.90.20&port=8888&enabled=false"
说明:
- 192.168.0.10:8848 nacos注册地址
- java-test 注册的应用名称
- 10.10.90.20 注册的应用名称所在主机地址
- 8888 注册的应用名称使用的端口号
- enabled=false 下线,enabled=true 上线
- namespaceId 命令空间,默认使用public命名空间则不写这个
这里是通过脚本先注入到镜像内 然后配置prestop来调用这个脚本
#!/bin/bash
NACOS_DISCOVERY_ADDR=`printenv | grep NACOS_DISCOVERY_ADDR | awk -F',' '{print $1}' | awk -F'=' '{print $2}'`
SERVER_NAME=${MY_POD_NAME}
PODIP=${POD_OWN_IP_ADDRESS}
PORT=`ss -tnl | grep 0.0.0.0 | awk '{print $4}' | awk -F':' '{print $2}'`
echo "输出必要的环境变量: ${NACOS_DISCOVERY_ADDR} ${SERVER_NAME} ${RUN_ENV} ${PODIP} ${PORT}"
result=$(curl -X PUT "http://${NACOS_DISCOVERY_ADDR}/nacos/v1/ns/instance?serviceName=${SERVER_NAME}&clusterName=DEFAULT&groupName=${RUN_ENV}&ip=${PODIP}&port=${PORT}&enabled=false"
)
echo "输出curl执行结果result:${result}"
if [ ${result} = "ok" ]; then
echo "执行成功"
sleep 45
exit 0
else
echo "执行失败"
exit 1
fi
将脚本添加到基础镜像中
ADD preStop.sh /tmp/pre_stop.sh
RUN chmod 777 /tmp/pre_stop.sh
1.3 yaml添加配置
lifecycle:
preStop:
exec:
command:
- /bin/sh
- '-c'
- /tmp/pre_stop.sh
再次重启服务将会发现老服务会先处于下线状态 持续45s后才会正常关闭