1. Обзор
В этом практическом задании вы создадите новый сервис Cloud Run, сервис создания коллажей, который будет запускаться планировщиком Cloud Scheduler через регулярные интервалы времени. Сервис получает последние загруженные изображения и создает из них коллаж: он находит список последних изображений в Cloud Firestore, а затем загружает сами файлы изображений из Cloud Storage.

Что вы узнаете
- Cloud Run
- Планировщик облачных задач
- Облачное хранилище
- Облачный Firestore
2. Настройка и требования
Настройка среды для самостоятельного обучения
- Войдите в консоль Google Cloud и создайте новый проект или используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .



- Название проекта — это отображаемое имя участников данного проекта. Это строка символов, не используемая API Google, и вы можете изменить её в любое время.
- Идентификатор проекта должен быть уникальным для всех проектов Google Cloud и неизменяемым (его нельзя изменить после установки). Консоль Cloud автоматически генерирует уникальную строку; обычно вам неважно, какая она. В большинстве практических заданий вам потребуется указать идентификатор проекта (обычно он обозначается как
PROJECT_ID), поэтому, если он вам не нравится, сгенерируйте другой случайный идентификатор или попробуйте свой собственный и посмотрите, доступен ли он. Затем он "замораживается" после создания проекта. - Существует третье значение — номер проекта , который используется некоторыми API. Подробнее обо всех трех значениях можно узнать в документации .
- Далее вам потребуется включить оплату в консоли Cloud, чтобы использовать ресурсы/API Cloud. Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Чтобы отключить ресурсы и избежать дополнительных расходов после завершения этого урока, следуйте инструкциям по «очистке», приведенным в конце практического задания. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .
Запустить Cloud Shell
Хотя Google Cloud можно управлять удаленно с ноутбука, в этом практическом занятии вы будете использовать Google Cloud Shell — среду командной строки, работающую в облаке.
В консоли GCP щелкните значок Cloud Shell на панели инструментов в правом верхнем углу:

Подготовка и подключение к среде займут всего несколько минут. После завершения вы должны увидеть что-то подобное:

Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Она предоставляет постоянный домашний каталог размером 5 ГБ и работает в облаке Google, что значительно повышает производительность сети и аутентификацию. Всю работу в этой лаборатории можно выполнять с помощью обычного браузера.
3. Включите API.
Для регулярного запуска службы Cloud Run вам потребуется планировщик задач Cloud Scheduler. Убедитесь, что он включен:
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 и запускаем код Node с помощью команды 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, 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.js: наше приложение отвечает на 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 фотографии.
Мы получаем 4 последних изображения, загруженных нашими пользователями, из метаданных, хранящихся в CloudFirestore. Мы проверяем, пуста ли полученная коллекция, а затем продолжаем выполнение в ветке else нашего кода.
Давайте соберем список имен файлов:
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");
Поскольку изображение коллажа сохранено локально на диске во временной папке, теперь нам необходимо загрузить его в облачное хранилище и получить успешный ответ (код состояния 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. CLI предложит включить API, если он еще не включен в проекте, и создаст репозиторий с именем cloud-run-source-deploy в регионе, куда вы развертываете приложение.
Флаг --no-allow-unauthenticated делает службу Cloud Run внутренней службой, которая будет запускаться только определенными учетными записями служб.
8. Настройка облачного планировщика.
Теперь, когда служба 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, которое будет выполняться каждую минуту:
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 Console вы можете перейти в раздел Cloud Scheduler, чтобы убедиться, что он настроен и указывает на URL-адрес службы Cloud Run:

9. Проверьте работу сервиса.
Чтобы проверить работоспособность настройки, проверьте наличие изображения коллажа (называемого collage.png ) в папке thumbnails . Вы также можете проверить журналы службы:

10. Уборка (необязательно)
Если вы не планируете продолжать выполнение остальных лабораторных работ из этой серии, вы можете освободить ресурсы, чтобы сэкономить средства и в целом ответственно относиться к облачным технологиям. Освободить ресурсы можно по отдельности следующим образом.
Удалить сервис:
gcloud run services delete $SERVICE_NAME -q
Удалите задание планировщика облачных задач:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
В качестве альтернативы вы можете удалить весь проект:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. Поздравляем!
Поздравляем! Вы создали запланированную службу: благодаря Cloud Scheduler, который каждую минуту отправляет сообщение в топик Pub/Sub, запускается ваша служба Cloud Run для создания коллажей, которая может объединять изображения для создания итогового изображения.
Что мы рассмотрели
- Cloud Run
- Планировщик облачных задач
- Облачное хранилище
- Облачный Firestore