目前在 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
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变体之外),但您可能需要更改本地容器构建以确保您自己的应用容器也是如此。