Kubernetes:在多容器Pod/Job中停止CloudSQL代理sidecar容器



我有一个KubernetesJOB,它在CloudSQL数据库上执行数据库迁移
从GKE访问CloudSQL数据库的一种方法是使用CloudSQL代理容器,然后通过localhost进行连接。太好了,到目前为止效果不错。但是,因为我在K8sJOB中执行此操作,所以作业没有标记为成功完成,因为代理仍在运行。

$ kubectrl get po
NAME                      READY     STATUS      RESTARTS   AGE
db-migrations-c1a547      1/2       Completed   0          1m

尽管输出显示"已完成",但最初两个容器中的一个仍在运行——代理。

在容器1内完成迁移时,如何使代理退出?

我发现的最好的方法是在容器之间共享进程名称空间,并使用SYS_PTRACE securityContext功能来杀死sidecar。

apiVersion: batch/v1
kind: Job
metadata:
name: my-db-job
spec:
template:
spec:
restartPolicy: OnFailure
shareProcessNamespace: true
containers:
- name: my-db-job-migrations
command: ["/bin/sh", "-c"]
args:
- |
<your migration commands>;
sql_proxy_pid=$(pgrep cloud_sql_proxy) && kill -INT $sql_proxy_pid;
securityContext:
capabilities:
add:
- SYS_PTRACE
- name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.17
command:
- "/cloud_sql_proxy"
args:
- "-instances=$(DB_CONNECTION_NAME)=tcp:5432"

一个可能的解决方案是使用匹配的服务单独部署cloudsql代理。然后,您只需要在连接到代理服务的作业中使用迁移容器。

这有一些缺点:

  • 更高的网络延迟,没有pod本地mysql通信
  • 如果将sql端口提供给整个kubernetes集群,可能会出现安全问题

如果要打开整个集群的cloudsql代理,则必须将cloudsql代理上的-instance参数中的tcp:3306替换为tcp:0.0.0.0:3306

有三种方法可以做到这一点。

1-使用私有IP将K8s作业连接到Cloud SQL,如@newoxo在其中一个答案中所述。要做到这一点,您的集群需要是VPC本机集群。我的不是,我也没有呼啸着把我所有的东西都搬到一个新的集群。所以我没能做到这一点。

2-如@Christian Kohler所述,将云SQL代理容器与服务单独部署。这看起来是一个很好的方法,但谷歌云支持不建议这样做。

我正要朝这个方向前进(解决方案2),但我决定尝试其他方法。

这是对我有效的解决方案:

3-您可以使用文件系统在同一Pod/Job中的不同容器之间进行通信。这个想法是告诉云SQL代理容器主工作何时完成,然后终止云SQL代理。以下是操作方法:

在yaml文件(我的工作.yaml)

apiVersion: v1
kind: Pod
metadata:
name: my-job-pod
labels:
app: my-job-app
spec:
restartPolicy: OnFailure
containers:
- name: my-job-app-container
image: my-job-image:0.1
command: ["/bin/bash", "-c"]
args:
- |
trap "touch /lifecycle/main-terminated" EXIT
{ your job commands here }
volumeMounts:
- name: lifecycle
mountPath: /lifecycle
- name: cloudsql-proxy-container
image: gcr.io/cloudsql-docker/gce-proxy:1.11
command: ["/bin/sh", "-c"]
args:
- |
/cloud_sql_proxy -instances={ your instance name }=tcp:3306 -credential_file=/secrets/cloudsql/credentials.json &
PID=$!
while true
do
if [[ -f "/lifecycle/main-terminated" ]] 
then
kill $PID
exit 0
fi
sleep 1
done
securityContext:
runAsUser: 2  # non-root user
allowPrivilegeEscalation: false
volumeMounts:
- name: cloudsql-instance-credentials
mountPath: /secrets/cloudsql
readOnly: true
- name: lifecycle
mountPath: /lifecycle
volumes:
- name: cloudsql-instance-credentials
secret:
secretName: cloudsql-instance-credentials
- name: lifecycle
emptyDir:

基本上,当您的主要工作完成时,它将在/hifecycle中创建一个文件,该文件将由添加到云sql代理容器的观察者标识,这将终止代理并终止容器。

我希望它能有所帮助!如果你有任何问题,请告诉我。

基于:https://stackoverflow.com/a/52156131/7747292

看起来Kubernetes不能单独完成这项工作,一旦迁移退出,您需要手动终止代理。这里提出了类似的问题:Kubernetes Jobs中的Sidecar容器?

谷歌云sql最近推出了cloudsql的私有ip地址连接。如果云sql实例和kubernetes集群在同一个区域,您可以在不使用云sql代理的情况下连接到cloudsql。

https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine#private-ip

一个可能的解决方案是在作业spec中设置concurrencyPolicy: Replace。。。每当需要再次运行时,这将不可知地用新实例替换当前pod。但是,您必须确保后续的cron运行足够分离。

不幸的是,其他答案对我来说不起作用,因为CloudSQLProxy运行在没有shell的发行版环境中。

我通过将CloudSQLProxy二进制文件与我的部署捆绑在一起,并运行bash脚本来启动CloudSQLProxy,然后启动我的应用程序,从而解决了这一问题。

Dockerfile:

FROM golang:1.19.4
RUN apt update
COPY . /etc/mycode/
WORKDIR /etc/mycode
RUN chmod u+x ./scripts/run_migrations.sh
RUN chmod u+x ./bin/cloud_sql_proxy.linux-amd64
RUN go install
ENTRYPOINT ["./scripts/run_migrations.sh"]

外壳脚本(run_migrations.sh):

#!/bin/sh
# This script is run from the parent directory
dbConnectionString=$1
cloudSQLProxyPort=$2
echo "Starting Cloud SQL Proxy"
./bin/cloud_sql_proxy.linux-amd64 -instances=${dbConnectionString}=tcp:5432 -enable_iam_login -structured_logs &
CHILD_PID=$!
echo "CloudSQLProxy PID: $CHILD_PID"
echo "Migrating DB..."
go run ./db/migrations/main.go
MAIN_EXIT_CODE=$?
kill $CHILD_PID;
echo "Migrations complete.";
exit $MAIN_EXIT_CODE

K8s(通过Pulumi):

import * as k8s from '@pulumi/kubernetes'
const jobDBMigrations = new k8s.batch.v1.Job("job-db-migrations", {
metadata: {
namespace: namespaceName,
labels: appLabels,
},
spec: {
backoffLimit: 4,
template: {
spec: {
containers: [
{
image: pulumi.interpolate`gcr.io/${gcpProject}/${migrationsId}:${migrationsVersion}`,
name: "server-db-migration",
args: [
dbConnectionString,
],
},
],
restartPolicy: "Never",
serviceAccount: k8sSAMigration.metadata.name,
},
},
},
},
{
provider: clusterProvider,
});

Cloud sql proxy 2支持一个quitquitquit端点,该端点可用于关闭sidecar代理。不再需要诸如共享进程空间或写入文件之类的变通方法。

只需将--quitquitquit标志添加到sql云代理中,并通过在作业定义的args中发送POST请求来终止sidecar:

;exit_code=$?; curl -X POST localhost:9091/quitquitquit && exit $exit_code

点击此处阅读更多信息:https://github.com/GoogleCloudPlatform/cloud-sql-proxy/issues/828

相关内容

  • 没有找到相关文章