在 Kubernetes 中,控制容器终止顺序的方式是什么?

6

我有一个pod里面有两个容器,一个是我的应用程序容器,另一个是CloudSQL代理容器。基本上,我的应用程序容器依赖于这个CloudSQL容器。

问题是当pod被终止时,CloudSQL代理容器首先被终止,仅在几秒钟后才终止我的应用程序容器。

因此,在我的容器终止之前,它继续向CloudSQL容器发送请求,导致错误:

could not connect to server: Connection refused Is the server running on host "127.0.0.1" and accepting TCP/IP connections on port 5432

这就是为什么我认为指定终止顺序是个好主意,这样我的应用容器就会先终止,然后再终止cloudsql。
在文档中我没有找到任何可以做到这一点的方法。但也许有办法。

你是如何让CloudSQL代理容器终止的?我有一个类似于你描述的设置,但我的代理容器永远不会终止。你是怎么做到的? - Marcus Vinicius Melo
1
@MarcusViniciusMelo 那是很久以前的事情了,所以我不记得细节了。但那时候没有办法指定顺序。我做了一些 hacky 的东西来解决这个问题。有一个容器的生命周期钩子,你可以在终止之前指定一个脚本运行。我编写了一个简单的脚本,在终止之前等待 30 秒,足够时间让我的应用程序容器先终止。 - Jahongir Rahmonov
嗯,我明白了。非常感谢,我想我知道这是什么机制了。我会尝试一下。 - Marcus Vinicius Melo
1个回答

8
目前在 Kubernetes pod API 中直接实现这一点是不可能的。容器可以以任何顺序终止。例如,Cloud SQL pod 可能比您的应用程序更快地死亡,如果它需要执行较少的清理或者有较少的正在进行的请求需要排空。
来自 Pods 的终止
当用户请求删除 pod 时,系统会记录 pod 被强制终止之前的优雅期限,并向每个容器中的主进程发送 TERM 信号。

您可以通过将Cloud SQL和主容器包装在不同的入口点中来解决这个问题,它们使用共享的Pod级文件系统相互通信其退出状态。

此解决方案不适用于Cloud SQL代理1.16版本(请参阅评论),因为此版本停止将shell与容器捆绑在一起。1.17版本现在在Alpine或Debian Buster变体中可用,因此此版本现在是一个可行的升级目标,再次与此解决方案兼容。

以下包装程序可能有助于解决此问题:

containers:
- command: ["/bin/bash", "-c"]
  args:
  - |
    trap "touch /lifecycle/main-terminated" EXIT
    <your entry point goes here>
  volumeMounts:
  - name: lifecycle
    mountPath: /lifecycle
- name: cloudsql_proxy
  image: gcr.io/cloudsql-docker/gce-proxy
  command: ["/bin/bash", "-c"]
  args:
  - |
    /cloud_sql_proxy <your flags> &
    PID=$!

    function stop {
        while true; do
            if [[ -f "/lifecycle/main-terminated" ]]; then
                kill $PID
            fi
            sleep 1
        done
    }
    trap stop EXIT
    # We explicitly call stop to ensure the sidecar will terminate
    # if the main container exits outside a request from Kubernetes
    # to kill the Pod.
    stop &
    wait $PID
  volumeMounts:
  - name: lifecycle
    mountPath: /lifecycle

您还需要一个本地的临时空间,用于通信生命周期事件:

volumes:
- name: lifecycle
  emptyDir:

该解决方案如何工作?它在Cloud SQL代理容器中拦截Kubernetes监管员传递给每个Pod容器的SIGTERM信号。运行在该容器中的“主进程”是一个shell,它已经产生了运行Cloud SQL代理的子进程。因此,Cloud SQL代理不会立即终止。相反,shell代码会阻塞等待来自已成功退出的主容器的信号(通过简单手段,在文件系统中出现的文件)。只有在那一点上,Cloud SQL代理进程才会终止并返回旁路容器。
当然,这对于强制终止没有影响,如果您的容器关闭花费太长时间并超过配置的优雅期限。
该解决方案取决于您运行的容器是否为其提供了可用的shell;这对于Cloud SQL代理是正确的(除1.16和1.17使用alpine或debian变体之外),但您可能需要更改本地容器构建以确保您自己的应用容器也是如此。

谢谢。我会尝试这个并告诉你结果。 - Jahongir Rahmonov
自v1.16版本开始,此方法已不再适用,因为您无法再访问shell。请参见https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/317。 - trev9065
@trev9065 感谢您指出这一点。我已经修改了答案的文本,特别标识这是一个当前的问题。 - Cosmic Ossifrage
1
FYI,这里有一个新的更新,Google现在有一个运行在Alpine和Buster上的CloudSQL代理映像,因此您现在可以升级到v1.17-alpine/buster。https://console.cloud.google.com/gcr/images/cloudsql-docker/GLOBAL/gce-proxy?gcrImageListsize=30 - trev9065
我不得不删除 trap stop EXIT 这行代码。因为它一遍又一遍地失败并显示 can't kill pid 7: No such process - jobevers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接