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ụ ảnh ghép mới trên Cloud Run. Dịch vụ này sẽ được Trình lập lịch biểu đám mây kích hoạt theo định kỳ. Dịch vụ này tìm nạp các bức ảnh mới nhất được tải lên và tạo ảnh ghép gồm các bức ảnh đó: tìm danh sách các bức ảnh gần đây trong Cloud Firestore, sau đó tải các tệp ảnh thực tế xuống từ Cloud Storage.
Kiến thức bạn sẽ học được
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. Thiết lập và yêu cầu
Thiết lập môi trường theo tiến độ riêng
- Đăng nhập vào Google Cloud Console rồi tạo dự án mới hoặc sử dụng lại 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.
- 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ự không được API của Google sử 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 trong tất cả các dự án Google Cloud và không thể thay đổi (không thể thay đổi sau khi đã đặt). Cloud Console sẽ tự động tạo một chuỗi duy nhất; thường bạn không quan tâm đến sản phẩm đó là gì. 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 (và mã này thường được xác định là
PROJECT_ID
). Vì vậy, nếu không thích, bạn có thể tạo một mã ngẫu nhiên khác hoặc bạn có thể thử mã của riêng mình để xem có mã này chưa. Sau đó, video sẽ được "đóng băng" sau khi tạo dự án. - Có giá trị thứ ba là Project Number (Số dự án) mà một số API sử dụng. Tìm hiểu thêm về cả ba giá trị này trong tài liệu này.
- Tiếp theo, bạn sẽ cần bật tính năng thanh toán trong Cloud Console để sử dụng tài nguyên/API trên Cloud. Việc chạy qua lớp học lập trình này sẽ không tốn nhiều chi phí. Để tắt các tài nguyên để bạn không phải chịu thanh toán ngoài hướng dẫn này, hãy làm theo mọi thao tác "dọn dẹp" hướng dẫn ở 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í 300 USD.
Khởi động Cloud Shell
Mặc dù bạn 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 trong Đám mây.
Trong Bảng điều khiển GCP, hãy nhấp vào biểu tượng Cloud Shell ở thanh công cụ trên cùng bên phải:
Sẽ chỉ mất một chút thời gian để cấp phép và kết nối với môi trường. Sau khi hoàn tất, bạn sẽ thấy như sau:
Máy ảo này chứa tất cả các công cụ phát triển mà bạn cần. Phiên bản này cung cấp thư mục gốc có dung lượng ổn định 5 GB và chạy trên Google Cloud, giúp nâng cao đáng kể hiệu suất và khả năng xác thực của mạng. Bạn có thể thực hiện tất cả công việc trong phòng thí nghiệm này chỉ bằng một trình duyệt.
3. Bật API
Bạn cần có một Cloud Scheduler để kích hoạt dịch vụ Cloud Run theo định kỳ. Đảm bảo bạn đã bật chế độ này:
gcloud services enable cloudscheduler.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.
4. Sao chép mã
Sao chép mã nếu bạn chưa truy cập vào 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/collage/nodejs
Bạn sẽ có bố cục tệp sau đây cho dịch vụ:
services | ├── collage | ├── nodejs | ├── Dockerfile ├── index.js ├── package.json
Bên trong thư mục này, bạn có 3 tệp:
index.js
chứa mã Node.jspackage.json
xác định các phần phụ thuộc của thư việnDockerfile
xác định hình ảnh vùng chứa
5. Khám phá đoạn 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": "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"
}
}
Chúng tôi dựa vào thư viện Cloud Storage để đọc và lưu tệp hình ảnh trong Cloud Storage. Chúng ta khai báo phần phụ thuộc trên Cloud Firestore để tìm nạp siêu dữ liệu ảnh mà chúng ta đã lưu trữ trước đây. Express là một khung web dành cho JavaScript / Nút. Bluebird được dùng để xử lý lời hứa, còn imagemagick là thư viện để chỉnh sửa hình ảnh.
tệp Docker
Dockerfile
xác định hình ảnh vùng chứa cho ứng dụng:
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" ]
Chúng tôi đang sử dụng hình ảnh cơ sở của Nút 14 sáng. Chúng tôi đang cài đặt thư viện imagemagick. Sau đó, chúng ta cài đặt các mô-đun TLD cần thiết cho mã của chúng ta và chạy mã nút với phần đầu npm.
index.js
Hãy xem xét kỹ hơn mã index.js
của chúng ta:
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');
Chúng tôi cần có nhiều phần phụ thuộc cần thiết để chạy chương trình: Express là khung web Nút mà chúng tôi sẽ sử dụng, ImageMagick thư viện để xử lý các thao tác đối với hình ảnh, Bluebird là một thư viện xử lý các lời hứa về JavaScript, Path được dùng để xử lý các tệp và đường dẫn thư mục, sau đó Storage và Firestore sẽ dùng để xử lý các tệp và đường dẫn thư mục tương ứng với Google Cloud Storage (nhóm hình ảnh) và kho dữ liệu 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);
}
});
Ở trên, chúng ta có cấu trúc của trình xử lý Nút: ứng dụng phản hồi các yêu cầu HTTP GET. Và chúng ta đang xử lý một chút lỗi trong trường hợp có sự cố. Bây giờ, hãy cùng xem bên trong cấu trúc này là gì.
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 {
/* ... */
}
Dịch vụ ghép ảnh của chúng tôi sẽ cần ít nhất bốn ảnh (đã được tạo hình thu nhỏ), do đó hãy nhớ tải lên 4 ảnh trước.
Chúng tôi truy xuất 4 hình ảnh mới nhất mà người dùng đã tải lên từ siêu dữ liệu lưu trữ trong Cloud Firerstore. Chúng ta sẽ kiểm tra xem tập hợp thu được có trống hay không, sau đó tiếp tục thực hiện thêm trong nhánh else của mã.
Hãy thu thập danh sách tên tệp:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
Chúng ta sẽ tải từng tệp trong số đó xuống từ bộ chứa hình thu nhỏ, có tên được lấy từ một biến môi trường mà chúng ta đã đặt tại thời điểm triển khai:
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');
Sau khi hình thu nhỏ mới nhất được tải lên, chúng ta sẽ sử dụng thư viện ImageMagick để tạo lưới 4x4 cho các hình thu nhỏ đó. Chúng ta sử dụng thư viện Bluebird và triển khai Promise của thư viện này để chuyển đổi mã dùng lệnh gọi lại thành mã thân thiện với async
/ await
, sau đó chúng ta chờ đợi lời hứa sẽ tạo ảnh ghép:
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");
Do ảnh ghép đã được lưu vào ổ đĩa cục bộ trong thư mục tạm thời, bây giờ chúng ta cần tải ảnh lên Cloud Storage, sau đó trả về phản hồi thành công (mã trạng thái 2xx):
await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");
res.status(204).send("Collage created.");
Bây giờ, đã đến lúc để tập lệnh Nút xử lý các yêu cầu sắp tới:
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started collage service on port ${PORT}`);
});
Ở cuối tệp nguồn, chúng ta có hướng dẫn để Express thực sự khởi động ứng dụng web trên cổng mặc định 8080.
6. Kiểm thử cục bộ
Kiểm thử mã trên thiết bị để đảm bảo mã hoạt động trước khi triển khai lên đám mây.
Bên trong thư mục collage/nodejs
, hãy cài đặt các phần phụ thuộc npm và khởi động máy chủ:
npm install; npm start
Nếu mọi thứ diễn ra suôn sẻ, máy chủ sẽ khởi động trên cổng 8080:
Started collage service on port 8080
Sử dụng CTRL-C
để thoát.
7. Xây dựng và triển khai 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 những khu vực và nền tảng được hỗ trợ thành managed
:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
Bạn có thể kiểm tra để đảm bảo 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 mình bằng cách sử dụng Google Cloud Buildpacks.
Chạy lệnh sau để tạo hình ảnh vùng chứa:
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
Lưu ý cờ –-source
. Đây là quy trình triển khai dựa trên nguồn trong Cloud Run. Nếu Dockerfile
có trong thư mục mã nguồn thì mã nguồn đã tải lên sẽ được tạo bằng Dockerfile
đó. Nếu không có Dockerfile
nào trong thư mục mã nguồn, thì các gói bản dựng của Google Cloud sẽ tự động phát hiện ngôn ngữ mà bạn đang sử dụng và tìm nạp các phần phụ thuộc của mã để tạo hình ảnh vùng chứa sẵn sàng cho việc phát hành công khai bằng cách dùng hình ảnh cơ sở bảo mật do Google quản lý. Thao tác này sẽ gắn cờ Cloud Run để sử dụng Google Cloud Buildpacks nhằm tạo hình ảnh vùng chứa được xác định trong Dockerfile
.
Ngoài ra, xin lưu ý rằng tính năng triển khai dựa trên nguồn sử dụng Artifact Registry để lưu trữ vùng chứa đã xây dựng. Artifact Registry là một phiên bản hiện đại của Google Container Registry. CLI sẽ nhắc bật API nếu API này chưa được bật trong dự án và sẽ tạo một kho lưu trữ có tên là cloud-run-source-deploy
tại khu vực bạn đang triển khai.
Cờ --no-allow-unauthenticated
khiến dịch vụ Cloud Run trở thành một dịch vụ nội bộ chỉ được kích hoạt bằng một số tài khoản dịch vụ cụ thể.
8. Thiết lập Trình lập lịch biểu đám mây
Hiện tại, dịch vụ Cloud Run đã sẵn sàng và được triển khai, đã đến lúc tạo lịch biểu định kỳ để gọi dịch vụ mỗi phút.
Tạo tài khoản dịch vụ:
SERVICE_ACCOUNT=collage-scheduler-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Collage Scheduler Service Account"
Cấp quyền cho tài khoản dịch vụ để gọi dịch vụ 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
Tạo công việc Trình lập lịch biểu trên đám mây để thực thi 1 phút một lần:
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
Bạn có thể chuyển đến phần Cloud Scheduler trong Cloud Console để xem phần này đã được thiết lập và trỏ đến url dịch vụ Cloud Run:
9. Kiểm thử dịch vụ
Để kiểm tra xem quá trình thiết lập có hoạt động hay không, hãy kiểm tra bộ chứa thumbnails
để tìm ảnh ghép (có tên là collage.png
). Bạn cũng có thể kiểm tra nhật ký của dịch vụ:
10. Dọn dẹp (Không bắt buộc)
Nếu không có ý định tiếp tục sử dụng các phòng thí nghiệm khác trong chuỗi chương trình này, bạn có thể dọn dẹp các tài nguyên để tiết kiệm chi phí và trở thành một công dân tốt về công nghệ đám mây. Bạn có thể dọn dẹp từng tài nguyên như sau.
Xoá dịch vụ:
gcloud run services delete $SERVICE_NAME -q
Xoá công việc của Cloud Scheduler:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
Ngoài ra, bạn có thể xoá toàn bộ dự án theo cách sau:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. Xin chúc mừng!
Xin chúc mừng! Bạn đã tạo một dịch vụ theo lịch: nhờ Cloud Scheduler, dịch vụ này đẩy tin nhắn mỗi phút về một chủ đề Pub/Sub, dịch vụ ảnh ghép Cloud Run của bạn được gọi và có thể nối các hình ảnh với nhau để tạo ra hình ảnh thu được.
Nội dung đã đề cập
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore