每天一拍:研究室 3—使用最新的相片製作美術拼貼

每天一拍:研究室 3—使用最新的相片製作美術拼貼

程式碼研究室簡介

subject上次更新時間:1月 31, 2023
account_circle作者:Guillaume Laforge, Mete Atamel

1. 總覽

在本程式碼研究室中,您將建立新的 Cloud Run 服務 (美術拼貼服務),並由 Cloud Scheduler 定期觸發。這項服務會擷取最新上傳的相片,然後建立這些相片的美術拼貼:在 Cloud Firestore 中找到近期相片的清單,然後從 Cloud Storage 下載實際的相片檔案。

df20f5d0402b54b4.png

課程內容

  • Cloud Run
  • Cloud Scheduler
  • Cloud Storage
  • Cloud Firestore

2. 設定和需求

自修環境設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 不使用的字元字串,您可以隨時更新。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常稱為 PROJECT_ID),因此如果您不喜歡的話,可以再隨機產生一個,或者,您也可以自行嘗試看看是否可用。是「凍結」建立專案後
  • 還有第三個值,也就是部分 API 使用的專案編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行這個程式碼研究室並不會產生任何費用,如果有的話。如要關閉資源,以免產生本教學課程結束後產生的費用,請按照任「清除所用資源」操作請參閱本程式碼研究室結尾處的操作說明。Google Cloud 的新使用者符合 $300 美元免費試用計畫的資格。

啟動 Cloud Shell

雖然 Google Cloud 可以從筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是一種在 Cloud 中執行的指令列環境。

在 GCP 控制台的右上方,按一下「Cloud Shell」圖示:

bce75f34b2c53987.png

佈建並連線至環境的作業只需幾分鐘的時間。完成後,您應該會看到類似下方的內容:

f6ef2b5f13479f3a.png

這部虛擬機器都裝載了您需要的所有開發工具。提供永久的 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 建構上傳的原始碼。如果原始碼目錄中沒有 DockerfileGoogle 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 服務網址:

35119e28c1da53f3.png

9. 測試服務

如要測試設定是否正常運作,請在 thumbnails 值區中查看美術拼貼圖片 (名為 collage.png)。您也可以查看服務的記錄:

93922335a384be2e.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

後續步驟