本教學課程說明如何將在 Heroku 上執行的 Node.js 網路應用程式遷移至 Google Cloud的 Cloud Run。本教學課程適用於想要將應用程式從 Heroku 遷移至 Google Cloud受管理服務的架構師和產品負責人。
Cloud Run 是一種代管運算平台,能夠讓您執行可透過 HTTP 要求叫用的無狀態容器。此平台建構於開放原始碼的 Knative,可讓工作負載在不同平台之間遷移,並支援容器工作流程和持續推送軟體更新標準。Cloud Run 平台與 Google Cloud 產品套件整合良好,可讓您更輕鬆地設計及開發可攜式、可擴充且具備韌性的應用程式。
在本教學課程中,您將瞭解如何將應用程式遷移至 Google Cloud 。該應用程式以 Node.js 編寫,並使用 Heroku 上的Heroku Postgres 做為後端服務。網頁應用程式會以容器形式託管在 Cloud Run 中,並使用 PostgreSQL 適用的 Cloud SQL 做為持續性層。
在本教學課程中,您將使用名為「Tasks」的簡單應用程式,查看及建立工作。這些工作會儲存在 Heroku Postgres 中,也就是目前在 Heroku 上部署的應用程式。
本教學課程假設您熟悉 Heroku 的基本功能,並且擁有 (或可存取) Heroku 帳戶。此外,本文也假設您熟悉 Cloud Run、Cloud SQL、Docker 和 Node.js。
目標
- 建構 Docker 映像檔,將應用程式部署至 Cloud Run。
- 建立 PostgreSQL 適用的 Cloud SQL 執行個體,做為遷移至 Google Cloud後的後端。
- 查看 Node.js 程式碼,瞭解 Cloud Run 如何連線至 Cloud SQL,以及從 Heroku 遷移至 Cloud Run 時需要進行的程式碼變更 (如有)。
- 將資料從 Heroku Postgres 遷移至 PostgreSQL 適用的 Cloud SQL。
- 將應用程式部署至 Cloud Run。
- 測試已部署的應用程式。
費用
在本文件中,您會使用 Google Cloud的下列計費元件:
如要根據預測用量估算費用,請使用 Pricing Calculator。
您可能還需要支付在 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.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
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 column 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」頁面 - 選取專案。
- 按一下「授予存取權」 。
-
在「New principals」(新增主體) 欄位中,輸入您的使用者 ID。 這通常是 Google 帳戶的電子郵件地址。
- 在「Select a role」(選取角色) 清單中,選取角色。
- 如要授予其他角色,請按一下 「新增其他角色」,然後新增每個其他角色。
- 按一下 [Save]。
-
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
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 column 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」頁面 - 選取專案。
- 按一下「授予存取權」 。
-
在「New principals」(新增主體) 欄位中,輸入您的使用者 ID。 這通常是 Google 帳戶的電子郵件地址。
- 在「Select a role」(選取角色) 清單中,選取角色。
- 如要授予其他角色,請按一下 「新增其他角色」,然後新增每個其他角色。
- 按一下 [Save]。
-
正在設定環境
開啟 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 應用程式包含一或多個網頁 dyno。Web dyno 可以接收及回應 HTTP 流量,這與 worker dyno 不同,後者較適合用於背景工作和定時工作。應用程式會使用 Node.js 的 Mustache 範本程式庫,提供顯示儲存在 Postgres 資料庫中工作的索引頁面。
您可透過 HTTPS 網址存取應用程式。該網址的 /tasks
路線可讓您建立新工作。
在 Google Cloud,Cloud Run 會做為無伺服器平台,用來部署 Tasks 應用程式。Cloud Run 的設計宗旨是執行無狀態、要求驅動的容器。如果您需要受管理服務支援自動調度資源的容器化應用程式,並在應用程式未處理流量時將資源調度降至零,就很適合使用這項服務。
將 Heroku 中使用的元件對應至 Google Cloud
下表列出 Heroku 平台中的元件與 Google Cloud的對應關係。 這項對應可協助您將本教學課程中說明的架構從 Heroku 轉換為 Google Cloud。
元件 | Heroku 平台 | Google Cloud |
---|---|---|
容器 | Dynos: Heroku 會使用容器模型建構及擴充 Heroku 應用程式。這些 Linux 容器稱為「dyno」,可擴充至您指定的數量,以支援 Heroku 應用程式的資源需求。您可以根據應用程式的記憶體和 CPU 需求,從一系列 dyno 類型中進行選擇。 | Cloud Run 容器: Google Cloud 支援在無狀態容器中執行容器化工作負載,這些容器可在全代管環境或 Google Kubernetes Engine (GKE) 叢集中執行。 |
網頁應用程式 | Heroku 應用程式:Dynos 是 Heroku 應用程式的建構區塊。應用程式通常由一或多個 Dyno 類型組成,通常是網頁和工作站 Dyno 的組合。 | Cloud Run 服務:網頁應用程式可以模擬為 Cloud Run 服務。每項服務都有專屬的 HTTPS 端點,並可根據服務端點的流量,自動將資源從 0 擴充或縮減至 N。 |
資料庫 | Heroku Postgres 是 Heroku 的資料庫即服務 (DaaS),以 PostgreSQL 為基礎。 | Cloud SQL 是 Google Cloud上的關聯式資料庫代管資料庫服務。 |
將範例 Tasks 網頁應用程式部署至 Heroku
接下來的章節說明如何設定 Heroku 的指令列介面 (CLI)、複製 GitHub 來源存放區,以及將應用程式部署至 Heroku。
設定 Heroku 的指令列介面
本教學課程會在 Cloud Shell 中執行 Heroku CLI,且必須使用 Heroku API 金鑰進行驗證。在 Cloud Shell 中執行時,Heroku CLI 無法使用密碼或網頁式驗證進行驗證。
或者,如果您在本機終端機上執行範例,可以使用任何 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。views
目錄,其中包含網頁應用程式在「/」路徑上提供的 HTML 內容。.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 網址。在 Docker 容器中,使用下列指令建立
TASKS
資料表:CREATE TABLE TASKS (DESCRIPTION TEXT NOT NULL);
結束容器:
exit
在 Cloud Shell 中執行下列指令,取得 Heroku 應用程式的網頁網址:
heroku info
在瀏覽器視窗中開啟網頁網址。應用程式看起來會像下方螢幕截圖 (但您的版本不會列出工作):
透過瀏覽器在應用程式中建立範例工作。確認工作已從資料庫擷取,並顯示在 UI 中。
準備網頁應用程式程式碼,以便遷移至 Cloud Run
本節詳細說明您必須完成的步驟,以便準備將網頁應用程式部署至 Cloud Run。
建構 Docker 容器並發布至 Container Registry
您需要 Docker 映像檔來建構應用程式容器,才能在 Cloud Run 中執行。您可以手動建構容器,也可以使用建構套件。
手動建構容器
在 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"
使用 Buildpacks 建構容器
在 Cloud Shell 中安裝 pack CLI。
將 pack CLI 設為預設使用 Heroku 建構工具:
pack config default-builder heroku/buildpacks:22
建立環境變數來保留 Docker 映像檔名稱:
export IMAGE_NAME=gcr.io/PROJECT_ID/APP_NAME:1
使用
pack
指令建構映像檔,並將映像檔推送或發布至 Container Registry:pack build --publish $IMAGE_NAME
建立 PostgreSQL 適用的 Cloud SQL 執行個體
您將建立 PostgreSQL 適用的 Cloud SQL 執行個體,做為網頁應用程式的後端。在本教學課程中,PostgreSQL 最適合做為部署在 Heroku 上的範例應用程式,因為該應用程式使用 Postgres 資料庫做為後端。就這個應用程式而言,從受管理 Postgres 服務遷移至 PostgreSQL 適用的 Cloud SQL 時,不需要變更結構定義。
為使用私人 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 不支援外部副本 (追蹤者),因此在本教學課程中,您會使用開放原始碼工具遷移應用程式的結構定義。
在本教學課程中,您將使用 pg_dump 公用程式,將 Tasks 應用程式的資料從 Heroku Postgres 匯出至 Cloud Storage bucket,然後匯入 Cloud SQL。這個公用程式可跨同質版本轉移資料,或在目的地資料庫版本比來源資料庫更新時轉移資料。
在 Cloud Shell 中,取得附加至範例應用程式的 Heroku Postgres 資料庫資料庫憑證。您會在下一個步驟中用到這些憑證。
heroku pg:credentials: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
:資訊字串中顯示的密碼字串。
以 SQL 格式備份 Heroku Postgres 資料庫:
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 bucket:
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 SQL 執行個體授予匯入 SQL 檔案的必要角色,從 Cloud Storage bucket 匯入檔案:
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 的 Web 應用程式需要連線至 Heroku Postgres 的代管執行個體,Cloud Run 也需要存取 Cloud SQL,才能讀取及寫入資料。
Cloud Run 會使用 Cloud SQL Proxy 與 Cloud SQL 通訊。將容器部署至 Cloud Run 時,系統會自動啟用及設定 Cloud SQL Proxy。資料庫不需要核准外部 IP 位址,因為收到的所有通訊都是透過安全 TCP 從 Proxy 傳送。
您的程式碼需要透過 UNIX Socket 呼叫 Proxy,藉此叫用資料庫作業 (例如從資料庫擷取資料或寫入資料)。
由於這個網頁應用程式是以 Node.js 編寫,因此您可以使用 pg-connection-string
程式庫剖析資料庫 URL,並建立 config
物件。這種做法的優點是,在 Heroku 和 Cloud Run 之間,連線至後端資料庫時不會發生任何問題。
在下一個步驟中,您會在部署網頁應用程式時,將資料庫網址做為環境變數傳遞。
將範例應用程式部署至 Cloud Run
在 Cloud Shell 中設定無伺服器虛擬私有雲存取權,允許從 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)')
建立名為
DATABASE_URL
的環境變數,用來保存透過 UNIX 連接埠連線至 Cloud SQL Proxy 的連線字串。export DATABASE_URL="socket:/cloudsql/${DB_CONN_NAME}?db=postgres&user=postgres&password=POSTGRES_PASSWORD"
為 Cloud Run 建立服務帳戶,並指派 IAM 角色,以便連線至資料庫:
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 Run 容器連結至您建立的 Cloud SQL 資料庫執行個體。這項指令會為 Cloud Run 設定環境變數,指向您在上一個步驟中建立的
DATABASE_URL
字串。
測試應用程式
在 Cloud Shell 中,取得 Cloud Run 服務流量的網址:
gcloud run services list
您也可以在Google Cloud 控制台中查看 Cloud Run 服務。
前往 Cloud Run 服務網址,確認 Web 應用程式接受 HTTP 要求。
當 HTTP 要求傳送至服務端點,且容器尚未執行時,Cloud Run 會建立或啟動新容器。也就是說,導致新容器啟動的要求可能需要較長時間才能處理。請考量應用程式可支援的並行要求數量,以及可能有的任何特定記憶體需求。
這個應用程式使用預設並行設定,允許 Cloud Run 服務從單一容器同時處理 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 說明文件。