⚙️

Cloud Buildからpsqldefを使用してCloud SQL for PostgreSQLにマイグレーションする

2022/12/15に公開

はじめに

こんにちは、株式会社トレタのサーバーサイドエンジニアの @shiroemons です。

https://tech.toreta.in/entry/2022/12/15/cloud-build-psqldef-cloud-sql

現在のプロジェクトでは、Cloud Buildを用いてdocker buildやCloud Runへのデプロイを行っています。

また、データベース(Cloud SQL)へのマイグレーションもCloud Buildから行っています。

今回は、Cloud Buildからpsqldefというマイグレーションツールを使用して、Cloud SQL for PostgreSQLにマイグレーションする方法を紹介します。

ただし、Cloud SQL for PostgreSQLなどの設定は完了している前提のため、省略しています。

psqldefとは

SQLで羃等にDBスキーマ管理ができるツール「sqldef」のPostgreSQL用のツールです。

https://github.com/k0kubun/sqldef

PostgreSQL用の他に、MySQL用のmysqldefやSQLite3用のsqlite3defなども存在します。

sqldefについての細かい説明は、ここでは省略します。

Cloud Buildとは

Cloud Buildは、Google Cloud 上でビルドを実行するサービスです。

Cloud Buildでは、ビルド構成ファイルと呼ばれる設定ファイルにビルドやデプロイの方法(指示)を記述します。記述した指示に基づいてタスクを実行し、ビルドやデプロイを行います。

Cloud SQLへのマイグレーションで使用した構成ファイルの紹介と説明をします。

Cloud Buildの構成ファイル

Cloud SQLへのマイグレーションで使用したCloud Buildの構成ファイルはこちらになります。

  • cloudbuild-migration.yaml
steps:
  - name: gcr.io/cloud-builders/wget
    args:
      - 'https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64'
      - '-O'
      - ./cloud_sql_proxy
    id: cloud_sql_proxy download
  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - |
        chmod +x ./cloud_sql_proxy && ./cloud_sql_proxy --version
    id: cloud_sql_proxy version
    entrypoint: bash
  - name: gcr.io/cloud-builders/wget
    args:
      - >-
        https://github.com/k0kubun/sqldef/releases/latest/download/psqldef_linux_amd64.tar.gz
    id: psqldef download
  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - |
        tar -zxvf psqldef_linux_amd64.tar.gz && ./psqldef --version
    id: psqldef version
    entrypoint: bash
  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - >
        ./cloud_sql_proxy -instances=$_INSTANCE_CONNECTION_NAME=tcp:$_DATABASE_PORT & sleep $_SLEEP_SEC;
        ./psqldef --dry-run --file $_SCHEMA_FILE --host $_DATABASE_HOST --port $_DATABASE_PORT --user $_DATABASE_USER --password $$DATABASE_PASS $_DATABASE_NAME
    id: psqldef dry-run
    entrypoint: bash
    secretEnv:
      - DATABASE_PASS
  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - >
        ./cloud_sql_proxy -instances=$_INSTANCE_CONNECTION_NAME=tcp:$_DATABASE_PORT & sleep $_SLEEP_SEC;
        ./psqldef --file $_SCHEMA_FILE --host $_DATABASE_HOST --port $_DATABASE_PORT --user $_DATABASE_USER --password $$DATABASE_PASS $_DATABASE_NAME
    id: psqldef execute
    entrypoint: bash
    secretEnv:
      - DATABASE_PASS
substitutions:
  _SCHEMA_FILE: ./schema.sql
  _DATABASE_HOST: 127.0.0.1
  _DATABASE_PORT: '5432'
  _DATABASE_NAME: db_name
  _DATABASE_USER: db_user
  _DATABASE_PASSWORD_KEY: database_password
  _INSTANCE_REGION: asia-northeast1
  _INSTANCE_ID: database
  _INSTANCE_CONNECTION_NAME: '${PROJECT_ID}:${_INSTANCE_REGION}:${_INSTANCE_ID}'
  _SLEEP_SEC: '5'
availableSecrets:
  secretManager:
    - versionName: >-
        projects/$PROJECT_ID/secrets/${_DATABASE_PASSWORD_KEY}/versions/latest
      env: DATABASE_PASS

(代入変数部分を変更して動作することを確認しています。)

各ビルドステップの説明

  • よく使用するフィールドについて簡単に説明します。
    • name: クラウドビルダーの指定(Docker..etc)
    • args: ビルダーに渡す引数のリスト
    • id: ビルドステップに対して一意の識別子
    • entrypoint: エントリポイントを指定 (bash etc)
    • secretEnv: Cloud KMS暗号鍵を使用して暗号化された環境変数のリスト
  • 詳しい説明は、 ビルド構成ファイルの構造 を参照ください。

ステップ1: Cloud SQL Proxyのダウンロード

  - name: gcr.io/cloud-builders/wget
    args:
      - 'https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64'
      - '-O'
      - ./cloud_sql_proxy
    id: cloud_sql_proxy download
  • Cloud SQLに接続する際、Cloud SQL Proxyを使用して接続します。
    • Cloud SQL Proxy を使用するには、Cloud SQL Admin API を有効にする必要があります。
    • こちらから有効にできます。
  • Cloud SQL Proxyをwgetでダウンロードします。

ステップ2: Cloud SQL Proxyの実行権限付与とCloud SQL Proxyのバージョン確認

  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - |
        chmod +x ./cloud_sql_proxy && ./cloud_sql_proxy --version
    id: cloud_sql_proxy version
    entrypoint: bash
  • ダウンロードしたCloud SQL Proxyに実行権限を付与します。
  • どのバージョンを使用したかわかるようにバージョンを確認します。
  • ファイルの存在確認の意図もあります。

ステップ3: psqldef の最新版をダウンロード

  - name: gcr.io/cloud-builders/wget
    args:
      - >-
        https://github.com/k0kubun/sqldef/releases/latest/download/psqldef_linux_amd64.tar.gz
    id: psqldef download
  • マイグレーションに必要なpsqldef(最新版)をwgetでダウンロードします。

ステップ4: psqldef の解凍とpsqldef のバージョン確認

  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - |
        tar -zxvf psqldef_linux_amd64.tar.gz && ./psqldef --version
    id: psqldef version
    entrypoint: bash
  • ダウンロードしたpsqldefは圧縮されているため解凍します。
  • どのバージョンを使用したかわかるようにバージョンを確認します。
  • ファイルの存在確認の意図もあります。

ステップ5: psqldef の dry-run 実行

  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - >
        ./cloud_sql_proxy -instances=$_INSTANCE_CONNECTION_NAME=tcp:$_DATABASE_PORT & sleep $_SLEEP_SEC;
        ./psqldef --dry-run --file $_SCHEMA_FILE --host $_DATABASE_HOST --port $_DATABASE_PORT --user $_DATABASE_USER --password $$DATABASE_PASS $_DATABASE_NAME
    id: psqldef dry-run
    entrypoint: bash
    secretEnv:
      - DATABASE_PASS
  • Cloud SQLに接続する場合、Cloud SQL Proxyを先に起動しておく必要があります。
  • Cloud SQL Proxyの起動に一定時間かかるため sleep を入れています。
  • 設定に必要な値は、すべて代入変数で定義しておきます。
    • 代入変数を用いることでビルド構成ファイル自体の変更をしなくてもよくなります。
  • psqldefを本実行する前に、dry-runで実行してエラーがないことを確認しておきます。
  • DBのパスワードは、Secret Managerに保存して使用しています。

ステップ6: psqldef の 実行

  - name: gcr.io/cloud-builders/gcloud
    args:
      - '-c'
      - >
        ./cloud_sql_proxy -instances=$_INSTANCE_CONNECTION_NAME=tcp:$_DATABASE_PORT & sleep $_SLEEP_SEC;
        ./psqldef --file $_SCHEMA_FILE --host $_DATABASE_HOST --port $_DATABASE_PORT --user $_DATABASE_USER --password $$DATABASE_PASS $_DATABASE_NAME
    id: psqldef execute
    entrypoint: bash
    secretEnv:
      - DATABASE_PASS

内容は、dry-runとほぼ同じです。psqldefのdry-runオプションを外した内容です。

代入変数(substitutions)の説明

substitutions:
  _SCHEMA_FILE: ./schema.sql
  _DATABASE_HOST: 127.0.0.1
  _DATABASE_PORT: '5432'
  _DATABASE_NAME: db_name
  _DATABASE_USER: db_user
  _DATABASE_PASSWORD_KEY: database_password
  _INSTANCE_REGION: asia-northeast1
  _INSTANCE_ID: database
  _INSTANCE_CONNECTION_NAME: '${PROJECT_ID}:${_INSTANCE_REGION}:${_INSTANCE_ID}'
  _SLEEP_SEC: '5'
代入変数名 説明
_SCHEMA_FILE psqldef でマイグレーションするスキーマファイル
_DATABASE_HOST DBのホスト
_DATABASE_PORT DBのポート
_DATABASE_NAME DB名
_DATABASE_USER DBのユーザー名
_DATABASE_PASSWORD_KEY DBのパスワードを Secret Manager に保存した際のシークレット名
_INSTANCE_REGION Cloud SQLのインスタンスのリージョン
_INSTANCE_ID Cloud SQLのインスタンスID
_INSTANCE_CONNECTION_NAME Cloud SQLの接続名(環境変数や代入変数で値を作成する)
_SLEEP_SEC Cloud SQL Proxyの起動を待つスリープ(秒数を指定する)

数値の指定の場合、クォートが必要です。そのため、DBのポートやスリープの秒数にシングルクォートを付けています。

availableSecretsの説明

availableSecrets:
  secretManager:
    - versionName: >-
        projects/$PROJECT_ID/secrets/${_DATABASE_PASSWORD_KEY}/versions/latest
      env: DATABASE_PASS
  • availableSecretsは、Cloud BuildでSecret Managerのシークレットを使用する時のフィールドです。

DBのパスワードを、Secret Managerに保存しており、そこから最新の設定内容を取得するようにしています。

Cloud Build 実行に必要なロール

  • 今回のCloud Build実行には以下の2つのロールが必要です。
    • Cloud SQL クライアント
    • Secret Manager のシークレット アクセサー

実行ログ

構成ファイルの代入変数の値を適宜変更し、実行すると以下のように成功します。

実行ログ

振り返り

Cloud Buildでsqldefを用いてマイグレーションする方法をネットで探しても出てこず苦労しました。

Cloud SQL ProxyとpsqldefをwaitForを使用して分けて実行させてみたりと試行錯誤の連続でした。

Cloud BuildでCloud SQL Proxyを用いてCloud SQLへの接続がどうしてもうまく行かず、Google Cloudのサポートも利用しました。

Cloud SQL Proxyの起動には、少し時間を要するためスリープを入れることで接続できない問題は解決しました。

さいごに

この記事が、Cloud Buildからpsqldefもしくはmysqldefを使用してマイグレーションを検討している方の助けになれば幸いです。

次回の トレタ Advent Calendar 2022 の22日目は、Cloud Buildの結果をSlackに通知する方法を紹介したいと思います。

トレタではエンジニアの募集を全方位で行なっております。

コロナ禍を乗り越えた飲食店の新しい姿を探求する仲間をお待ちしております。

https://corp.toreta.in/recruit/engineer/

Discussion