概要

PostgreSQLのバックアップをpg_dumpコマンドを使って取得した後、そのファイルをGCSにアップロードすることを想定します。スケジュールはKubernetesのCronJobに任せます。pg_dumpを実行する際にパスワードをベタ書きするわけには行かないのでSecretを作成し、それをマウントすることでパスワード認証できるようにします。Kubernetesのバージョンはv1.27.7-gkeで実施しました。

Dockerfile

まずはコンテナイメージを作成します。postgresql-clientgcloudコマンドをインストールします。ユーザーは root以外のユーザーで実行することを想定します。

FROM ubuntu:24.04

ARG GOOGLE_CLOUD_CLI_VERSION=469.0.0
ARG USER=postgres-client
ARG UID=1001

RUN apt-get update && apt-get install -y --no-install-recommends \
    apt-transport-https \
    ca-certificates \
    gnupg \
    curl \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

RUN useradd -m -s /bin/bash -u ${UID} ${USER}

USER ${USER}

WORKDIR /home/${USER}

RUN curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GOOGLE_CLOUD_CLI_VERSION}-linux-x86_64.tar.gz \
    && tar -xf google-cloud-cli-${GOOGLE_CLOUD_CLI_VERSION}-linux-x86_64.tar.gz \
    && ./google-cloud-sdk/install.sh -q

ENV PATH $PATH:/home/${USER}/google-cloud-sdk/bin

ConfigMap

バックアップ用のスクリプトをConfigMapで設定します。pg_dumpgcloudコマンドでGCSにファイルをアップロードする簡単なスクリプトです。

apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-backup-script
data:
  backup-database-to-gcs.sh: |
    #!/bin/bash -xe
    hostname=${1:-localhost}
    port=${2:-5432}
    user=${3:-postgres}
    database=${4:-postgres}
    bucket=${5:-hoge}
    filename="backup-${database}-postgres-$(date +"%Y-%m-%d").gz"

    pg_dump -h ${hostname} -U ${user} -p ${port} ${database} | gzip -c > ${filename}
    gcloud storage cp ${filename} gs://${bucket}/${filename}

Secret

続いてPostgreSQLに接続で利用するパスワードを含む情報をSecretに設定します。 .pgpass の書き方は公式Documentに記載がありますので参考にします。

apiVersion: v1
kind: Secret
metadata:
  name: pgpass-secret
type: Opaque
data:
  .pgpass: [BASE64_ENCODED_PGPASS_STRING]

ServiceAccount

CronJobを実行する際のServiceAccountを作成します。今回はGCSへのファイルアップロードにWorkload Identityを利用します。以下、annotationsにGCPのサービスアカウントを記載することで、GCSへのアップロードを実現します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: postgres-client
  annotations:
    iam.gke.io/gcp-service-account: [GCP_SERVICE_ACCOUNT_NAME]

Workload Identityの設定については事前にGCPのサービスアカウントを作成して、 roles/iam.workloadIdentityUserを付与しておく必要があります。詳細はこちら

CronJob

CronJobを作成します。注意する点は以下の通りです。

  • serviceAccountName: [GCP_SERVICE_ACCOUNT_NAME]に作成したServiceAccountを設定します。
  • initContainersを利用して、ファイルの所有者を変更します。所有者を変更するため、initコンテナはrootユーザーで起動します。
  • Volumesには、pgpass-secret-ownership-changedemptyDir: {}で作成し、initコンテナで所有者を変更後、メインのコンテナにアタッチします。
    • .pgpass はパーミッションを0600に設定しないといけません。fsGroupを使った場合、グループ権限のみが変更され、所有者はrootのままなので要件を満たしません。
  • timezoneがUTCかどうかはご利用の環境に依存します。
apiVersion: batch/v1
kind: CronJob
metadata:
  name: postgres-backup
spec:
  schedule: "0 1 * * *" # every day at 1:00 UTC (10:00 JST)
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: [GCP_SERVICE_ACCOUNT_NAME]
          restartPolicy: OnFailure
          initContainers:
          # .pgpassファイルの所有者をrootから実行ユーザーに変更する
          - name: postgres-backup-init
            image: [IMAGE_NAME]
            command: ["sh", "-c", "cd /home/postgres-client; cp .pgpass ./pgpass; chown -R 1001:1001 ./pgpass"]
            securityContext:
              runAsUser: 0
            volumeMounts:
            - name: pgpass-secret
              mountPath: /home/postgres-client/.pgpass
              subPath: .pgpass
            - mountPath: /home/postgres-client/pgpass
              name: pgpass-secret-ownership-changed
          containers:
          - name: postgres-backup
            image: [IMAGE_NAME]
            command: 
            - /home/postgres-client/backup-database-to-gcs.sh
            env:
              - name: PGPASSFILE
                value: /home/postgres-client/pgpass/.pgpass
            volumeMounts:
            - name: postgres-backup-script
              mountPath: /home/postgres-client/backup-database-to-gcs.sh
              subPath: backup-database-to-gcs.sh
            - name: pgpass-secret-ownership-changed
              mountPath: /home/postgres-client/pgpass
          volumes:
          - name: postgres-backup-script
            configMap:
              name: postgres-backup-script
              items:
              - key: backup-database-to-gcs.sh
                path: backup-database-to-gcs.sh
                mode: 0755
          - name: pgpass-secret
            secret:
              secretName: pgpass-secret
              defaultMode: 0600
          - name: pgpass-secret-ownership-changed
            emptyDir: {}

以上で、pg_dumpコマンドの実行の際に .pgpassからパスワードを読み取り接続してくれます。また、環境変数にPGPASSFILEを設定することで、任意のフォルダにファイルを置くことができます。その際もパーミッションは 0600の必要がありますのでご注意ください。