Kubernetes:在多容器Pod / Job中停止CloudSQL-proxy sidecar容器

时间:2017-01-16 15:06:53

标签: docker kubernetes google-cloud-sql

我有一个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内的迁移时退出代理?

6 个答案:

答案 0 :(得分:10)

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

这有一些缺点:

  • 更高的网络延迟,没有pod本地mysql通信
  • 如果您为整个kubernetes集群提供sql端口,则可能存在安全问题

如果要将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容器的观察者识别,这将终止代理并终止该容器。

希望对您有所帮助!如果您有任何问题,请告诉我。

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

答案 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"