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

1. Введение

1965fab24c502bd5.png

Обзор

Службы Cloud Run хорошо подходят для контейнеров, которые работают неопределенно долго и прослушивают HTTP-запросы, тогда как задания Cloud Run лучше подходят для контейнеров, которые выполняются до завершения (в настоящее время до 24 часов ) и не обслуживают запросы. Например, обработка записей из базы данных, обработка списка файлов из корзины Cloud Storage или длительная операция, такая как вычисление числа Pi, будут работать хорошо, если они будут реализованы как задание 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 Run, обновляете задание для обработки большего количества веб-страниц и запускаете задание по расписанию с помощью Cloud Scheduler.

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

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

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

Самостоятельная настройка среды

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

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

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

Запустить Cloud Shell

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

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

84688aa223b1c3a2.png

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

320e18fedb7fbe0.png

Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Он предлагает постоянный домашний каталог объемом 5 ГБ и работает в Google Cloud, что значительно повышает производительность сети и аутентификацию. Всю работу в этой лаборатории кода можно выполнять в браузере. Вам не нужно ничего устанавливать.

Настройка 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 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

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

скриншот.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_TASK_INDEX передается заданиями Cloud Run. Задания Cloud Run могут запускать несколько копий приложения как уникальные задачи. CLOUD_RUN_TASK_INDEX представляет индекс выполняемой задачи. По умолчанию оно равно нулю, когда код выполняется вне заданий Cloud Run. Когда приложение запускается как несколько задач, каждая задача/контейнер выбирает URL-адрес, за который отвечает, делает снимок экрана и сохраняет изображение в корзину.

пакет.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 определяет образ контейнера для приложения со всеми необходимыми библиотеками и зависимостями:

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 \
  --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

Вы также можете проверить страницу заданий 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

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

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

Удалите корзину Cloud Storage:

gcloud storage rm --recursive gs://screenshot-$PROJECT_ID

Что мы рассмотрели

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