【问题标题】:Nginx container not restarting after shutdown in Kubernetes在 Kubernetes 中关闭后 Nginx 容器未重新启动
【发布时间】:2021-06-23 15:35:09
【问题描述】:

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

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

这是我们为感兴趣的人提供的所有配置的要点: gist

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

稳定的高山

稳定

主线高山

1.17.10-高山

所有结果都产生相同的日志集。

我尝试过的事情:

  • 更改 FE 的 nginx 版本
  • 告诉 nginx-ingress 使用 HTTP 1
  • 告诉 nginx-ingress 不要使用 GZIP
  • 使用了本网站的所有内容tencent high availability in nginx blog post
  • 为整个 nginx-ingress 和每个单独的 child-ingress 打开和关闭代理缓冲
  • 在 nginx-ingress 中将 max-temp-file-size 设置为 0
  • 在 nginx-ingress 中将 max-temp-file-size 设置为 10M
  • 从对上游的请求中删除了 Accept Encoding、Content-Length 和 Content-Type
  • 为 FE 容器启用 Gzip
  • 将工作进程设置为自动,在 FE 容器中将工作进程设置为 1
  • 设置keepalive-timeout为65,在FE容器中设置为15
  • 更新了 FE 部署的生命周期 preStop
  • 从 FE 部署中将 terminateGracePeriodSeconds 设置为 60(然后将其删除)

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

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

当然,如果有人知道为什么 nginx 容器首先被告知要关闭,那也会很有帮助。

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

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

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

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

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

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

【问题讨论】:

  • 请告诉我们您是只使用 Kubernetes 还是使用 GKE?

标签: docker nginx kubernetes google-kubernetes-engine nginx-ingress


【解决方案1】:

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

【讨论】:

  • 我已经尝试了标准的稳定版本,我相信它是在 1.18 上,它没有任何新的或不同的效果。
【解决方案2】:

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

1。我们在前端/上游 nginx 容器和部署中设置了 liveliness & readiness 探针。

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 文档 ON preStop 命令中推荐的 nginx 默认值,如 here 所示。在另一个stackOverflow question中发现了sleep 3,而在这个medium article中使用了pgrep。这绝对是一个拼凑而成的停止命令,但它似乎对我们有用。

最后,我们得出的最低 CPU 请求和内存请求基于我们所有 FE 部署的指标。 0.001 CPU 是高负载期间的平均使用率,4M 是高负载期间内存的平均使用率。认为最好在这里对冲下注并使用比我们需要的稍微多一点的 CPU/内存(尽管显然这种 CPU 使用率很小)。

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

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

祝找到这个的人好运!

【讨论】:

    猜你喜欢
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 2022-01-06
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    相关资源
    最近更新 更多