前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实验理解 K8S 滚动更新时如何实现零宕机

实验理解 K8S 滚动更新时如何实现零宕机

作者头像
我的小碗汤
发布2023-08-08 10:01:22
4300
发布2023-08-08 10:01:22
举报
文章被收录于专栏:我的小碗汤我的小碗汤

如果我们没有在 k8s 上运行的应用程序考虑正常关闭,它可能会在滚动更新期间立即返回 502 错误(Bad Gateway)。

首先,我将简要说明滚动更新开始后旧 pod 将如何终止。然后,我将展示帮助一个 Go 应用程序实现零停机时间的简单的正常关机实现。

Pod 终止时会发生什么?

根据官方文档[1],以下两个步骤将异步运行;

步骤 1。如果清单文件中定义了 preStop 挂钩,则运行它。之后,发送 SIGTERM 终止 pod 的每个容器中的进程。

第 2 步。从服务中摘除关闭的 pod。该服务不再将请求路由到这些 pod。

如果我们不通过 preStop 钩子让应用程序休眠几秒钟或适当地处理 SIGTERM,则 Step1 可以比 Step2 更早完成。如果在 Step2 结束之前有一些请求,该服务可能会将这些请求路由到终止的 pod 并返回 502 错误。因此,滚动更新可能会导致短暂的停机时间,直到所有到来的请求都被路由到新的 pod。

让我们通过两个实验进一步了解这一点。

实验

设置

实际上,将 sleep 命令作为 preStop 挂钩运行是实现优雅关机的最简单方法。但是,如果我们的应用程序运行在轻量级容器(如 alpine)上,则无法设置该命令,因为 shell 在此类容器上不可用。

B 计划是在应用程序代码级别处理 SIGTERM。

这是我在 Go 中的应用程序代码。

代码语言:javascript
复制
import (
 "context"
 "flag"
 "log"
 "net/http"
 "os"
 "os/signal"
 "syscall"
 "time"
)

func main() {
 var t time.Duration
 flag.DurationVar(&t, "shutdown.delay", 0, "duration until shutdown starts")
 flag.Parse()

 srv := http.Server{
  Addr: ":8080",
  Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   w.Write([]byte("hello world"))
  }),
 }

 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
 defer stop()
 go func() {
  log.Println("Server is running")
  if err := srv.ListenAndServe(); err != http.ErrServerClosed {
   log.Fatal(err)
  }
 }()

 for {
  select {
  case <-ctx.Done():
   time.Sleep(t)
   srv.Shutdown(ctx)
   return
  }
 }
}

服务器在 shutdown.delay 标志指定的秒数内开始关闭。我通过 minikube 创建了一个本地 k8s 集群,并使用vegeta[2] 向我的应用程序发送 HTTP 请求。您可以在Gist[3] 上查看 k8s 清单文件和 Dockerfile 。

vegeta 是很强大的HTTP 负载测试工具和库

在没有正常关机的情况下进行实验

让我们从第一个没有正常关机的实验开始。 在这种情况下,我们可以将 0s 设置为 shutdown.delay。

代码语言:javascript
复制
# deployment.yaml
template:
    spec:
      containers:
      - name: graceful-shudown
        args:
        - --shutdown.delay=0s
代码语言:javascript
复制
# rolling update starts in 30 seconds
$ sleep 30; kubectl rollout restart deployment graceful-shutdown
# execute vegeta command on a different tab
$ echo "GET http://graceful.shutdown.test" | vegeta attack -duration=60s -rate=1000 | tee results.bin | vegeta report
Requests      [total, rate, throughput]  60000, 1000.02, 996.32
Duration      [total, attack, wait]      59.999783354s, 59.999059582s, 723.772µs
Latencies     [mean, 50, 95, 99, max]    136.958326ms, 553.588µs, 10.9967ms, 5.001062432s, 5.089183568s
Bytes In      [total, mean]              690719, 11.51
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    99.63%
Status Codes  [code:count]               200:59779  502:221
Error Set:
502 Bad Gateway

我发送了 60 秒的请求,并在 30 秒内开始滚动更新。如我们所见,返回了一些 502 响应。

尝试优雅关机

对于这个实验,我将 shutdown.delay 设置为 5s,其他设置与上一个实验相同。

代码语言:javascript
复制
# deployment.yaml
template:
    spec:
      containers:
      - name: graceful-shudown
        args:
        - --shutdown.delay=5s
代码语言:javascript
复制
# rolling update starts in 30 seconds
$ sleep 30; kubectl rollout restart deployment graceful-shutdown
# execute vegeta command on a different tab
$ echo "GET http://graceful.shutdown.test" | vegeta attack -duration=60s -rate=1000 | tee results.bin | vegeta report
Requests      [total, rate, throughput]  60000, 1000.02, 1000.00
Duration      [total, attack, wait]      59.999790006s, 59.999058824s, 731.182µs
Latencies     [mean, 50, 95, 99, max]    1.662431ms, 512.264µs, 3.372343ms, 26.208994ms, 178.154272ms
Bytes In      [total, mean]              660000, 11.00
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    100.00%
Status Codes  [code:count]               200:60000
Error Set:

这一次,所有响应的状态都是 200。

结论

为了避免在滚动更新期间停机,我们必须在服务器开始关闭之前通过一些方法(例如 preStop 或信号处理)实现优雅关闭。

作者:山中裕太郎 出处:https://dev.to/yutaroyamanaka/understand-how-graceful-shutdown-can-achieve-zero-downtime-during-k8s-rolling-update-15eh

参考资料

[1]

官方文档: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-lifetime

[2]

vegeta: https://github.com/tsenart/vegeta

[3]

Gist: https://gist.github.com/yutaroyamanaka/3b77f028bfec131b86f2207714d7306c

- END -

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 进击云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Pod 终止时会发生什么?
  • 实验
    • 设置
      • 尝试优雅关机
      • 结论
        • 参考资料
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档