概要
PostgreSQLのバックアップをpg_dumpコマンドを使って取得した後、そのファイルをGCSにアップロードすることを想定します。スケジュールはKubernetesのCronJobに任せます。pg_dumpを実行する際にパスワードをベタ書きするわけには行かないのでSecretを作成し、それをマウントすることでパスワード認証できるようにします。Kubernetesのバージョンはv1.27.7-gkeで実施しました。
Dockerfile
まずはコンテナイメージを作成します。postgresql-clientとgcloudコマンドをインストールします。ユーザーは 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/binConfigMap
バックアップ用のスクリプトをConfigMapで設定します。pg_dumpとgcloudコマンドで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-changedをemptyDir: {}で作成し、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の必要がありますのでご注意ください。