Cloud Run Jobs から Alloy DB にマイグレーション
はじめに
昨日、Cloud Run Jobs から Cloud SQL へのDBマイグレーション(up/down)を実行してみる、ということをやってみました。
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:1]
1. Artifact Registry の作成まず、マイグレーションジョブ用のDockerイメージを格納するためのレジストリを作成します。
resource "google_artifact_registry_repository" "migration_alloydb" {
location = "asia-northeast1"
repository_id = "migration-alloydb"
description = "migration docker repository"
format = "DOCKER"
}
[1:2]
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.ini
の sqlalchemy.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マイグレーション用のコンテナも作成できます。
[1:3]
4. イメージのビルド&プッシュ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
ロールを付与する必要があります。)
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]できます。
[1:4]
(Appendix)GitHub Actionsによる自動化以上で構築は完了ですが、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マイグレーションを実行するための環境構築方法と、自動化について記載しました。
マイグレーションの実装方法には様々なアプローチがありますが、ここで紹介したような方法を取る場合に実装の一助になれば幸いです。
世界のラストワンマイルを最適化する、OPTIMINDのテックブログです。「どの車両が、どの訪問先を、どの順に、どういうルートで回ると最適か」というラストワンマイルの配車最適化サービス、Loogiaを展開しています。recruit.optimind.tech/
Discussion