目前,Kubernetes pod API 无法直接实现这一点。容器可以按任何顺序终止。Cloud SQL pod 可能会比您的应用程序更快地死亡,例如,如果要执行的清理较少或要消耗的运行中请求较少。
从Pod 的终止:
当用户请求删除一个 pod 时,系统会记录该 pod 被强制杀死之前的预期宽限期,并向每个容器中的主进程发送一个 TERM 信号。
您可以通过将 Cloud SQL 和主容器包装在不同的入口点中来在一定程度上解决此问题,这些入口点使用共享的 pod 级文件系统在彼此之间传达它们的退出状态。
此解决方案不适用于 Cloud SQL 代理的 1.16 版本(请参阅评论),因为此版本不再将外壳与容器捆绑在一起。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 代理容器中拦截SIGTERM
Kubernetes 主管在关闭时传递给每个 pod 容器的信号。在该容器中运行的“主进程”是一个 shell,它产生了一个运行 Cloud SQL 代理的子进程。因此,Cloud SQL 代理不会立即终止。相反,shell 代码会阻塞等待它已成功退出的主容器的信号(通过文件系统中出现的文件的简单方式)。只有在此时,Cloud SQL 代理进程才会终止,sidecar 容器才会返回。
当然,如果您的容器关闭时间过长并超过配置的宽限期,这对强制终止没有影响。
解决方案取决于您正在运行的容器是否有可用的外壳;Cloud SQL 代理也是如此(1.16 和 1.17 及更高版本使用alpine
ordebian
变体时除外),但您可能需要对本地容器构建进行更改,以确保您自己的应用程序容器也是如此。