目前使用 Kubernetes pod API 还不能直接实现这一点。容器可以按任何顺序终止。 Cloud SQL Pod 可能比您的应用程序更快消亡,例如,如果它需要执行的清理工作较少或需要消耗的正在进行的请求较少。
From Pod 的终止 https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods:
当用户请求删除 Pod 时,系统会记录允许强制杀死 Pod 之前的预期宽限期,并向每个容器中的主进程发送 TERM 信号。
您可以通过将 Cloud SQL 和主容器包装在不同的入口点中来在一定程度上解决此问题,这些入口点使用共享的 Pod 级文件系统在彼此之间传达退出状态。
此解决方案不适用于 Cloud SQL 代理 1.16 版本(看评论 https://stackoverflow.com/questions/52148322/control-order-of-container-termination-in-a-single-pod-in-kubernetes/52156131?noredirect=1#comment110296216_52156131)因为此版本不再将外壳与容器捆绑在一起。 1.17 版本是现在有 Alpine 或 Debian Buster 版本 https://console.cloud.google.com/gcr/images/cloudsql-docker/GLOBAL/gce-proxy?gcrImageListsize=30,因此该版本现在是一个可行的升级目标,再次与该解决方案兼容。
像下面这样的包装器可能会有所帮助:
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 代理容器中拦截SIGTERM
关闭时 Kubernetes Supervisor 向每个 Pod 容器传递的信号。该容器中运行的“主进程”是一个 shell,它生成了一个运行 Cloud SQL 代理的子进程。因此,Cloud SQL 代理不会立即终止。相反,shell 代码会阻塞等待来自主容器的已成功退出的信号(通过文件系统中出现的简单方式)。仅在此时,Cloud SQL 代理进程才会终止,并且 sidecar 容器才会返回。
当然,如果您的容器关闭时间过长并超过配置的宽限期,这对强制终止没有影响。
解决方案取决于您正在运行的容器是否有可用的 shell; Cloud SQL 代理也是如此(1.16 和 1.17 及以上版本除外,当使用alpine
or debian
变体),但您可能需要对本地容器构建进行更改,以确保您自己的应用程序容器也是如此。