程式碼研究室簡介
1. 總覽
在本程式碼研究室中,您將建立新的 Cloud Run 服務 (美術拼貼服務),並由 Cloud Scheduler 定期觸發。這項服務會擷取最新上傳的相片,然後建立這些相片的美術拼貼:在 Cloud Firestore 中找到近期相片的清單,然後從 Cloud Storage 下載實際的相片檔案。
課程內容
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. 設定和需求
自修環境設定
- 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶。
- 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 不使用的字元字串,您可以隨時更新。
- 所有 Google Cloud 專案的專案 ID 均不得重複,且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常稱為
PROJECT_ID
),因此如果您不喜歡的話,可以再隨機產生一個,或者,您也可以自行嘗試看看是否可用。是「凍結」建立專案後 - 還有第三個值,也就是部分 API 使用的專案編號。如要進一步瞭解這三個值,請參閱說明文件。
- 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行這個程式碼研究室並不會產生任何費用,如果有的話。如要關閉資源,以免產生本教學課程結束後產生的費用,請按照任「清除所用資源」操作請參閱本程式碼研究室結尾處的操作說明。Google Cloud 的新使用者符合 $300 美元免費試用計畫的資格。
啟動 Cloud Shell
雖然 Google Cloud 可以從筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是一種在 Cloud 中執行的指令列環境。
在 GCP 控制台的右上方,按一下「Cloud Shell」圖示:
佈建並連線至環境的作業只需幾分鐘的時間。完成後,您應該會看到類似下方的內容:
這部虛擬機器都裝載了您需要的所有開發工具。提供永久的 5 GB 主目錄,而且在 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 用於處理承諾,而 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 是要使用的節點網路架構、用於執行映像檔操作的 ImageMagick 程式庫、Bluebird 是處理 JavaScript 承諾的程式庫、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 Firerstore 的中繼資料擷取使用者上傳的最新 4 張相片。我們會檢查產生的集合是否空白,然後繼續在程式碼的其他位置進行。
讓我們收集檔案名稱清單:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
我們會從縮圖值區下載每個檔案,檔案名稱來自我們在部署時設定的環境變數:
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
友善程式碼,然後等待產生圖片美術拼貼的承諾:
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
除了透過 Cloud Build 手動建構及發布容器映像檔,您也可以透過 Cloud Run 使用 Google Cloud Buildpacks 來建構容器映像檔。
執行下列指令來建構容器映像檔:
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 服務網址:
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