🍣

Cloud Run Jobs から Alloy DB にマイグレーション

2024/07/28に公開

はじめに

昨日、Cloud Run Jobs から Cloud SQL へのDBマイグレーション(up/down)を実行してみる、ということをやってみました。

https://zenn.dev/optimind/articles/b00592163df170

Alloy DB でも同様にジョブを作成できるかと思い、確認のため実際に試しました。結論として、コネクション設定を少し変えることで同様のことが可能でした。本記事ではその際の情報をまとめようと思います。なお、CloudSQLで実施した前述記事と重複する部分が多いため、セクションが同一内容である場合にはタイトルに「[1]」を付けています。

改めて、今回はAlloy DBに対して、Cloud Run Jobs上でマイグレーションを実行する実装を行いました。本記事では、そのための環境構築方法をTerraformコードと共に説明します。サンプルコードはこちら(github)にあります。

0. 前提

実装に先立ち、Google Cloud上に構築されている環境の前提条件を記載します。この前提条件に基づいて、ジョブの実装を進めていきます。

AlloyDBクラスタ及びインスタンスがService Producer VPCネットワークに存在し、ユーザ定義VPCネットワークとVPCピアリングが確立されており、プライベートIPアドレスでアクセス可能な状態であるとします。Terraformを使用して構成した場合、次のようなリソースが作成されているような状態です。

data "google_project" "current" {}

resource "google_compute_network" "db_network" {
  name                    = "db-network"
  auto_create_subnetworks = false
}

resource "google_compute_global_address" "db_private_ip" {
  name          = "db-private-ip"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  address       = "10.0.0.0"
  prefix_length = 16
  network       = google_compute_network.db_network.id
}

resource "google_service_networking_connection" "db_conn" {
  network                 = google_compute_network.db_network.id
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.db_private_ip.name]
}

resource "google_alloydb_cluster" "db_cluster" {
  cluster_id = "db-cluster"
  location   = "asia-northeast1"

  network_config {
    network = google_compute_network.db_network.id
  }
}

resource "google_alloydb_instance" "db_instance" {
  cluster       = google_alloydb_cluster.db_cluster.id
  instance_id   = "db-instance"
  instance_type = "PRIMARY"

  machine_config {
    cpu_count = 2
  }
}

resource "google_alloydb_user" "db_admin" {
  cluster        = google_alloydb_cluster.db_cluster.id
  user_id        = "db-admin"
  user_type      = "ALLOYDB_BUILT_IN"
  # 本来はシークレットマネージャなどを使用するべき
  password       = var.password
  database_roles = ["alloydbsuperuser"]
}

1. Artifact Registry の作成[1:1]

まず、マイグレーションジョブ用のDockerイメージを格納するためのレジストリを作成します。

resource "google_artifact_registry_repository" "migration_alloydb" {
  location      = "asia-northeast1"
  repository_id = "migration-alloydb"
  description   = "migration docker repository"
  format        = "DOCKER"
}

2. マイグレーション関連ファイル作成[1:2]

Cloud Run Jobs上で実行するマイグレーション関連ファイルを作成します。

ここではサンプルとしてalembicを使用していますが、Knexなど他のマイグレーションツールでも同様にマイグレーションを実行できると思います。alembicを使用しない場合、このセクションをスキップしてください。また、以降のセクションでもalembicに関するコードや説明については、適宜読み換えご利用ください。

まず、依存パッケージを準備し、マイグレーションの初期化を実行します。Ryeを使用する場合は、以下のコマンドを実行します(必要に応じて pip install などに読み換えてください)。

rye add sqlalchemy alembic psycopg2-binary
alembic init alembic

次に、マイグレーション関連ファイルのDB接続情報を設定します。この際、必要に応じて環境変数[2]を使用すると良いでしょう。alembicを使用する場合、前述のinitコマンドで自動生成される alembic.inisqlalchemy.url を編集します。リビジョンファイルも作成し、以下のコマンドを実行して、自動生成されたファイルの upgrade/downgrade 関数を実装します。

alembic revision -m "message"

3. Dockerfile作成

マイグレーションを実行するコンテナのDockerfileを作成します。このDockerfileには、マイグレーション関連ファイル一式とAlloyDB Auth Proxyをインストールします[^3]。そして、コンテナ起動時にプロキシを介してマイグレーションを実行するように設定します。

以下の projects/[PROJECT_ID]/locations/asia-northeast1/clusters/[CLUSTER_ID]/instances/[INSTANCE_ID] は、「接続URI」という項目をAlloyDBのコンソールから取得できます。

FROM python:3.11-slim

WORKDIR /app

RUN apt-get update && apt-get install -y wget gnupg && rm -rf /var/lib/apt/lists/*

RUN wget https://storage.googleapis.com/alloydb-auth-proxy/v1.10.2/alloydb-auth-proxy.linux.amd64 -O /usr/local/bin/alloydb_auth_proxy && \
    chmod +x /usr/local/bin/alloydb_auth_proxy

COPY alembic.ini /app/
COPY alembic /app/alembic
COPY pyproject.toml .
COPY requirements.lock .

RUN python -m venv /venv
RUN /venv/bin/pip install --no-cache-dir -r requirements.lock

CMD ./alloydb_auth_proxy projects/[PROJECT_ID]/locations/asia-northeast1/clusters/[CLUSTER_ID]/instances/[INSTANCE_ID] & \
    sleep 10 && \
    /venv/bin/alembic upgrade head

このCMDを編集することで、downマイグレーション用のコンテナも作成できます。

4. イメージのビルド&プッシュ[1:3]

3で作成したDockerfileをビルドし、1で作成したArtifact Registryにプッシュします。

まず、Google Cloudのレジストリに認証を設定します。

gcloud auth configure-docker asia-northeast1-docker.pkg.dev

次に、イメージのビルドを行います。ビルド環境がMacである場合、CloudRunの実行環境とCPUアーキテクチャが異なることに注意し(参考)、以下のようにビルドします。

(docker buildx create --name mybuilder --use)
docker buildx build --platform linux/amd64 -t asia-northeast1-docker.pkg.dev/[PROJECT_ID]/[REPOSITORY_NAME]/[IMAGE_NAME]:latest --push .

5. ジョブのデプロイ

4でプッシュされたイメージを使用してジョブをデプロイします。このジョブは、AlloyDBに対してVPCアクセスできるように設定します。また、このジョブにアタッチするサービスアカウントには、Artifact Registryからの読み込み権限も必要です。以下に、VPCアクセスコネクタを含むTerraformサンプルコードを記載します。(CloudSQLに対して実施した際と異なる点としては、使用するサービスアカウントに serviceusage.serviceUsageConsumer ロールを付与する必要があります。)

https://cloud.google.com/alloydb/docs/manage-iam-authn#role

resource "google_vpc_access_connector" "connector" {
  name          = "vpc-access-con"
  ip_cidr_range = "10.10.0.0/28"
  network       = google_compute_network.db_network.id
}

resource "google_service_account" "migration_alloydb_job" {
  account_id  = "migration-alloydb-job"
  description = "for migration job"
}

resource "google_project_iam_member" "migration_alloydb_job" {
  for_each = toset([
    "roles/artifactregistry.reader",
    "roles/alloydb.admin",
    "roles/serviceusage.serviceUsageConsumer",
  ])
  project = data.google_project.current.project_id
  role    = each.value
  member  = "serviceAccount:${google_service_account.migration_alloydb_job.email}"
}

resource "google_cloud_run_v2_job" "migration" {
  name     = "migration"
  location = "asia-northeast1"
  template {
    template {
      service_account = google_service_account.migration_alloydb_job.email
      containers {
        image = "asia-northeast1-docker.pkg.dev/${google_artifact_registry_repository.migration_alloydb.project}/${google_artifact_registry_repository.migration_alloydb.repository_id}/migration:latest"
      }
      vpc_access {
        connector = google_vpc_access_connector.connector.id
      }
    }
  }
}

最小権限を付与したい場合は、google_artifact_registry_repository_iam_memberなどのリソースを使用するのが良いでしょう。

これで、一通り構築は完了です。ジョブはコンソールから実行するか、もしくはコマンドにより実行できます。

gcloud run jobs execute

マイグレーションが正常に実行できているかどうかは、AlloyDB Studioを使うことで確認[3]できます。

(Appendix)GitHub Actionsによる自動化[1:4]

以上で構築は完了ですが、GitHub Actionsなどで自動化しておくと、CI/CDパイプラインに組み込めむことができ、より便利です。例えば、以下のようにビルドからジョブの実行までを自動化することができます。

name: migration

on:
  push:
    branches:
      - "main"

jobs:
  migration:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    env:
      WORKLOAD_IDENTITY_PROVIDER: 'projects/[PROJECT_ID]/locations/global/workloadIdentityPools/[POOL_ID]/providers/[PROVIDER_ID]'
      GITHUB_SERVICE_ACCOUNT: '[SERVICE_ACCOUNT_EMAIL]'
      IMAGE_PATH: 'asia-northeast1-docker.pkg.dev/[PROJECT_ID]/[REPOSITORY_NAME]/[IMAGE_NAME]:latest'

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: ${{ env.WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ env.GITHUB_SERVICE_ACCOUNT }}

      - name: Set up gcloud CLI
        uses: google-github-actions/setup-gcloud@v2
        with:
          version: 'latest'

      - name: Init docker for gcloud
        run: gcloud auth configure-docker asia-northeast1-docker.pkg.dev

      - name: Build docker image
        run: docker build -t ${{ env.IMAGE_PATH }} .

      - name: Push docker image for container registory
        run: docker push ${{ env.IMAGE_PATH }}

      - name: Execute Cloud Run Job
        run: |
          gcloud run jobs deploy migration \
            --image ${{ env.IMAGE_PATH }} \
            --region asia-northeast1
          gcloud run jobs execute migration \
            --region asia-northeast1

上記はWorkload Identity連携を使用しています。

これに加えて、3で記載したようにdownマイグレーションのジョブも簡単に作成できるので、こちらもワークフローに自動化しておくと良いでしょう。

まとめ

他の記事でCloudSQLに対して実施したのと同様に、Cloud Run Jobs を使用して、AlloyDBに対してDBのup/downマイグレーションを実行するための環境構築方法と、自動化について記載しました。

マイグレーションの実装方法には様々なアプローチがありますが、ここで紹介したような方法を取る場合に実装の一助になれば幸いです。

脚注
  1. CloudSQLに対して実施した際と同じ。 ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. シークレットマネージャから読み込んでCloudRunJobsジョブに注入できます(参考)。 ↩︎

  3. 踏み台サーバを立てるなどの準備なしに、コンソールから簡単にクエリを実行できます。CloudSQL StudioのGAは2024年7月ですが、意外にもこちらのGAは2024年4月です(参考)。 ↩︎

OPTIMINDテックブログ

Discussion