このチュートリアルでは、Heroku で実行されている Node.js ウェブアプリを Google Cloud の Cloud Run に移行する方法について説明します。このチュートリアルは、Heroku から Google Cloud のマネージド サービスにアプリを移行する設計者とプロダクト オーナーを対象としています。
Cloud Run はマネージド コンピューティング プラットフォームで、HTTP リクエストを介して呼び出すことができるステートレス コンテナを実行できます。Cloud Run はオープンソースの Knative で構築されています。Knative は、プラットフォーム間でのポータビリティを可能にし、コンテナのワークフローや継続的デリバリーの標準をサポートしています。Cloud Run プラットフォームは Google Cloud プロダクト スイートとうまく統合されており、移植性、スケーラビリティ、復元性に優れたアプリの設計と開発が容易になります。
このチュートリアルでは、Node.js で作成され、Heroku のバッキング サービスとして Heroku Postgres を使用しているアプリを、Google Cloud に移行する方法について説明します。このウェブアプリは Cloud Run でコンテナ化されてホストされ、永続的なレイヤとして Cloud SQL for PostgreSQL を使用します。
このチュートリアルでは、タスクの表示や作成ができる Tasks というシンプルなアプリを使用します。これらのタスクは、Heroku 上で現在デプロイされているアプリ内の Heroku Postgres に格納されます。
このチュートリアルは、Heroku の基本的な機能に精通しており、Heroku アカウント(あるいはアカウントへのアクセス権)があることを前提としています。また、Cloud Run、Cloud SQL、Docker、Node.js に精通していることを前提としています。
目標
- Cloud Run にアプリをデプロイするための Docker イメージをビルドします。
- Google Cloud への移行後にバックエンドとして機能する Cloud SQL for PostgreSQL インスタンスを作成します。
- Cloud Run が Cloud SQL に接続する方法を理解し、Heroku から Cloud Run に移行するために必要なコードの変更(ある場合)を確認するため、Node.js コードを確認します。
- Heroku Postgres から Cloud SQL for PostgreSQL にデータを移行します。
- Cloud Run にアプリをデプロイします。
- デプロイされたアプリをテストします。
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
また、Heroku で使用するリソースに対しても課金される場合があります。
始める前に
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。
-
Enable the Cloud SQL, Cloud Build, Cloud Run, Container Registry, Service Networking, Serverless VPC Access APIs.
-
Make sure that you have the following role or roles on the project: Cloud Run > Cloud Run Admin, Cloud Storage > Storage Admin, Cloud SQL > Cloud SQL Admin, Compute Engine > Compute Network Admin, Resource Manager > Project IAM Admin, Cloud Build > Cloud Build Editor, Serverless VPC Access > Serverless VPC Access Admin, Logging > Logs Viewer, Service Accounts > Service Account Admin, Service Accounts > Service Account User, and Service Usage > Service Usage Consumer
Check for the roles
-
In the Google Cloud console, go to the IAM page.
Go to IAM - Select the project.
-
In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.
- For all rows that specify or include you, check the Role colunn to see whether the list of roles includes the required roles.
Grant the roles
-
In the Google Cloud console, go to the IAM page.
[IAM] に移動 - プロジェクトを選択します。
- [ アクセスを許可] をクリックします。
-
[新しいプリンシパル] フィールドに、ユーザー ID を入力します。 これは通常、Google アカウントのメールアドレスです。
- [ロールを選択] リストでロールを選択します。
- 追加のロールを付与するには、 [別のロールを追加] をクリックして各ロールを追加します。
- [保存] をクリックします。
-
-
Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。
-
Enable the Cloud SQL, Cloud Build, Cloud Run, Container Registry, Service Networking, Serverless VPC Access APIs.
-
Make sure that you have the following role or roles on the project: Cloud Run > Cloud Run Admin, Cloud Storage > Storage Admin, Cloud SQL > Cloud SQL Admin, Compute Engine > Compute Network Admin, Resource Manager > Project IAM Admin, Cloud Build > Cloud Build Editor, Serverless VPC Access > Serverless VPC Access Admin, Logging > Logs Viewer, Service Accounts > Service Account Admin, Service Accounts > Service Account User, and Service Usage > Service Usage Consumer
Check for the roles
-
In the Google Cloud console, go to the IAM page.
Go to IAM - Select the project.
-
In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.
- For all rows that specify or include you, check the Role colunn to see whether the list of roles includes the required roles.
Grant the roles
-
In the Google Cloud console, go to the IAM page.
[IAM] に移動 - プロジェクトを選択します。
- [ アクセスを許可] をクリックします。
-
[新しいプリンシパル] フィールドに、ユーザー ID を入力します。 これは通常、Google アカウントのメールアドレスです。
- [ロールを選択] リストでロールを選択します。
- 追加のロールを付与するには、 [別のロールを追加] をクリックして各ロールを追加します。
- [保存] をクリックします。
-
環境設定
Cloud Shell を開きます。
Cloud Shell で、このチュートリアルで使用する Google Cloud CLI の環境変数とデフォルト値を設定します。
gcloud config set project PROJECT_ID gcloud config set run/region us-central1
PROJECT_ID
は、実際のプロジェクト ID に置き換えます。
アーキテクチャ
次の図は、現状の Heroku 上のウェブアプリのアーキテクチャと、これからビルドする Google Cloud 上のアーキテクチャ レイアウトを示しています。
現在、Heroku にデプロイされている Tasks アプリは、1 つ以上のウェブ dyno で構成されています。バックグラウンド ジョブや時間指定タスクに適したワーカー dyno とは異なり、ウェブ dyno は HTTP トラフィックを受信して応答できます。このアプリケーションは、Node.js の Mustache テンプレート ライブラリを使用して、Postgres データベースに格納されたタスクを表示するインデックス ページを提供します。
HTTPS URL でアプリにアクセスできます。その URL の /tasks
ルートを使用すると、新しいタスクを作成できます。
Google Cloud では、Cloud Run は Tasks アプリをデプロイするサーバーレス プラットフォームとして使用されます。Cloud Run は、ステートレスでリクエスト主導のコンテナを実行するように設計されています。自動スケーリングを行い、かつトラフィックを提供していないときにはゼロまでスケールダウンするコンテナ化されたアプリをサポートするマネージド サービスを必要とする場合に適しています。
Heroku で使用されるコンポーネントを Google Cloud にマッピングする
次の表は、Heroku プラットフォーム上のコンポーネントと Google Cloud 上のコンポーネントの比較を示したものです。この表は、このチュートリアルで説明するアーキテクチャを Heroku から Google Cloud に変換する際に役立ちます。
コンポーネント | Heroku プラットフォーム | Google Cloud |
---|---|---|
コンテナ | dyno: Heroku はコンテナモデルを使用して、Heroku アプリをビルドおよびスケールします。これらの Linux コンテナは dyno と呼ばれるもので、指定した数にスケーリングして、Heroku アプリのリソース需要に対応できます。また、さまざまな dyno タイプから、アプリのメモリ要件、CPU 要件に応じて、dyno を選ぶことができます。 | Cloud Run コンテナ: Google Cloud はフルマネージド環境や Google Kubernetes Engine(GKE)クラスタで実行できるステートレス コンテナ内で、コンテナ化されたワークロードの実行をサポートします。 |
ウェブアプリ | Heroku アプリ: dyno は、Heroku アプリの構成要素です。通常、アプリは 1 つ以上の dyno タイプで構成されます。また、アプリは通常、ウェブ dyno とワーカー dyno の組み合わせです。 | Cloud Run サービス: ウェブアプリは Cloud Run サービスとしてモデル化されます。各サービスは独自の HTTPS エンドポイントを取得します。サービスのエンドポイントへのトラフィックに応じて、0 から N までの範囲で自動スケーリングします。 |
データベース | Heroku Postgres は、PostgreSQL に基づいた Heroku のサービスとしてのデータベース(DaaS)です。 | Cloud SQL は、Google Cloud 上のリレーショナル データベース用のマネージド データベース サービスです。 |
サンプルの Tasks ウェブアプリを Heroku にデプロイする
次のセクションでは、Heroku のコマンドライン インターフェース(CLI)を設定して、GitHub ソース リポジトリのクローンを作成し、Heroku にアプリをデプロイする方法を説明します。
Heroku のコマンドライン インターフェースを設定する
このチュートリアルでは、Cloud Shell で Heroku CLI を実行し、Heroku API キーを使用して認証する必要があります。Heroku CLI を Cloud Shell で実行する場合、パスワードやウェブベースによる認証は使用できません。
ローカル ターミナルでサンプルを実行する場合は、任意の Heroku CLI 認証方法を使用できます。ローカル ターミナルでチュートリアルを実行する場合は、Google Cloud CLI、git、Docker もインストールする必要があります。
Heroku のウェブ コンソールにログインし、アカウント設定ページから API キーの値をコピーします。
Cloud Shell で、Heroku CLI をインストールします。
Cloud Shell で Heroku CLI を認証します。パスワードの入力を求められたら、コンソールへのログインに使用するパスワードではなく、Heroku コンソールからコピーした API キーの値を入力します。
heroku login --interactive
ソース リポジトリのクローンを作成する
Cloud Shell で、サンプルの Tasks アプリの GitHub リポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/migrate-webapp-heroku-to-cloudrun-node.git
リポジトリのクローン作成で作成されたディレクトリに移動します。
cd migrate-webapp-heroku-to-cloudrun-node
このディレクトリ内には以下のファイルがあります。
index.js
という Node.js スクリプトと、ウェブアプリによって提供されるルートのコード。- ウェブアプリの依存関係を説明する
package.json
ファイルとpackage-lock.json
ファイル。アプリを実行するには、これらの依存関係をインストールする必要があります。 - アプリが起動時に実行するコマンドを指定する
Procfile
ファイル。Procfile
ファイルを作成して、アプリを Heroku にデプロイします。 - 「/」ルート上のウェブアプリによって提供される HTML コンテンツを含む
views
ディレクトリ。 .gitignore
ファイル
Heroku にアプリをデプロイする
Cloud Shell で、Heroku アプリを作成します。
heroku create
アプリ用に作成した名前をメモしておきます。この値は次のステップで必要になります。
Heroku アプリ名の環境変数を作成します。
export APP_NAME=APP_NAME
APP_NAME
は、heroku create
コマンドから返されたアプリ名に置き換えます。Heroku Postgres アドオンを追加して、PostgreSQL データベースをプロビジョニングします。
heroku addons:create heroku-postgresql:mini
アドオンが正常に追加されたことを確認します。
heroku addons
Postgres アドオンが正常に追加されると、次のようなメッセージが表示されます。
Add-on Plan Price State ----------------- ----- -------- ----- heroku-postgresql mini 5$/month created
Heroku にアプリをデプロイします。
git push heroku master
次のコマンドを実行して、DATABASE_URL の値を確認します。
heroku config
取得した DATABASE_URL の値をメモしておきます。この値は次のステップで必要になります。
Docker コンテナを実行します。
docker run -it --rm postgres psql "DATABASE_URL"
DATABASE_URL
を、前のステップでメモした Heroku Postgres URI に置き換えます。Docker コンテナで、次のコマンドを使用して
TASKS
テーブルを作成します。CREATE TABLE TASKS (DESCRIPTION TEXT NOT NULL);
コンテナを終了します。
exit
Cloud Shell で次のコマンドを実行して、Heroku アプリのウェブ URL を取得します。
heroku info
ブラウザ ウィンドウでこのウェブ URL を開きます。アプリは次のスクリーンショットのように表示されます(ただし、ご自身のバージョンではリストされるタスクはありません)。
ブラウザから、アプリでサンプルタスクを作成します。タスクがデータベースから取得され、UI に表示されることを確認します。
Cloud Run への移行のためのウェブアプリ コードの準備
このセクションでは、ウェブアプリを Cloud Run へデプロイするために必要な手順を説明します。
Docker コンテナをビルドして Container Registry に公開する
Cloud Run で実行できるようにアプリコンテナをビルドするには、Docker イメージが必要です。コンテナは手動、または Buildpack を使用してビルドできます。
コンテナを手動でビルドする
Cloud Shell で、このチュートリアルのリポジトリのクローンを作成することによって作られたディレクトリに Dockerfile を作成します。
cat <<"EOF" > Dockerfile # Use the official Node image. # https://hub.docker.com/_/node FROM node:10-alpine # Create and change to the app directory. WORKDIR /app # Copying this separately prevents re-running npm install on every code change. COPY package*.json ./ RUN npm install # Copy local code to the container image. COPY . /app # Configure and document the service HTTP port. ENV PORT 8080 EXPOSE $PORT # Run the web service on container startup. CMD ["npm", "start"] EOF
Cloud Build でコンテナをビルドし、イメージを Container Registry に公開します。
gcloud builds submit --tag gcr.io/PROJECT_ID/APP_NAME:1 \ --gcs-log-dir=gs://PROJECT_ID_cloudbuild
作成した Docker イメージの名前を保持する環境変数を作成します。
export IMAGE_NAME="gcr.io/PROJECT_ID/APP_NAME:1"
Buildpack を使用してコンテナをビルドする
Cloud Shell で、パック CLI をインストールします。
デフォルトで Heroku ビルダーを使用するようにパック CLI を設定します。
pack config default-builder heroku/buildpacks:22
Docker イメージ名を保持する環境変数を作成します。
export IMAGE_NAME=gcr.io/PROJECT_ID/APP_NAME:1
pack
コマンドを使用してイメージをビルドし、イメージを Container Registry に push または公開します。pack build --publish $IMAGE_NAME
Cloud SQL for PostgreSQL インスタンスを作成する
ウェブアプリのバックエンドとして機能する Cloud SQL for PostgreSQL インスタンスを作成します。このチュートリアルでは、PostgreSQL が Heroku にデプロイされるサンプルアプリとして最適です。Heroku は、Postgres データベースをバックエンドとして使用します。マネージド Postgres サービスから Cloud SQL for PostgreSQL への移行では、このアプリのためにスキーマを変更する必要はありません。
プライベート IP アドレスを使用して Cloud SQL 用にネットワークを準備します。
gcloud compute addresses create google-managed-services-default \ --global \ --purpose=VPC_PEERING \ --prefix-length=16 \ --description="peering range for CloudSQL Private Service Access" \ --network=default gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=google-managed-services-default \ --network=default \ --project=PROJECT_ID
次のステップで作成するデータベース インスタンスの名前を保持する、
CLOUDSQL_DB_NAME
という環境変数を作成します。export CLOUDSQL_DB_NAME=tasks-db
データベースを作成します。
gcloud sql instances create $CLOUDSQL_DB_NAME \ --cpu=1 \ --memory=4352Mib \ --database-version=POSTGRES_15 \ --region=us-central1 \ --network default \ --no-assign-ip
インスタンスの初期化には、数分かかることがあります。
Postgres ユーザーのパスワードを設定します。
gcloud sql users set-password postgres \ --instance=$CLOUDSQL_DB_NAME \ --password=POSTGRES_PASSWORD
POSTGRES_PASSWORD
は、Postgres データベースに使用するパスワードに置き換えます。
Heroku Postgres から Cloud SQL にデータをインポートする
Cloud SQL へのデータ移行のパターンは複数あります。一般に、移行するデータベースのレプリカとして Cloud SQL を構成し、移行後に Cloud SQL をプライマリ インスタンスにする方法が、ダウンタイムをほとんど、あるいはまったく発生させない最適な方法です。Heroku Postgres は外部レプリカ(フォロワー)をサポートしていないため、このチュートリアルでは、オープンソースのツールを使用してアプリのスキーマを移行します。
このチュートリアルの Tasks アプリでは、pg_dump ユーティリティを使用して、Heroku Postgres から Cloud Storage バケットにデータをエクスポートし、Cloud SQL にインポートします。宛先とソースのバージョンが同じか、宛先のバージョンがソースより新しい場合に、このユーティリティでデータを転送できます。
Cloud Shell で、サンプルアプリに接続されている Heroku Postgres データベースのデータベース認証情報を取得します。これらの認証情報は次のステップで必要になります。
heroku pg:credentials:url
このコマンドは、アプリケーションの接続情報文字列と接続 URL を返します。接続情報文字列の形式は次のとおりです。
"dbname=DATABASE_NAME host=FQDN port=5432 user=USER_NAME password=PASSWORD_STRING sslmode=require"
接続文字列に示されている値は、次のステップで必要になります。
接続情報文字列の FQDN(完全修飾ドメイン名)の値の例については、Heroku ドキュメントをご覧ください。
以降のステップで使用する Heroku 値を保持するために、各環境変数を設定します。
export HEROKU_PG_DBNAME=DATABASE_NAME export HEROKU_PG_HOST=FQDN export HEROKU_PG_USER=USER_NAME export HEROKU_PG_PASSWORD=PASSWORD_STRING
次のように置き換えます。
DATABASE_NAME
: 情報文字列に表示されるデータベース名。FQDN
: 情報文字列に表示される FQDN。USER_NAME
: 情報文字列に表示されるユーザー名。PASSWORD_STRING
: 情報文字列に表示されるパスワード文字列。
Heroku Postgres データベースの SQL 形式のバックアップを作成します。
docker run \ -it --rm \ -e PGPASSWORD=$HEROKU_PG_PASSWORD \ -v $(pwd):/tmp \ --entrypoint "pg_dump" \ postgres \ -Fp \ --no-acl \ --no-owner \ -h $HEROKU_PG_HOST \ -U $HEROKU_PG_USER \ $HEROKU_PG_DBNAME > herokudump.sql
Cloud Storage バケットの名前を保持する環境変数を作成します。
export PG_BACKUP_BUCKET=gs://PROJECT_ID-pg-backup-bucket
Cloud Storage バケットを作成します。
gcloud storage buckets create $PG_BACKUP_BUCKET \ --location=us-central1 \ --public-access-prevention \ --uniform-bucket-level-access
このバケットに SQL ファイルをアップロードします。
gcloud storage cp herokudump.sql $PG_BACKUP_BUCKET/herokudump.sql
Cloud Storage バケットから SQL ファイルをインポートするために必要なロールを Cloud SQL インスタンスに付与します。
gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='get("serviceAccountEmailAddress")') \ --role=roles/storage.objectAdmin gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='get("serviceAccountEmailAddress")') \ --role=roles/cloudsql.editor
SQL ファイルを Cloud SQL インスタンスにインポートします。
gcloud sql import sql $CLOUDSQL_DB_NAME $PG_BACKUP_BUCKET/herokudump.sql \ --database=postgres \ --user=postgres
「
do you want to continue (y/n)
」とプロンプトが表示されたら、「y」と入力します。
Cloud Run が Cloud SQL データベースにアクセスする方法
Heroku にデプロイされたウェブアプリが、Heroku Postgres のマネージド インスタンスに接続する必要があるのと同じように、データの読み取りと書き込みを行うためには、Cloud Run は Cloud SQL へのアクセスが必要です。
Cloud Run は、コンテナを Cloud Run にデプロイするときに自動的にアクティブ化され、構成される Cloud SQL プロキシを使用して Cloud SQL と通信します。データベースは、外部 IP アドレスを承認する必要はありません。これは、データベースが受信する通信はすべて、セキュア TCP を使用するプロキシからの通信であるためです。
コードは、Unix ソケットを介してプロキシを呼び出すことにより、データベース オペレーション(データベースからのデータの取得やデータベースへの書き込みなど)を呼び出す必要があります。
このウェブアプリは Node.js で記述されているため、データベース URL を解析し、config
オブジェクトを作成するには、pg-connection-string
ライブラリを使用します。このアプローチの利点は、Heroku と Cloud Run との間でバックエンド データベースにシームレスに接続できることです。
次のステップでは、ウェブアプリのデプロイ時に、環境変数としてデータベース URL を渡します。
サンプルアプリを Cloud Run にデプロイする
Cloud Shell でサーバーレス VPC アクセスを構成して、Cloud Run から Cloud SQL へのプライベート トラフィックを許可します。
gcloud compute networks subnets create serverless-connector-subnet \ --network=default \ --range=10.0.0.0/28 \ --region=us-central1 gcloud compute networks vpc-access connectors create serverless-connector \ --region=us-central1 \ --subnet=serverless-connector-subnet
Cloud Shell で、作成した Cloud SQL インスタンスの接続名を保持する環境変数を作成します。
export DB_CONN_NAME=$(gcloud sql instances describe $CLOUDSQL_DB_NAME --format='value(connectionName)')
UNIX ポート経由で Cloud SQL プロキシに接続するための接続文字列を保持するために、
DATABASE_URL
という環境変数を作成します。export DATABASE_URL="socket:/cloudsql/${DB_CONN_NAME}?db=postgres&user=postgres&password=POSTGRES_PASSWORD"
データベースに接続するための IAM ロールを持つ Cloud Run のサービス アカウントを作成します。
gcloud iam service-accounts create sa-run-db-client gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:sa-run-db-client@PROJECT_ID.iam.gserviceaccount.com \ --role=roles/cloudsql.client
ウェブアプリを Cloud Run にデプロイします。
gcloud run deploy tasksapp-PROJECT_ID \ --image=$IMAGE_NAME \ --service-account=sa-run-db-client@PROJECT_ID.iam.gserviceaccount.com \ --set-env-vars=DATABASE_URL=$DATABASE_URL \ --add-cloudsql-instances $DB_CONN_NAME \ --vpc-connector serverless-connector \ --allow-unauthenticated
上記のコマンドは、作成した Cloud SQL データベース インスタンスに Cloud Run コンテナをリンクします。このコマンドは、前のステップで作成した
DATABASE_URL
文字列を指すように Cloud Run の環境変数を設定します。
アプリケーションをテストする
Cloud Shell で、Cloud Run がトラフィックを提供する URL を取得します。
gcloud run services list
また、Google Cloud コンソールで Cloud Run サービスを確認することもできます。
Cloud Run サービスの URL に移動して、ウェブアプリが HTTP リクエストを受け入れていることを確認します。
HTTP リクエストがサービスを提供しているエンドポイントに送信された場合と、コンテナがまだ実行されていない場合、Cloud Run は新しいコンテナを作成、またはスピンアップします。つまり、新しいコンテナをスピンアップさせるリクエストは、提供されるまでに少し時間がかかる場合があります。時間がかかる場合は、アプリがサポートできる同時リクエスト数と、アプリが持つ固有のメモリ要件を考慮してください。
このアプリでは、デフォルトの同時実行設定を使用します。この設定では、Cloud Run サービスは 1 つのコンテナからの 80 件のリクエストを同時に処理できます。
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにする手順は次のとおりです。このチュートリアルで、Heroku で作成したリソースも削除するといいでしょう。
Google Cloud プロジェクトの削除
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
Heroku アプリの削除
Heroku と関連する PostgreSQL アドオンにデプロイしたサンプルアプリを削除するには、次のコマンドを実行します。
heroku apps:destroy -a APP_NAME
次のステップ
- Cloud SQL にデータをインポートする方法を学ぶ。
- Cloud Run のドキュメントを確認する。