1. 總覽
在本程式碼研究室中,您將建立新的 Cloud Run 服務 (即 collage 服務),並定期透過 Cloud Scheduler 觸發該服務。這項服務會擷取最新上傳的圖片,並建立這些圖片的拼貼:在 Cloud Firestore 中找出最近的圖片清單,然後從 Cloud Storage 下載實際的圖片檔案。

課程內容
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. 設定和需求
自修實驗室環境設定
- 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶。



- 專案名稱是這個專案參與者的顯示名稱。這是 Google API 未使用的字元字串,您隨時可以更新。
- 專案 ID 在所有 Google Cloud 專案中不得重複,且設定後即無法變更。Cloud 控制台會自動產生專屬字串,通常您不需要在意該字串為何。在大多數程式碼研究室中,您需要參照專案 ID (通常會標示為
PROJECT_ID),因此如果您不喜歡該字串,可以產生另一個隨機字串,或是嘗試使用自己的字串,看看是否可用。專案建立後,系統就會「凍結」該值。 - 還有第三個值,也就是部分 API 使用的「專案編號」。如要進一步瞭解這三種值,請參閱說明文件。
- 接著,您需要在 Cloud 控制台中啟用帳單,才能使用 Cloud 資源/API。完成本程式碼研究室的費用應該不高,甚至完全免費。如要停用資源,避免在本教學課程結束後繼續產生帳單費用,請按照程式碼研究室結尾的「清除」操作說明操作。Google Cloud 新使用者可參加價值$300 美元的免費試用計畫。
啟動 Cloud Shell
雖然可以透過筆電遠端操作 Google Cloud,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是可在雲端執行的指令列環境。
在 GCP 主控台,按一下右上角工具列的 Cloud Shell 圖示:

佈建並連線至環境的作業需要一些時間才能完成。完成後,您應該會看到如下的內容:

這部虛擬機器搭載各種您需要的開發工具,並提供永久的 5GB 主目錄,而且可在 Google Cloud 運作,大幅提升網路效能並強化驗證功能。本實驗室的所有工作都可在瀏覽器上完成。
3. 啟用 API
您需要 Cloud Scheduler,才能定期觸發 Cloud Run 服務。確認已啟用這項功能:
gcloud services enable cloudscheduler.googleapis.com
您應該會看到作業順利完成:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
4. 複製程式碼
複製程式碼 (如果您在上一個程式碼研究室中尚未複製):
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
接著,您可以前往包含服務的目錄:
cd serverless-photosharing-workshop/services/collage/nodejs
服務的檔案版面配置如下:
services
|
├── collage
|
├── nodejs
|
├── Dockerfile
├── index.js
├── package.json
資料夾內有 3 個檔案:
index.js包含 Node.js 程式碼package.json定義程式庫依附元件Dockerfile定義容器映像檔
5. 探索程式碼
依附元件
package.json 檔案會定義所需的程式庫依附元件:
{
"name": "collage_service",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"bluebird": "^3.7.2",
"express": "^4.17.1",
"imagemagick": "^0.1.3",
"@google-cloud/firestore": "^4.9.9",
"@google-cloud/storage": "^5.8.3"
}
}
我們依賴 Cloud Storage 程式庫讀取及儲存 Cloud Storage 中的圖片檔。我們宣告對 Cloud Firestore 的依附元件,以擷取先前儲存的圖片中繼資料。Express 是 JavaScript / Node 網頁架構,Bluebird 用於處理 Promise,imagemagick 則是操作圖片的程式庫。
Dockerfile
Dockerfile 定義應用程式的容器映像檔:
FROM node:14-slim
# installing Imagemagick
RUN set -ex; \
apt-get -y update; \
apt-get -y install imagemagick; \
rm -rf /var/lib/apt/lists/*
WORKDIR /picadaily/services/collage
COPY package*.json ./
RUN npm install --production
COPY . .
CMD [ "npm", "start" ]
我們使用輕量型 Node 14 基本映像檔。我們正在安裝 imagemagick 程式庫。接著,我們會安裝程式碼所需的 NPM 模組,並使用 npm start 執行節點程式碼。
index.js
讓我們進一步瞭解 index.js 程式碼:
const express = require('express');
const imageMagick = require('imagemagick');
const Promise = require("bluebird");
const path = require('path');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
我們需要各種依附元件才能執行程式:Express 是我們使用的 Node 網頁架構;ImageMagick 是用於處理圖片的程式庫;Bluebird 是用於處理 JavaScript Promise 的程式庫;Path 用於處理檔案和目錄路徑;Storage 和 Firestore 則分別用於處理 Google Cloud Storage (我們的圖片值區) 和 Cloud Firestore 資料儲存區。
const app = express();
app.get('/', async (req, res) => {
try {
console.log('Collage request');
/* ... */
} catch (err) {
console.log(`Error: creating the collage: ${err}`);
console.error(err);
res.status(500).send(err);
}
});
如上所示,我們有 Node 處理常式的結構:應用程式會回應 HTTP GET 要求。我們也會進行一些錯誤處理,以防發生問題。現在來看看這個結構內有什麼。
const thumbnailFiles = [];
const pictureStore = new Firestore().collection('pictures');
const snapshot = await pictureStore
.where('thumbnail', '==', true)
.orderBy('created', 'desc')
.limit(4).get();
if (snapshot.empty) {
console.log('Empty collection, no collage to make');
res.status(204).send("No collage created.");
} else {
/* ... */
}
我們的相片組合服務至少需要四張圖片 (已生成縮圖),因此請務必先上傳 4 張圖片。
我們會從 Cloud Firestore 儲存的中繼資料,擷取使用者上傳的最新 4 張圖片。我們會檢查產生的集合是否為空,然後在程式碼的 else 分支中繼續執行。
讓我們收集檔案名稱清單:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
我們將從縮圖 bucket 下載每個檔案,bucket 名稱來自我們在部署時設定的環境變數:
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);
await Promise.all(thumbnailFiles.map(async fileName => {
const filePath = path.resolve('/tmp', fileName);
await thumbBucket.file(fileName).download({
destination: filePath
});
}));
console.log('Downloaded all thumbnails');
上傳最新縮圖後,我們將使用 ImageMagick 程式庫,建立這些縮圖的 4x4 格線。我們使用 Bluebird 程式庫及其 Promise 實作,將回呼驅動的程式碼轉換為 async / await 友善的程式碼,然後等待建立圖片拼貼的 Promise:
const collagePath = path.resolve('/tmp', 'collage.png');
const thumbnailPaths = thumbnailFiles.map(f => path.resolve('/tmp', f));
const convert = Promise.promisify(im.convert);
await convert([
'(', ...thumbnailPaths.slice(0, 2), '+append', ')',
'(', ...thumbnailPaths.slice(2), '+append', ')',
'-size', '400x400', 'xc:none', '-background', 'none', '-append',
collagePath]);
console.log("Created local collage picture");
由於合成圖片已儲存至暫時資料夾的本機磁碟,我們現在需要將圖片上傳至 Cloud Storage,然後傳回成功的回應 (狀態碼 2xx):
await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");
res.status(204).send("Collage created.");
現在要讓 Node 指令碼監聽傳入的要求:
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started collage service on port ${PORT}`);
});
在來源檔案的結尾,我們有相關指令,可讓 Express 在 8080 預設通訊埠上實際啟動網頁應用程式。
6. 在本機測試
先在本機測試程式碼,確認可正常運作,再部署至雲端。
在 collage/nodejs 資料夾中,安裝 npm 依附元件並啟動伺服器:
npm install; npm start
如果一切運作正常,伺服器應會在通訊埠 8080 上啟動:
Started collage service on port 8080
按 CTRL-C 即可退出。
7. 建構並部署至 Cloud Run
部署到 Cloud Run 前,請將 Cloud Run 區域設為支援的區域,並將平台設為 managed:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
您可以檢查設定是否已完成:
gcloud config list ... [run] platform = managed region = europe-west1
您也可以使用 Google Cloud Buildpacks,讓 Cloud Run 為您建構容器映像檔,不必手動使用 Cloud Build 建構及發布容器映像檔。
執行下列指令來建構容器映像檔:
BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT
SERVICE_NAME=collage-service
gcloud run deploy $SERVICE_NAME \
--source . \
--no-allow-unauthenticated \
--update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS
請注意 –-source 旗標。這是 Cloud Run 的以來源為基礎的部署作業 。如果原始碼目錄中存在 Dockerfile,系統會使用該 Dockerfile 建構上傳的原始碼。如果原始碼目錄中沒有 Dockerfile,Google Cloud Buildpacks 會自動偵測您使用的語言,並擷取程式碼的依附元件,使用 Google 管理的安全基礎映像檔,製作可立即用於實際工作環境的容器映像檔。這項標記會讓 Cloud Run 使用 Google Cloud Buildpacks,建構 Dockerfile 中定義的容器映像檔。
另請注意,以來源為基礎的部署作業會使用 Artifact Registry 儲存建構的容器。Artifact Registry 是 Google Container Registry 的現代版本。如果專案尚未啟用 API,CLI 會提示啟用,並在您要部署的區域中建立名為 cloud-run-source-deploy 的存放區。
--no-allow-unauthenticated 旗標會將 Cloud Run 服務設為內部服務,只能由特定服務帳戶觸發。
8. 設定 Cloud Scheduler
Cloud Run 服務已準備就緒並完成部署,現在可以建立定期排程,每分鐘叫用一次服務。
建立服務帳戶:
SERVICE_ACCOUNT=collage-scheduler-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Collage Scheduler Service Account"
授予服務帳戶叫用 Cloud Run 服務的權限:
gcloud run services add-iam-policy-binding $SERVICE_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --role=roles/run.invoker
建立 Cloud Scheduler 工作,每 1 分鐘執行一次:
SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --format 'value(status.url)') gcloud scheduler jobs create http $SERVICE_NAME-job --schedule "* * * * *" \ --http-method=GET \ --location=europe-west1 \ --uri=$SERVICE_URL \ --oidc-service-account-email=$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --oidc-token-audience=$SERVICE_URL
您可以前往 Cloud 控制台的 Cloud Scheduler 專區,查看設定是否完成,以及是否指向 Cloud Run 服務網址:

9. 測試服務
如要測試設定是否正常運作,請檢查 thumbnails bucket 中是否有合成圖片 (名為 collage.png)。您也可以檢查服務記錄:

10. 清除 (選用)
如果您不打算繼續進行本系列的其他實驗室,可以清除資源來節省費用,並成為優質的雲端使用者。您可以按照下列方式個別清除資源。
刪除服務:
gcloud run services delete $SERVICE_NAME -q
刪除 Cloud Scheduler 工作:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
或者,您也可以刪除整個專案:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. 恭喜!
恭喜!您已建立排程服務:由於 Cloud Scheduler 每分鐘都會在 Pub/Sub 主題上推送訊息,因此系統會叫用 Cloud Run 拼貼服務,並將圖片附加在一起,建立最終圖片。
涵蓋內容
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore