1. Введение

Обзор
Сервисы Cloud Run хорошо подходят для контейнеров, работающих неограниченно долго и ожидающих HTTP-запросов, тогда как задания Cloud Run лучше подходят для контейнеров, работающих до завершения (в настоящее время до 24 часов ) и не обрабатывающих запросы. Например, обработка записей из базы данных, обработка списка файлов из хранилища Cloud Storage или длительная операция, такая как вычисление числа Пи, хорошо бы работали, если бы были реализованы в виде задания Cloud Run.
Задания не имеют возможности обрабатывать запросы или прослушивать порты. Это означает, что в отличие от сервисов Cloud Run, задания не должны включать веб-сервер. Вместо этого контейнеры заданий должны завершать свою работу по завершении.
В заданиях Cloud Run можно запускать несколько копий контейнера параллельно, указав количество задач. Каждая задача представляет собой одну запущенную копию контейнера. Использование нескольких задач полезно, если каждая задача может независимо обрабатывать подмножество ваших данных. Например, обработка 10 000 записей из Cloud SQL или 10 000 файлов из Cloud Storage может быть выполнена быстрее с помощью 10 задач, обрабатывающих по 1000 записей или файлов каждая параллельно.
Использование заданий Cloud Run — это двухэтапный процесс:
- Создание задания: Этот параметр включает в себя всю необходимую конфигурацию для выполнения задания, такую как образ контейнера, регион, переменные среды.
- Запуск задания: это создаст новый запуск задания. При желании вы можете настроить выполнение задания по расписанию с помощью Cloud Scheduler.
В этом практическом занятии вы сначала изучите приложение Node.js для создания скриншотов веб-страниц и их сохранения в Cloud Storage. Затем вы создадите образ контейнера для приложения, запустите его в заданиях Cloud Run, обновите задание для обработки большего количества веб-страниц и запустите задание по расписанию с помощью Cloud Scheduler.
Что вы узнаете
- Как использовать приложение для создания скриншотов веб-страниц.
- Как создать образ контейнера для приложения.
- Как создать задание Cloud Run для приложения.
- Как запустить приложение в качестве задания Cloud Run.
- Как обновить задание.
- Как запланировать выполнение задания с помощью Cloud Scheduler.
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 — среду командной строки, работающую в облаке.
В консоли Google Cloud нажмите на значок Cloud Shell на панели инструментов в правом верхнем углу:

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

Эта виртуальная машина содержит все необходимые инструменты разработки. Она предоставляет постоянный домашний каталог объемом 5 ГБ и работает в облаке Google, что значительно повышает производительность сети и аутентификацию. Вся работа в этом практическом задании может выполняться в браузере. Вам не нужно ничего устанавливать.
Настройте gcloud
В Cloud Shell укажите идентификатор проекта и регион, в который вы хотите развернуть задание Cloud Run. Сохраните их как переменные PROJECT_ID и REGION . В будущем вы сможете выбрать регион из одного из местоположений Cloud Run .
PROJECT_ID=[YOUR-PROJECT-ID] REGION=us-central1 gcloud config set core/project $PROJECT_ID
Включить API
Включите все необходимые службы:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ run.googleapis.com
3. Получите код
Сначала вы изучаете приложение Node.js для создания скриншотов веб-страниц и сохранения их в Cloud Storage. Затем вы создаете образ контейнера для приложения и запускаете его в качестве задания в Cloud Run.
В оболочке Cloud Shell выполните следующую команду, чтобы клонировать код приложения из этого репозитория:
git clone https://github.com/GoogleCloudPlatform/jobs-demos.git
Перейдите в каталог, содержащий приложение:
cd jobs-demos/screenshot
Вы должны увидеть следующую структуру файла:
screenshot | ├── Dockerfile ├── README.md ├── screenshot.js ├── package.json
Вот краткое описание каждого файла:
-
screenshot.jsсодержит код Node.js для приложения. -
package.jsonопределены зависимости библиотек. -
Dockerfileопределяет образ контейнера.
4. Изучите код
Для изучения кода воспользуйтесь встроенным текстовым редактором, нажав кнопку « Open Editor в верхней части окна Cloud Shell.

Вот краткое описание каждого файла.
screenshot.js
Для начала screenshot.js добавляет в качестве зависимостей Puppeteer и Cloud Storage. Puppeteer — это библиотека Node.js, используемая для создания скриншотов веб-страниц:
const puppeteer = require('puppeteer');
const {Storage} = require('@google-cloud/storage');
Существует функция initBrowser для инициализации Puppeteer и функция takeScreenshot для создания скриншотов заданного URL-адреса:
async function initBrowser() {
console.log('Initializing browser');
return await puppeteer.launch();
}
async function takeScreenshot(browser, url) {
const page = await browser.newPage();
console.log(`Navigating to ${url}`);
await page.goto(url);
console.log(`Taking a screenshot of ${url}`);
return await page.screenshot({
fullPage: true
});
}
Далее, есть функция для получения или создания корзины Cloud Storage, а также функция для загрузки скриншота веб-страницы в корзину:
async function createStorageBucketIfMissing(storage, bucketName) {
console.log(`Checking for Cloud Storage bucket '${bucketName}' and creating if not found`);
const bucket = storage.bucket(bucketName);
const [exists] = await bucket.exists();
if (exists) {
// Bucket exists, nothing to do here
return bucket;
}
// Create bucket
const [createdBucket] = await storage.createBucket(bucketName);
console.log(`Created Cloud Storage bucket '${createdBucket.name}'`);
return createdBucket;
}
async function uploadImage(bucket, taskIndex, imageBuffer) {
// Create filename using the current time and task index
const date = new Date();
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
const filename = `${date.toISOString()}-task${taskIndex}.png`;
console.log(`Uploading screenshot as '${filename}'`)
await bucket.file(filename).save(imageBuffer);
}
Наконец, main функция является точкой входа:
async function main(urls) {
console.log(`Passed in urls: ${urls}`);
const taskIndex = process.env.CLOUD_RUN_TASK_INDEX || 0;
const url = urls[taskIndex];
if (!url) {
throw new Error(`No url found for task ${taskIndex}. Ensure at least ${parseInt(taskIndex, 10) + 1} url(s) have been specified as command args.`);
}
const bucketName = process.env.BUCKET_NAME;
if (!bucketName) {
throw new Error('No bucket name specified. Set the BUCKET_NAME env var to specify which Cloud Storage bucket the screenshot will be uploaded to.');
}
const browser = await initBrowser();
const imageBuffer = await takeScreenshot(browser, url).catch(async err => {
// Make sure to close the browser if we hit an error.
await browser.close();
throw err;
});
await browser.close();
console.log('Initializing Cloud Storage client')
const storage = new Storage();
const bucket = await createStorageBucketIfMissing(storage, bucketName);
await uploadImage(bucket, taskIndex, imageBuffer);
console.log('Upload complete!');
}
main(process.argv.slice(2)).catch(err => {
console.error(JSON.stringify({severity: 'ERROR', message: err.message}));
process.exit(1);
});
Обратите внимание на следующие особенности main метода:
- URL-адреса передаются в качестве аргументов.
- Имя корзины передается в виде определяемой пользователем переменной среды
BUCKET_NAME. Имя корзины должно быть уникальным во всех средах Google Cloud. - В заданиях Cloud Run передается переменная среды
CLOUD_RUN_TASK_INDEX. Задания Cloud Run могут запускать несколько копий приложения в качестве отдельных задач.CLOUD_RUN_TASK_INDEXпредставляет собой индекс запущенной задачи. По умолчанию он равен нулю, если код выполняется вне заданий Cloud Run. Когда приложение запускается в виде нескольких задач, каждая задача/контейнер получает URL-адрес, за который она отвечает, делает снимок экрана и сохраняет изображение в хранилище.
package.json
Файл package.json определяет приложение и указывает зависимости для Cloud Storage и Puppeteer:
{
"name": "screenshot",
"version": "1.0.0",
"description": "Create a job to capture screenshots",
"main": "screenshot.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Google LLC",
"license": "Apache-2.0",
"dependencies": {
"@google-cloud/storage": "^5.18.2",
"puppeteer": "^13.5.1"
}
}
Dockerfile
Dockerfile определяется образ контейнера для приложения со всеми необходимыми библиотеками и зависимостями:
FROM ghcr.io/puppeteer/puppeteer:16.1.0 COPY package*.json ./ RUN npm ci --omit=dev COPY . . ENTRYPOINT ["node", "screenshot.js"]
5. Развернуть задание
Перед созданием задания необходимо создать учетную запись службы, которая будет использоваться для его выполнения.
gcloud iam service-accounts create screenshot-sa --display-name="Screenshot app service account"
Предоставьте учетной записи службы роль storage.admin , чтобы она могла создавать корзины и объекты.
gcloud projects add-iam-policy-binding $PROJECT_ID \ --role roles/storage.admin \ --member serviceAccount:screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Теперь вы готовы развернуть задание Cloud Run, включающее необходимую для его выполнения конфигурацию.
gcloud beta run jobs deploy screenshot \ --source=. \ --args="https://example.com" \ --args="https://cloud.google.com" \ --tasks=2 \ --task-timeout=5m \ --region=$REGION \ --set-env-vars=BUCKET_NAME=screenshot-$PROJECT_ID-$RANDOM \ --service-account=screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Этот метод использует развертывание на основе источника и создает задание Cloud Run без его выполнения.
Обратите внимание, как веб-страницы передаются в качестве аргументов. Имя хранилища для сохранения скриншотов передается в виде переменной окружения.
Вы можете запускать несколько копий контейнера параллельно, указав количество задач для выполнения с помощью флага --tasks . Каждая задача представляет собой одну работающую копию контейнера. Использование нескольких задач полезно, если каждая задача может независимо обрабатывать подмножество ваших данных. Для этого каждая задача знает свой индекс, который хранится в переменной среды CLOUD_RUN_TASK_INDEX . Ваш код отвечает за определение того, какая задача обрабатывает какое подмножество данных. Обратите внимание на --tasks=2 в этом примере. Это гарантирует запуск двух контейнеров для двух URL-адресов, которые мы хотим обработать.
Каждая задача может выполняться до 24 часов . Вы можете уменьшить это время ожидания, используя флаг --task-timeout , как мы сделали в этом примере. Для успешного завершения задания все задачи должны быть успешно выполнены. По умолчанию задачи, завершившиеся с ошибкой, не повторяются. Вы можете настроить повторные попытки для задач, завершившихся с ошибкой. Если какая-либо задача превысит количество повторных попыток, все задание завершится с ошибкой.
По умолчанию ваша задача будет выполняться с максимально возможным количеством параллельных задач. Это количество будет равно числу задач для вашей задачи, но не более 100. Возможно, вам потребуется уменьшить уровень параллелизма для задач, которые обращаются к бэкэнду с ограниченной масштабируемостью. Например, для базы данных, поддерживающей ограниченное количество активных соединений. Вы можете уменьшить уровень параллелизма с помощью флага --parallelism .
6. Выполните задание
Перед запуском задания проверьте его статус, чтобы убедиться, что оно создано:
gcloud run jobs list ✔ JOB: screenshot REGION: us-central LAST RUN AT: CREATED: 2022-02-22 12:20:50 UTC
Запустите задание с помощью следующей команды:
gcloud run jobs execute screenshot --region=$REGION
Это запускает задание. Вы можете просмотреть список текущих и прошлых выполнений:
gcloud run jobs executions list --job screenshot --region=$REGION ... JOB: screenshot EXECUTION: screenshot-znkmm REGION: $REGION RUNNING: 1 COMPLETE: 1 / 2 CREATED: 2022-02-22 12:40:42 UTC
Опишите ход выполнения. Вы должны увидеть зеленую галочку и сообщение tasks completed successfully :
gcloud run jobs executions describe screenshot-znkmm --region=$REGION ✔ Execution screenshot-znkmm in region $REGION 2 tasks completed successfully Image: $REGION-docker.pkg.dev/$PROJECT_ID/containers/screenshot at 311b20d9... Tasks: 2 Args: https://example.com https://cloud.google.com Memory: 1Gi CPU: 1000m Task Timeout: 3600s Parallelism: 2 Service account: 11111111-compute@developer.gserviceaccount.com Env vars: BUCKET_NAME screenshot-$PROJECT_ID-$RANDOM
Вы также можете проверить статус заданий Cloud Run на странице Cloud Console:

Если вы проверите содержимое хранилища Cloud Storage, вы увидите два созданных файла скриншотов:

Иногда может потребоваться остановить выполнение до его завершения — например, если вы поняли, что нужно запустить задачу с другими параметрами, или если в коде возникла ошибка, и вы не хотите тратить лишнее вычислительное время.
Чтобы остановить выполнение задания, необходимо удалить это выполнение:
gcloud run jobs executions delete screenshot-znkmm --region=$REGION
7. Обновить задание
Новые версии вашего контейнера не автоматически подхватываются заданиями Cloud Run при следующем запуске. Если вы изменяете код задания, вам необходимо пересобрать контейнер и обновить задание. Использование образов с тегами поможет вам определить, какая версия образа используется в данный момент.
Аналогично, вам также потребуется обновить задание, если вы хотите изменить некоторые переменные конфигурации. Последующие выполнения задания будут использовать новый контейнер и параметры конфигурации.
Обновите задание и измените количество страниц, с которых приложение делает снимки экрана, в параметре --args . Также обновите параметр --tasks , указав количество страниц.
gcloud run jobs update screenshot \ --args="https://www.pinterest.com" \ --args="https://www.apartmenttherapy.com" \ --args="https://www.google.com" \ --region=$REGION \ --tasks=3
Запустите задание еще раз. На этот раз передайте флаг --wait , чтобы дождаться завершения выполнения:
gcloud run jobs execute screenshot --region=$REGION --wait
Через несколько секунд вы увидите, что в корзину добавлены еще 3 скриншота:

8. Составьте расписание работы
До сих пор вы запускали задания вручную. В реальных условиях вам, вероятно, потребуется запускать задания в ответ на событие или по расписанию. Давайте посмотрим, как запустить задание по созданию скриншотов по расписанию с помощью Cloud Scheduler.
Во-первых, убедитесь, что API Cloud Scheduler включен:
gcloud services enable cloudscheduler.googleapis.com
Перейдите на страницу с подробной информацией о заданиях Cloud Run и нажмите на раздел Triggers :

Нажмите кнопку Add Scheduler Trigger :

Справа откроется панель. Создайте задание планировщика, которое будет запускаться каждый день в 9:00 с указанной конфигурацией, и выберите Continue :

На следующей странице выберите учетную запись вычислительной службы по умолчанию и нажмите Create :

Теперь вы должны увидеть созданный новый триггер Cloud Scheduler:

Нажмите View Details , чтобы перейти на страницу «Планировщик облачных задач».
Вы можете подождать до 9 утра, пока запустится планировщик, или же запустить облачный планировщик вручную, выбрав Force Run :

Через несколько секунд вы увидите сообщение об успешном выполнении задания Cloud Scheduler:

Вы также должны увидеть еще 3 скриншота, добавленных вызовом из Cloud Scheduler:

9. Поздравляем!
Поздравляем, вы завершили практическое занятие!
Уборка (необязательно)
Чтобы избежать дополнительных расходов, целесообразно проводить очистку ресурсов.
Если проект вам не нужен, вы можете просто удалить его:
gcloud projects delete $PROJECT_ID
Если вам нужен проект, вы можете удалять ресурсы по отдельности.
Удалите исходный код:
rm -rf ~/jobs-demos/
Удалите репозиторий реестра артефактов:
gcloud artifacts repositories delete containers --location=$REGION
Удалите учетную запись службы:
gcloud iam service-accounts delete screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Удалите задание Cloud Run:
gcloud run jobs delete screenshot --region=$REGION
Удалите задание планировщика облачных задач:
gcloud scheduler jobs delete screenshot-scheduler-trigger --location=$REGION
Удалите сегмент облачного хранилища:
gcloud storage rm --recursive gs://screenshot-$PROJECT_ID
Что мы рассмотрели
- Как использовать приложение для создания скриншотов веб-страниц.
- Как создать образ контейнера для приложения.
- Как создать задание Cloud Run для приложения.
- Как запустить приложение в качестве задания Cloud Run.
- Как обновить задание.
- Как запланировать выполнение задания с помощью Cloud Scheduler.