【问题标题】:How to gracefully shutdown a Go service running on Kubernetes如何优雅地关闭运行在 Kubernetes 上的 Go 服务
【发布时间】:2019-01-17 15:20:46
【问题描述】:

我有一个用 Go 编写的 API,它已经被 Dockerised 并在 GKE 上的 Kubernetes 集群中运行。

目前,我的 API 服务器无法处理任何关闭情况,例如 Pod 死亡或被故意关闭。

我应该捕获哪组 UNIX 信号才能正常关闭服务器?在什么情况下会触发它们?例如崩溃、K8s 关闭等。

【问题讨论】:

    标签: linux docker go kubernetes signals


    【解决方案1】:

    Kubernetes 发送一个SIGTERM 信号。所以优雅的关机可能是这样的:

    package main
    
    import (
        "context"
        "log"
        "net/http"
        "os"
        "os/signal"
        "syscall"
    )
    
    func main() {
        var srv http.Server
    
        idleConnsClosed := make(chan struct{})
        go func() {
            sigint := make(chan os.Signal, 1)
    
            // interrupt signal sent from terminal
            signal.Notify(sigint, os.Interrupt)
            // sigterm signal sent from kubernetes
            signal.Notify(sigint, syscall.SIGTERM)
    
            <-sigint
    
            // We received an interrupt signal, shut down.
            if err := srv.Shutdown(context.Background()); err != nil {
                // Error from closing listeners, or context timeout:
                log.Printf("HTTP server Shutdown: %v", err)
            }
            close(idleConnsClosed)
        }()
    
        if err := srv.ListenAndServe(); err != http.ErrServerClosed {
            // Error starting or closing listener:
            log.Printf("HTTP server ListenAndServe: %v", err)
        }
    
        <-idleConnsClosed
    }
    

    您还应该将 Liveness 和 Readiness 探针添加到您的 pod:

    livenessProbe:
      httpGet:
        path: /health
        port: 80
    readinessProbe:
      httpGet:
        path: /health
        port: 80
    

    【讨论】:

    • 通道被 make(chan os.Signal, 1) 缓冲的原因是什么?我注意到它似乎适用于无缓冲通道,即 make(chan os.Signal)
    【解决方案2】:

    回答 https://stackoverflow.com/a/54239385/12641885 只是部分正确。 当 Kubernetes 发送 SIGTERM 信号时,流量仍然可以路由到 pod,因为从端点集中删除 pod 并且 SIGTERM 信号是异步的 - 如果 pod 在 SIGTERM 之后,端点可能没有时间更新。 SIGTERM 只是礼貌地要求开始结束,但不要立即停止接受新的请求。

    您可以在 &lt;-sigint 之后将 sleep 添加到您的代码中或添加到您的 Deployment 中

    lifecycle:
          preStop:
            exec:
              command: ["sh", "-c", "sleep 10"]
    

    更多详情https://github.com/kubernetes/kubernetes/issues/86280#issuecomment-583173036

    【讨论】:

      猜你喜欢
      • 2022-07-12
      • 2013-04-17
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 2010-09-06
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      相关资源
      最近更新 更多