在 Kubernetes 中关闭后 Nginx 容器没有重新启动 1.我们在前端/上游 nginx 容器和部署中设置了活跃度和准备情况探测2.我们为 nginx 容器设置了平滑关闭3.最低 CPU 和内存请求最后的笔记

问题描述

最近,我们在 GKE 上运行的 Kubernetes 部署遇到了问题。 看起来,随机地,我们的 Nginx 前端容器,服务于我们的前端应用程序,似乎死了。这引起了相当大的骚动,因为 nginx-ingress 只会告诉我们存在 HTTP2 协议错误。经过大约一周的混乱,我们终于在 FE 容器的日志中注意到,每当我们遇到 HTTP2 协议错误(在 chrome 中)时都会发生这种输出

enter image description here

一旦我们将 nginx-ingress 切换到 HTTP1,我们就会得到 ERR_CONTENT_LENGTH_MISMATCH 200 的错误,但这仍然是一个误导性错误

这是我们所有配置的要点,供感兴趣的人使用: gist

至于Nginx版本,我尝试了以下:

稳定的高山

稳定

mainline-alpine

1.17.10-高山

所有结果都在同一组日志中。

我尝试过的事情:

在任何人问之前:到目前为止,对 nginx-ingress 所做的所有配置都是为了解决 HTTP2 协议错误。显然没有这些工作的,因为如果上游服务器关闭,这并不重要。

我可以推断出,虽然 Nginx 正在关闭(为什么,我仍然不知道),但容器本身并没有重新启动,因此该 pod 实际上是一个僵尸案例。我如何 A. 强制重启或 B. 强制 Pod 死亡并重生?

当然,如果有人首先回答为什么 Nginx 容器被告知关闭,那也会有帮助。

一个可能相关的问题是,有时此部署的副本无法启动,容器已准备就绪,但没有日志或连接。

手动杀死 Pod,似乎可以解决此问题,但这不是真正的解决方案。

集群正在运行 n1-standard-2 个节点,并且我们启用了自动缩放,因此 cpu/内存/存储不是(不应该是,永远不要说永远)问题。

提前致谢!如果我可以改进这个问题,请发表评论

编辑 #1:包括我们在 GKE 上。

编辑 #2:我添加了就绪和活跃度探测器。我已经使用健康检查路由更新了 Nginx FE 服务器。这似乎起到了故障保护的作用,以确保如果内部 Nginx 进程停止或什至没有启动,容器将重新启动。但是,如果有人有更好的选择或根本原因,我很想知道!也许我应该为每个 Pod 设置特定的 cpu 和内存请求?

解决方法

我建议您做的是将图像本身从 apine 更改为 debian,或者将 nginx 从 1.17 更新到更新版本。我记得很多人在这张 alpine expecialy 图像中的网络问题中挣扎着反应应用程序和 php 应用程序。如果您正在使用 supervisord 运行 nginx 来检查该子进程或 stopasgroup 等上的停止信号,我建议您做的另一件事是,因为该配置有几个配置。 另一件可能改进的事情是正常关闭,您可以在 deployment.yml 中这样做 如果您遇到系统 OOM,还要检查 kubernetes 事件。

,

好的!经过大量反复试验和错误,这最终对我们有用。

1.我们在前端/上游 nginx 容器和部署中设置了活跃度和准备情况探测。

nginx.conf

# default server block
location /healthz {
   auth_basic off;
   allow all;
   return 200;
}

deployment.yaml

#spec.containers
livenessProbe:
  failureThreshold: 1
  httpGet:
    path: /healthz
    port: 80
readinessProbe:
  failureThreshold: 3
  httpGet:
    path: /healthz
    port: 80

毫无疑问,这确保了当我们的 nginx 容器失败时,无论出于何种原因,它们都会重新启动。

2.我们为 nginx 容器设置了平滑关闭

deployment.yaml

#spec.containers
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh","-c","sleep 3; nginx -s quit; while pgrep -x nginx; do sleep 1; done"]

这确保了当重启发生时,nginx 容器实际上关闭而不会丢失连接(尽管公平地说,这种情况很少见)。

3.最低 CPU 和内存请求

有了上述两个变化,感觉我们处于一个很好的位置。在此之前,我们将每个前端部署扩展到 3 个副本。仅仅一个晚上之后,似乎是随机选择的,几个 FE 部署中的一些副本(我们已经设置了几个用于测试,dev-1 到 dev-20)重新启动了 800 次!疯了!

我们不知道是什么导致了这种情况。但一时兴起,我们最终添加了一些最小 CPU 和内存请求,最终解决了重启/失败循环。

# spec.containers
resources:
  requests:
    cpu: 0.001
    memory: 4M

最后的笔记

从上面可以看出,我们确实在现有的部署设置中添加了大量配置和工作。但这些都与 Ingress 无关,而是我们所有的上游 nginx 容器。

活性探测非常严格,因为一旦容器开始起作用,该容器就结束了。我们没有看到容器自行修复,所以一旦活跃度探​​测器发现健康检查失败,我们就可以强制重启。

preStop 命令大致是 kubernetes 文档中关于 preStop 命令的推荐为 nginx 的默认命令,如 here 所示。在另一个 stackOverflow question 中找到了 sleep 3,而在这个 medium article 中使用了 pgrep。这绝对是一个拼凑而成的停止命令,但它似乎对我们有用。

最后,我们遇到的最小 CPU 请求和内存请求基于我们所有 FE 部署的指标。 0.001 CPU 是高负载时的平均使用率,4M 是高负载时的平均内存使用率。认为最好在这里对冲下注并使用比我们需要的略多的 CPU/内存(尽管显然这个 CPU 使用率很小)。

我不完全确定为什么设置请求最终解决了重启问题。如果我不得不猜测,给出请求允许 kubernetes 找到更好的节点来放置这些 pod。也许经常出现故障的 Pod 被塞进了一个或另一个节点的极限,因此任何实际使用都会导致故障。

我希望这对未来的某人有所帮助,或者这可能是我们自己制造的怪物,每个人都已经知道要执行上述所有操作。

祝找到这个的人好运!