Начало работы с заданиями Cloud Run

1. Введение

1965fab24c502bd5.png

Обзор

Сервисы 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 — это двухэтапный процесс:

  1. Создание задания: Этот параметр включает в себя всю необходимую конфигурацию для выполнения задания, такую ​​как образ контейнера, регион, переменные среды.
  2. Запуск задания: это создаст новый запуск задания. При желании вы можете настроить выполнение задания по расписанию с помощью Cloud Scheduler.

В этом практическом занятии вы сначала изучите приложение Node.js для создания скриншотов веб-страниц и их сохранения в Cloud Storage. Затем вы создадите образ контейнера для приложения, запустите его в заданиях Cloud Run, обновите задание для обработки большего количества веб-страниц и запустите задание по расписанию с помощью Cloud Scheduler.

Что вы узнаете

  • Как использовать приложение для создания скриншотов веб-страниц.
  • Как создать образ контейнера для приложения.
  • Как создать задание Cloud Run для приложения.
  • Как запустить приложение в качестве задания Cloud Run.
  • Как обновить задание.
  • Как запланировать выполнение задания с помощью Cloud Scheduler.

2. Настройка и требования

Настройка среды для самостоятельного обучения

  1. Войдите в консоль Google Cloud и создайте новый проект или используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

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

Запустить Cloud Shell

Хотя Google Cloud можно управлять удаленно с ноутбука, в этом практическом занятии вы будете использовать Google Cloud Shell — среду командной строки, работающую в облаке.

В консоли Google Cloud нажмите на значок Cloud Shell на панели инструментов в правом верхнем углу:

Активировать Cloud Shell

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

Скриншот терминала Google 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.

15a2cdc9b7f6dfc6.png

Вот краткое описание каждого файла.

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:

1afde14d65f0d9ce.png

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

7c4d355f6f65106.png

Иногда может потребоваться остановить выполнение до его завершения — например, если вы поняли, что нужно запустить задачу с другими параметрами, или если в коде возникла ошибка, и вы не хотите тратить лишнее вычислительное время.

Чтобы остановить выполнение задания, необходимо удалить это выполнение:

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 скриншота:

ed0cbe0b5a5f9144.png

8. Составьте расписание работы

До сих пор вы запускали задания вручную. В реальных условиях вам, вероятно, потребуется запускать задания в ответ на событие или по расписанию. Давайте посмотрим, как запустить задание по созданию скриншотов по расписанию с помощью Cloud Scheduler.

Во-первых, убедитесь, что API Cloud Scheduler включен:

gcloud services enable cloudscheduler.googleapis.com

Перейдите на страницу с подробной информацией о заданиях Cloud Run и нажмите на раздел Triggers :

3ae456368905472f.png

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

48cbba777f75e1eb.png

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

81fd098be0db216.png

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

fe479501dfb91f9f.png

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

5a7bc6d96b970b92.png

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

Вы можете подождать до 9 утра, пока запустится планировщик, или же запустить облачный планировщик вручную, выбрав Force Run :

959525f2c8041a6a.png

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

d64e03fc84d61145.png

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

56398a0e827de8b0.png

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.