我有一个Kubernetes JOB
,可以在CloudSQL数据库上进行数据库迁移
从GKE访问CloudSQL数据库的一种方法是使用CloudSQL代理容器,然后通过localhost
连接。太棒了 - 到目前为止工作正常。但是因为我在K8s JOB
内部这样做,所以作业没有被标记为成功完成,因为代理继续运行。
$ kubectrl get po
NAME READY STATUS RESTARTS AGE
db-migrations-c1a547 1/2 Completed 0 1m
即使输出显示“已完成”,最初的两个容器之一仍在运行 - 代理。
如何在完成容器1内的迁移时退出代理?
答案 0 :(得分:10)
一种可能的解决方案是使用匹配服务的单独的cloudql-proxy部署。然后,您只需要在连接到代理服务的作业中使用迁移容器。
这有一些缺点:
如果要将cloudql-proxy打开到整个群集,则必须在cloudsql-proxy上的tcp:3306
参数中将tcp:0.0.0.0:3306
替换为-instance
。
答案 1 :(得分:4)
有3种方法。
1-如@newoxo在答案之一中所述,使用私有IP将K8s作业连接到Cloud SQL。为此,您的群集必须是VPC本地群集。我的不是,我不是想将我所有的东西搬到一个新的集群中。因此我无法做到这一点。
2-如@Christian Kohler所述,将Cloud SQL Proxy容器放置在带有服务的单独部署中。这看起来是个好方法,但是Google Cloud Support不建议这样做。
我正朝这个方向前进(解决方案2),但我决定尝试其他方法。
这是最适合我的解决方案:
3-您可以使用文件系统在同一Pod / Job中的不同容器之间进行通信。这个想法是要告诉Cloud SQL Proxy容器何时完成主要作业,然后终止Cloud sql代理。这是操作方法:
在yaml文件(my-job.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:
基本上,当您完成主要工作时,它将在/ lifecycle中创建一个文件,该文件将由添加到cloud-sql-proxy容器的观察者识别,这将终止代理并终止该容器。
希望对您有所帮助!如果您有任何问题,请告诉我。
答案 2 :(得分:3)
看起来Kubernetes不能单独执行此操作,您需要在迁移退出后手动终止代理。类似的问题在这里问:Sidecar containers in Kubernetes Jobs?
答案 3 :(得分:0)
一种可能的解决方案是在作业concurrencyPolicy: Replace
中设置spec
……这将在需要再次运行时将其用新实例不可知地替换。但是,您必须确保后续的cron运行足够分开。
答案 4 :(得分:0)
Google Cloud sql最近为cloudsql启动了专用ip地址连接。如果Cloud sql实例和kubernetes集群位于同一区域,则可以不使用Cloud sql代理即可连接到cloudsql。
答案 5 :(得分:0)
我发现最好的方法是在容器之间share the process namespace,并使用SYS_PTRACE securityContext功能允许您杀死边车。
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"