惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
D
Docker
K
Kaspersky official blog
Latest news
Latest news
P
Privacy International News Feed
雷峰网
雷峰网
S
Security Affairs
博客园 - 司徒正美
博客园 - Franky
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
C
Check Point Blog
T
Tailwind CSS Blog
T
Tenable Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Threat Research - Cisco Blogs
The Last Watchdog
The Last Watchdog
Google Online Security Blog
Google Online Security Blog
L
Lohrmann on Cybersecurity
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
B
Blog
The Hacker News
The Hacker News
V
V2EX
L
LINUX DO - 最新话题
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
W
WeLiveSecurity
Know Your Adversary
Know Your Adversary
P
Proofpoint News Feed
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Microsoft Security Blog
Microsoft Security Blog
S
Securelist
V2EX - 技术
V2EX - 技术
博客园 - 叶小钗
The Cloudflare Blog
小众软件
小众软件
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
L
LangChain Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Hacker News: Ask HN
Hacker News: Ask HN
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The Register - Security
The Register - Security

Posts on WKLKEN THINKING

apisix 中的 lrucache apisix 中的服务发现机制 apisix 中的负载均衡 apisix etcd机制 聊聊框架 apisix 遇到的一些问题 关于在除夕前一天换了一个洗衣机的故事 Django DRF 性能优化 DRF 的一些实践 Part1: Serializer DRF继承关系图 Better Code: 关于接口的灵活性 新的仓库: wklken/naming 缓存使用的一些经验 Better Code: 抽象: 可扩展性与可维护性的抉择 Better Code: 异常时, 该提示用户哪些信息? Better Code: 更好的异常日志打印 Go: some libs Go: go-redis/cache升级的坑 Go: logrus性能提升 Go: gin validation 远程办公的一点总结 Go: 开发过程中的一些bug 项目管理实践: 风险驱动开发 Go: 一种error wrap调用链处理方式 漫谈技术选型 Go: 基于 apitest 做handler层单元测试 Go: go-sql-driver interpolateparams参数优化 [分享]深度工作 你需要更多的思考时间 Django项目重构小结 工作七年小结: 学习,生活及其他 [分享]bash日常: bash-utils 极客时间推广海报 2017总结: 予时光以意义 k8s APIServer源码: api注册详细细节 k8s APIServer源码: api注册主体流程 k8s APIServer源码: 服务启动 k8s APIServer源码: go-restful框架 重构 - 读书笔记(Python示例) 写给新人的沟通建议 vim 杂谈 - 关于快速编辑 vim 杂谈 - 关于移动 读书笔记-重构: 章11 处理概括关系 读书笔记-重构: 章10 简化函数调用 读书笔记-重构: 章9 简化表达式 读书笔记-重构: 章8 重新组织数据 读书笔记-重构: 章7 在对象之间搬移特性 读书笔记-重构: 章6 重新组织函数 Python 代码规范小结 [分享]关于vim ElasticSearch集群部署文档 Logstash+ElasticSearch处理mysql慢查询日志 [分享]关于代码调试DE那些事 Logstash+ElasticSearch+Kibana- 实现相对通用的数据收集分析 ELK维护的一些点(二) [分享]Python源码剖析-数据结构 一些Centos Python生产环境的部署命令 摘录<<6个月学会任何一种外语>> ELK 维护的一些点 也许是一个新的开始 一些vim的个性化配置 读书笔记-调试九法 这段时间的一些想法 Python 源码阅读 - 垃圾回收机制 我为什么要写博客 APUE笔记-第一章 UNIX基础知识 Python源码阅读-闭包的实现 Python源码阅读-内存管理机制(二) Python源码阅读-内存管理机制(一) Python-基础-数据结构小结 '活动'设计的一些trick 一些简单的Python测试题 我的tmux配置及说明【k-tmux】 Review and Restart 工作四周年小结 vim插件: surround & repeat[成对符号编辑] vim插件: gundo[时光机] vim插件: expand-region[区域选中] vim插件: quickrun[快速执行] vim插件: trailing-whitespace[行尾空格处理] vim插件: closetag[成对标签补全] vim插件: ctrlp[文件搜索] vim插件: airline[状态栏增强] vim插件: theme[主题] vim插件: tagbar[大纲式导航] vim插件: nerdcommenter[快速注释] vim插件: rainbow_parentheses[括号高亮] vim插件: syntastic[语法检查] vim插件: delimitmate[符号自动补全] vim插件: matchit[成对标签跳转] vim插件: easy-align[快速对齐] vim插件: multiple-cursors[多光标操作] vim插件: vim-signature[快速标记跳转] vim插件: easymotion[快速跳转] vim插件: vundle[管理插件] Elasticsearch几个问题的解决 分享一份 Vim 简介PPT k-vim 更新9.0版本 关于知识管理工具的思考 Logstash+ElasticSearch+Kibana处理nginx访问日志
关于 k8s 的 zero downtime deployment 一些建议
2023-12-17 · via Posts on WKLKEN THINKING

问题

后端服务对接了 API 网关, 服务正常, 但是在滚动更新的时候, 会出现 502

滚动更新时, k8s会起新的pod, 同时删除老的pod

可能原因:

  1. 新的pod启动后, 标记为ready但实际服务并没有准备好
  2. 老的pod在删除时, 已经在处理的请求没有处理完就退出, 或者退出时还有流量进来

解决

需要通过一系列配置, 做到 zero downtime rolling update (可以google相关的关键字了解更多), 以下给到一些建议

1. 配置 liveness/rediness

  • liveness 判断一个pod是否正常启动, 进入Running状态
  • rediness 判断一个pod是否完成了所有必要的初始化动作, 可以开始提供服务, 进入Ready状态

pod 进入 Ready 状态意味着此时会有流量进来, 此时如果进程无法提供正常服务, 会导致 502

所以, 需要确保 rediness 的正确性, 使得进程可以提供服务之后, pod 才进入 Ready 状态

2. 配置 terminationGracePeriodSeconds

terminationGracePeriodSeconds, 最长的宽限期,是允许 Pod 在收到终止信号后优雅关闭的最大时间。如果 Pod 在这个时间结束之前已经自主成功退出,那么 Kubernetes 就会立即进行后续的清理回收步骤, 默认是 30s

如果pod被删除时, 后端服务有正在处理的请求, 并且请求需要超过 30s 才能处理完, 此时服务无法正常 graceful shutdown, 会被强杀, 导致 502.

所以这个值需要设置为 terminationGracePeriodSeconds > 服务承诺的最大的请求耗时时间 + 进程graceful shutdown耗时, 例如你的服务设置的处理请求最大超时时间是 60s, 那么 terminationGracePeriodSeconds 需要大于 60s

3. 程序要支持 graceful shutdown

确保正在处理的请求能被全部处理完之后再结束, 需要监听 SIGTERM 信号并且处理

例如 golang 1.18中支持 Server.Shutdown

Shutdown gracefully shuts down the server without interrupting any active connections. Shutdown works by first closing all open listeners, then closing all idle connections, and then waiting indefinitely for connections to return to idle and then shut down. If the provided context expires before the shutdown is complete, Shutdown returns the context’s error, otherwise it returns any error returned from closing the Server’s underlying Listener(s).

如何验证: 发送一个请求, 请求正在处理时, 发送SIGTERM信号给进程, 这个请求能被正常处理完

4. 主进程在容器中的 pid 必须为 1

这样才能正常接收到信号

某些应用编写了自定义脚本来启动服务, 但是pid=1的进程是这个脚本而不是服务, 这样会导致服务没法接收到信号并做graceful shutdown

例如:

  • /bin/bash -c app, 信号是shell收到的, app收不到
  • exec

5. 配置 preStop

建议配置 preStop

配置后执行的顺序 preStop -> SIGTERM -> SIGKILL

  • 先执行preStop脚本
  • 之后给进程发送信号SIGTERM

另外一个502可能原因, 从service中摘除 pod endpoint和删除pod是同步进行的, 但是谁先谁后是不确定的(watch到变更, 独立的事件), 此时如果删除pod先执行并且程序很快退出, 此时可能endpoint还没有被摘除, 那么会出现 502

因为 preStop 之后 k8s会发送 SIGTERM, 所以如果进程pid=1并且处理了SIGTERM信号能很好地进行graceful shutdown, 那么只需要加一个sleep确保没有流量进来

        lifecycle:
          preStop:
            exec:
              command:
              - sleep
              - 30

注意: 这个sleep的 30s 只是一个示例, 各个后端服务要自行压测确定, 例如如果集群使用ipvs+nodeport暴露服务到外部, 那么经验值是 sleep 120s, 此时注意terminationGracePeriodSeconds 需要配置并且大于 sleep时间+进程graceful shutdown时间

preStop也可以执行一些等待/资源回收/主动触发hook之类的操作, 但是需要注意:

  • 如果preStop执行时间+进程graceful shutdown在 terminationGracePeriodSeconds 时间之内执行结束, 容器正常删除;
  • 如果超过了terminationGracePeriodSeconds, 容器会被kill;
  • 如果 preStop 阻塞住了, 直到超过terminationGracePeriodSeconds, 容器会被kill
  • 如果 preStop 异常了, 容器会被kill

6. maxUnavailable/maxSurge

这两个跟 zero downtime 无关, 但是能降低影响范围

  • .spec.strategy.rollingUpdate.maxUnavailable, 滚动更新过程中,允许 “不可用” 的最大 Pod 数量; 默认 25%, 可以是绝对值或百分比
    • 确保在更新期间始终有足够多的 Pod 保持可用, 避免因为可用实例过少带来的问题(健康的pod负载过高导致不健康)
  • .spec.strategy.rollingUpdate.maxSurge, 滚动更新过程中,允许 “超过” Desired Replicas 数的最大 Pod 数量; 默认 25%;
    • 控制在更新过程中可能会暂时承受的额外负载

需要根据自身集群的资源/每个服务的负载等确定

怎么验证

  • 部署 deployment
  • 启动压测
  • 滚动pod kubectl rollout restart deployment xxxx
  • 如果压测结果中没有状态码为 502 的, 那么代表生效了

其他

websocket 这类服务能做到zero downtime么?

通过rolling update的方式无法做到, 需要其他方式, 例如部署两套后通过接入层做切换

参考文档