【发布时间】:2019-01-17 15:20:46
【问题描述】:
我有一个用 Go 编写的 API,它已经被 Dockerised 并在 GKE 上的 Kubernetes 集群中运行。
目前,我的 API 服务器无法处理任何关闭情况,例如 Pod 死亡或被故意关闭。
我应该捕获哪组 UNIX 信号才能正常关闭服务器?在什么情况下会触发它们?例如崩溃、K8s 关闭等。
【问题讨论】:
标签: linux docker go kubernetes signals
我有一个用 Go 编写的 API,它已经被 Dockerised 并在 GKE 上的 Kubernetes 集群中运行。
目前,我的 API 服务器无法处理任何关闭情况,例如 Pod 死亡或被故意关闭。
我应该捕获哪组 UNIX 信号才能正常关闭服务器?在什么情况下会触发它们?例如崩溃、K8s 关闭等。
【问题讨论】:
标签: linux docker go kubernetes signals
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
【讨论】:
回答 https://stackoverflow.com/a/54239385/12641885 只是部分正确。
当 Kubernetes 发送 SIGTERM 信号时,流量仍然可以路由到 pod,因为从端点集中删除 pod 并且 SIGTERM 信号是异步的 - 如果 pod 在 SIGTERM 之后,端点可能没有时间更新。
SIGTERM 只是礼貌地要求开始结束,但不要立即停止接受新的请求。
您可以在 <-sigint 之后将 sleep 添加到您的代码中或添加到您的 Deployment 中
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]
更多详情https://github.com/kubernetes/kubernetes/issues/86280#issuecomment-583173036
【讨论】: