Pic-a-daily: Lab 5 – Dọn dẹp sau khi xoá hình ảnh

1. Tổng quan

Trong lớp học lập trình này, bạn sẽ tạo một dịch vụ Cloud Run mới (trình thu gom rác hình ảnh) do Eventarc (một dịch vụ mới để nhận sự kiện trong Cloud Run) kích hoạt. Khi một bức ảnh bị xoá khỏi nhóm ảnh, dịch vụ sẽ nhận được một sự kiện từ Eventarc. Sau đó, hàm này sẽ xoá hình ảnh khỏi nhóm hình thu nhỏ và cũng xoá hình ảnh đó khỏi bộ sưu tập hình ảnh Firestore.

d93345bfc235f81e.png

Kiến thức bạn sẽ học được

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc

2. Thiết lập và yêu cầu

Thiết lập môi trường theo tốc độ của riêng bạn

  1. Đăng nhập vào Google Cloud Console rồi tạo một dự án mới hoặc sử dụng lại một dự án hiện có. Nếu chưa có tài khoản Gmail hoặc Google Workspace, bạn phải tạo một tài khoản.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • Tên dự án là tên hiển thị của những người tham gia dự án này. Đây là một chuỗi ký tự mà các API của Google không dùng và bạn có thể cập nhật chuỗi này bất cứ lúc nào.
  • Mã dự án phải là duy nhất trên tất cả các dự án trên Google Cloud và không thể thay đổi (bạn không thể thay đổi sau khi đã đặt). Cloud Console sẽ tự động tạo một chuỗi duy nhất; thường thì bạn không cần quan tâm đến chuỗi này. Trong hầu hết các lớp học lập trình, bạn sẽ cần tham chiếu đến Mã dự án (thường được xác định là PROJECT_ID). Vì vậy, nếu không thích mã này, bạn có thể tạo một mã ngẫu nhiên khác hoặc thử mã của riêng mình để xem mã đó có dùng được hay không. Sau đó, mã này sẽ "đóng băng" sau khi dự án được tạo.
  • Có một giá trị thứ ba là Số dự án mà một số API sử dụng. Tìm hiểu thêm về cả 3 giá trị này trong tài liệu.
  1. Tiếp theo, bạn cần bật tính năng thanh toán trong Cloud Console để sử dụng các tài nguyên/API trên Cloud. Việc thực hiện lớp học lập trình này sẽ không tốn nhiều chi phí, nếu có. Để tắt các tài nguyên nhằm tránh bị tính phí ngoài phạm vi hướng dẫn này, hãy làm theo mọi hướng dẫn "dọn dẹp" ở cuối lớp học lập trình. Người dùng mới của Google Cloud đủ điều kiện tham gia chương trình Dùng thử miễn phí trị giá 300 USD.

Khởi động Cloud Shell

Mặc dù có thể vận hành Google Cloud từ xa trên máy tính xách tay, nhưng trong lớp học lập trình này, bạn sẽ sử dụng Google Cloud Shell, một môi trường dòng lệnh chạy trên Cloud.

Trên Bảng điều khiển GCP, hãy nhấp vào biểu tượng Cloud Shell trên thanh công cụ ở trên cùng bên phải:

bce75f34b2c53987.png

Quá trình này chỉ mất vài phút để cung cấp và kết nối với môi trường. Khi quá trình này kết thúc, bạn sẽ thấy như sau:

f6ef2b5f13479f3a.png

Máy ảo này được trang bị tất cả các công cụ phát triển mà bạn cần. Nó cung cấp một thư mục chính có dung lượng 5 GB và chạy trên Google Cloud, giúp tăng cường đáng kể hiệu suất mạng và hoạt động xác thực. Bạn chỉ cần một trình duyệt là có thể thực hiện mọi thao tác trong phòng thí nghiệm này.

3. Giới thiệu về Eventarc

Eventarc giúp bạn dễ dàng kết nối các dịch vụ Cloud Run với các sự kiện từ nhiều nguồn. Nó sẽ xử lý việc tiếp nhận, phân phối, bảo mật, uỷ quyền và xử lý lỗi cho bạn.

776ed63706ca9683.png

Bạn có thể lấy các sự kiện từ các nguồn Google Cloud và các ứng dụng tuỳ chỉnh xuất bản lên Cloud Pub/Sub, rồi gửi các sự kiện đó đến các đích đến Google Cloud Run.

Các sự kiện từ nhiều nguồn trên Google Cloud được gửi qua Nhật ký kiểm tra trên đám mây. Độ trễ và tính sẵn có của việc gửi sự kiện từ những nguồn này sẽ phụ thuộc vào độ trễ và tính sẵn có của Nhật ký kiểm tra trên đám mây. Bất cứ khi nào một sự kiện từ nguồn Google Cloud được kích hoạt, một mục nhập Nhật ký kiểm tra trên đám mây tương ứng sẽ được tạo.

Các ứng dụng tuỳ chỉnh xuất bản lên Cloud Pub/Sub có thể xuất bản thông báo đến một chủ đề Pub/Sub mà chúng chỉ định ở bất kỳ định dạng nào.

Trình kích hoạt sự kiện là cơ chế lọc để chỉ định sự kiện nào sẽ được gửi đến đích nào.

Tất cả các sự kiện đều được gửi ở định dạng CloudEvents v1.0 để có khả năng tương tác giữa các dịch vụ.

4. Trước khi bắt đầu

Bật API

Bạn sẽ cần dịch vụ Eventarc để kích hoạt dịch vụ Cloud Run. Đảm bảo bạn đã bật tính năng này:

gcloud services enable eventarc.googleapis.com

Bạn sẽ thấy thao tác hoàn tất thành công:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

Định cấu hình tài khoản dịch vụ

Tài khoản dịch vụ tính toán mặc định sẽ được dùng trong các điều kiện kích hoạt. Cấp vai trò eventarc.eventReceiver cho tài khoản dịch vụ mặc định của Compute Engine:

PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format='value(projectNumber)')

gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
    --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
    --role roles/eventarc.eventReceiver

Cấp vai trò pubsub.publisher cho tài khoản dịch vụ Cloud Storage. Đây là điều kiện cần thiết cho trình kích hoạt Eventarc Cloud Storage:

SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER)

gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member serviceAccount:$SERVICE_ACCOUNT \
    --role roles/pubsub.publisher

Nếu bạn đã bật tài khoản dịch vụ Pub/Sub vào hoặc trước ngày 8 tháng 4 năm 2021, hãy cấp vai trò iam.serviceAccountTokenCreator cho tài khoản dịch vụ Pub/Sub:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
  --role roles/iam.serviceAccountTokenCreator

5. Sao chép mã

Sao chép mã nếu bạn chưa thực hiện trong lớp học lập trình trước:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

Sau đó, bạn có thể chuyển đến thư mục chứa dịch vụ:

cd serverless-photosharing-workshop/services/garbage-collector/nodejs

Bạn sẽ có bố cục tệp sau cho dịch vụ:

services
 |
 ├── garbage-collector
      |
      ├── nodejs
           |
           ├── index.js
           ├── package.json

Trong thư mục này, bạn có 3 tệp:

  • index.js chứa mã Node.js
  • package.json xác định các phần phụ thuộc của thư viện

6. Khám phá mã

Phần phụ thuộc

Tệp package.json xác định các phần phụ thuộc cần thiết của thư viện:

{
  "name": "garbage_collector_service",
  "version": "0.0.1",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "cloudevents": "^4.0.1",
    "express": "^4.17.1",
    "@google/events": "^3.1.0",
    "@google-cloud/firestore": "^4.9.9",
    "@google-cloud/storage": "^5.8.3"
  }
}

Chúng tôi phụ thuộc vào thư viện Cloud Storage để xoá hình ảnh trong Cloud Storage. Chúng tôi khai báo một phần phụ thuộc vào Cloud Firestore để xoá cả siêu dữ liệu hình ảnh mà chúng tôi đã lưu trữ trước đó. Ngoài ra, chúng tôi phụ thuộc vào SDK CloudEvents và các thư viện Google Events để đọc CloudEvents do Eventarc gửi. Express là một khung web JavaScript / Node. Bluebird được dùng để xử lý các promise.

index.js

Hãy xem xét kỹ hơn mã index.js của chúng ta:

const express = require('express');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
const { HTTP } = require("cloudevents");
const {toStorageObjectData} = require('@google/events/cloud/storage/v1/StorageObjectData');

Chúng ta cần có nhiều thành phần phụ thuộc để chương trình chạy: Express là khung web Node mà chúng ta sẽ sử dụng, Bluebird là một thư viện để xử lý các lời hứa của JavaScript, Storage và Firestore lần lượt dùng để làm việc với Google Cloud Storage (các nhóm hình ảnh của chúng ta) và kho dữ liệu Cloud Firestore. Ngoài ra, chúng tôi yêu cầu CloudEvent đọc CloudEvent do Eventarc StoreObjectData gửi từ thư viện Google Events để đọc nội dung sự kiện Cloud Storage của CloudEvent.

const app = express();
app.use(express.json());

app.post('/', async (req, res) => {
    try {
        const cloudEvent = HTTP.toEvent({ headers: req.headers, body: req.body });
        console.log(cloudEvent);


        /* ... */

    } catch (err) {
        console.log(`Error: ${err}`);
        res.status(500).send(err);
    }
});

Ở trên, chúng ta có cấu trúc của trình xử lý Node: ứng dụng của chúng ta phản hồi các yêu cầu HTTP POST. Hàm này đọc CloudEvent từ yêu cầu HTTP và chúng ta sẽ xử lý một số lỗi trong trường hợp có vấn đề xảy ra. Bây giờ, hãy xem bên trong cấu trúc này có gì.

Bước tiếp theo là truy xuất và phân tích cú pháp nội dung CloudEvent, đồng thời truy xuất tên đối tượng:

const storageObjectData = toStorageObjectData(cloudEvent.data);
console.log(storageObjectData);

const objectName = storageObjectData.name;

Sau khi biết tên hình ảnh, chúng ta có thể xoá hình ảnh đó khỏi nhóm hình thu nhỏ:

try {
    await storage.bucket(bucketThumbnails).file(objectName).delete();
    console.log(`Deleted '${objectName}' from bucket '${bucketThumbnails}'.`);
}
catch(err) {
    console.log(`Failed to delete '${objectName}' from bucket '${bucketThumbnails}': ${err}.`);
}

Bước cuối cùng, hãy xoá siêu dữ liệu hình ảnh khỏi bộ sưu tập Firestore:

try {
    const pictureStore = new Firestore().collection('pictures');
    const docRef = pictureStore.doc(objectName);
    await docRef.delete();

    console.log(`Deleted '${objectName}' from Firestore collection 'pictures'`);
}
catch(err) {
    console.log(`Failed to delete '${objectName}' from Firestore: ${err}.`);
}

res.status(200).send(`Processed '${objectName}'.`);

Bây giờ là lúc để tập lệnh Node của chúng ta lắng nghe các yêu cầu đến. Ngoài ra, hãy kiểm tra để đảm bảo bạn đã thiết lập các biến môi trường bắt buộc:

app.listen(PORT, () => {
    if (!bucketThumbnails) throw new Error("BUCKET_THUMBNAILS not set");
    console.log(`Started service on port ${PORT}`);
});

7. Kiểm thử cục bộ

Kiểm thử mã cục bộ để đảm bảo mã hoạt động trước khi triển khai lên đám mây.

Trong thư mục garbage-collector/nodejs, hãy cài đặt các phần phụ thuộc npm và khởi động máy chủ:

export BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT

npm install; npm start

Nếu mọi thứ diễn ra suôn sẻ, thì máy chủ sẽ khởi động trên cổng 8080:

Started service on port 8080

Sử dụng CTRL-C để thoát.

8. Tạo bản dựng và triển khai lên Cloud Run

Trước khi triển khai lên Cloud Run, hãy đặt khu vực Cloud Run thành một trong các khu vực được hỗ trợ và nền tảng thành managed:

REGION=europe-west1
gcloud config set run/region $REGION
gcloud config set run/platform managed

Bạn có thể kiểm tra để đảm bảo rằng cấu hình đã được thiết lập:

gcloud config list

...
[run]
platform = managed
region = europe-west1

Thay vì tạo và xuất bản hình ảnh vùng chứa bằng Cloud Build theo cách thủ công, bạn cũng có thể dựa vào Cloud Run để tạo hình ảnh vùng chứa cho bạn bằng Google Cloud Buildpacks.

Chạy lệnh sau để tạo hình ảnh vùng chứa bằng cách sử dụng Google Cloud Buildpack rồi triển khai hình ảnh vùng chứa đó vào Cloud Run:

SERVICE_NAME=garbage-collector-service

gcloud run deploy $SERVICE_NAME \
    --source . \
    --no-allow-unauthenticated \
    --update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS

Lưu ý cờ –-source. Lệnh này gắn cờ Cloud Run để sử dụng Google Cloud Buildpacks nhằm tạo hình ảnh vùng chứa mà không có Dockerfile. Cờ --no-allow-unauthenticated biến dịch vụ Cloud Run thành một dịch vụ nội bộ, chỉ được kích hoạt bởi các tài khoản dịch vụ cụ thể. Sau đó, bạn sẽ tạo một Trình kích hoạt bằng tài khoản dịch vụ mặc định của Compute Engine có vai trò run.invoker để gọi các dịch vụ Cloud Run nội bộ.

9. Tạo điều kiện kích hoạt

Trong Eventarc, Trình kích hoạt xác định dịch vụ nào sẽ nhận được loại sự kiện nào. Trong trường hợp này, bạn muốn dịch vụ nhận được các sự kiện khi một tệp bị xoá trong một nhóm.

Đặt vị trí của Trình kích hoạt ở cùng khu vực với vùng chứa ảnh đã tải lên:

gcloud config set eventarc/location eu

Tạo một trình kích hoạt AuditLog để lọc các sự kiện storage.objects.delete và gửi đến dịch vụ Cloud Run:

BUCKET_IMAGES=uploaded-pictures-$GOOGLE_CLOUD_PROJECT

gcloud eventarc triggers create trigger-$SERVICE_NAME \
  --destination-run-service=$SERVICE_NAME \
  --destination-run-region=$REGION \
  --event-filters="type=google.cloud.storage.object.v1.deleted" \
  --event-filters="bucket=$BUCKET_IMAGES" \
  --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

Bạn có thể kiểm tra kỹ để đảm bảo Trình kích hoạt được tạo bằng lệnh sau:

gcloud eventarc triggers list

10. Kiểm thử dịch vụ

Để kiểm tra xem dịch vụ có hoạt động hay không, hãy chuyển đến vùng chứa uploaded-pictures rồi xoá một trong các bức ảnh. Bạn sẽ thấy trong nhật ký của dịch vụ rằng dịch vụ đã xoá bức ảnh có liên quan trong vùng chứa thumbnails và cũng xoá tài liệu của bức ảnh đó khỏi bộ sưu tập pictures Firestore.

519abf90e7ea4d12.png

11. Dọn dẹp (Không bắt buộc)

Nếu không có ý định tiếp tục với các phòng thí nghiệm khác trong loạt bài này, bạn có thể dọn dẹp tài nguyên để tiết kiệm chi phí và trở thành một công dân đám mây tốt. Bạn có thể dọn dẹp từng tài nguyên riêng lẻ như sau.

Xoá dịch vụ:

gcloud run services delete $SERVICE_NAME -q

Xoá điều kiện kích hoạt Eventarc:

gcloud eventarc triggers delete trigger-$SERVICE_NAME -q

Ngoài ra, bạn có thể xoá toàn bộ dự án:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

12. Xin chúc mừng!

Xin chúc mừng! Bạn đã tạo một dịch vụ Cloud Run, trình thu gom rác hình ảnh, được kích hoạt bởi Eventarc, một dịch vụ mới để nhận các sự kiện trong Cloud Run. Khi một bức ảnh bị xoá khỏi nhóm ảnh, dịch vụ sẽ nhận được một sự kiện từ Eventarc. Sau đó, hàm này sẽ xoá hình ảnh khỏi nhóm hình thu nhỏ và cũng xoá hình ảnh đó khỏi bộ sưu tập hình ảnh Firestore.

Nội dung đã đề cập

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc