Развертывание отказоустойчивой архитектуры с прерываемыми виртуальными машинами
В этом руководстве вы создадите функцию Yandex Cloud Functions на языке Node.js, которая будет вызываться по расписанию и запускать прерываемую ВМ Yandex Compute Cloud, если ВМ остановлена.
Описанная в руководстве архитектура подходит для ВМ с некритичной нагрузкой. Архитектура позволяет использовать ценовое преимущество тарифов на прерываемые ВМ и при этом в случае отключения ВМ обеспечивать время простоя не более одной минуты.
Чтобы развернуть отказоустойчивую архитектуру с прерываемой ВМ:
- Подготовьте окружение.
- Подготовьте ZIP-архив с кодом функции.
- Создайте функцию.
- Создайте триггер.
- Протестируйте работу функции.
Если созданные ресурсы вам больше не нужны, удалите их.
Перед началом работы
Зарегистрируйтесь в Yandex Cloud и создайте платежный аккаунт:
- Перейдите в консоль управления
, затем войдите в Yandex Cloud или зарегистрируйтесь. - На странице Yandex Cloud Billing
убедитесь, что у вас подключен платежный аккаунт, и он находится в статусеACTIVEилиTRIAL_ACTIVE. Если платежного аккаунта нет, создайте его и привяжите к нему облако.
Если у вас есть активный платежный аккаунт, вы можете создать или выбрать каталог, в котором будет работать ваша инфраструктура, на странице облака
Подробнее об облаках и каталогах.
Необходимые платные ресурсы
В стоимость поддержки инфраструктуры входят:
- Плата за вычислительные ресурсы ВМ (см. тарифы Compute Cloud).
- Плата за диски ВМ (см. тарифы Compute Cloud).
- Плата за использование динамического или статического публичного IP-адреса (см. тарифы Yandex Virtual Private Cloud).
- Плата за хранение секрета и запросы к нему (см. тарифы Yandex Lockbox).
- Плата за количество вызовов функции, вычислительные ресурсы, выделенные для выполнения функции, и исходящий трафик (см. тарифы Cloud Functions).
- Плата за запись и хранение данных в лог-группе (см. тарифы Yandex Cloud Logging), если вы используете сервис Cloud Logging.
Подготовьте окружение
- Создайте сервисный аккаунт, от имени которого будет вызываться функция, и назначьте ему роли
functions.functionInvokerиlockbox.payloadViewer. - Создайте прерываемую ВМ.
Создайте секрет
Создайте секрет Yandex Lockbox для хранения OAuth-токена.
Примечание
Используйте OAuth-токен, если у вас нет возможности автоматически запрашивать IAM-токен. IAM-токен обновляется чаще, поэтому более безопасен.
- В консоли управления
выберите каталог, в котором хотите создать секрет. - В списке сервисов выберите Lockbox.
- Нажмите кнопку Создать секрет.
- В поле Имя введите имя секрета, например
oauth-token. - В поле Тип секрета выберите
Пользовательский. - В блоке Версия:
- В поле Ключ введите
key_token. - В поле Значение введите значение OAuth-токена
, необходимого для авторизации функции.
- В поле Ключ введите
- Нажмите кнопку Создать.
Если у вас еще нет интерфейса командной строки Yandex Cloud (CLI), установите и инициализируйте его.
По умолчанию используется каталог, указанный при создании профиля CLI. Чтобы изменить каталог по умолчанию, используйте команду yc config set folder-id <идентификатор_каталога>. Также для любой команды вы можете указать другой каталог с помощью параметров --folder-name или --folder-id.
Чтобы создать секрет, выполните команду:
yc lockbox secret create --name oauth-token \
--payload "[{'key': 'key_token', 'text_value': '<OAuth-токен>'}]"
Где text_value — значение OAuth-токена
Результат:
done (1s)
id: e6qu9ik259lb********
folder_id: b1g9d2k0itu4********
...
status: ACTIVE
payload_entry_keys:
- key_token
-
Опишите в конфигурационном файле параметры секрета:
resource "yandex_lockbox_secret" "oauth-token" { name = "oauth-token" } resource "yandex_lockbox_secret_version" "my_version" { secret_id = yandex_lockbox_secret.my_secret.id entries { key = "key_token" text_value = "<OAuth-токен>" } }Где:
name— имя секрета.key— ключ секрета.text_value— значение OAuth-токена , необходимого для авторизации функции.
Примечание
Рекомендуется использовать ресурс
yandex_lockbox_secret_version_hashed, он хранит в состоянии Terraform значения в хешированном виде. Поддержка ресурсаyandex_lockbox_secret_versionостается.Более подробную информацию о ресурсе
yandex_lockbox_secret_version_hashedсм. в документации провайдера.Более подробную информацию о параметрах используемых ресурсов в Terraform см. в документации провайдера:
-
Проверьте корректность конфигурационных файлов.
-
В командной строке перейдите в папку, где вы создали конфигурационный файл.
-
Выполните проверку с помощью команды:
terraform plan
Если конфигурация описана верно, в терминале отобразится список создаваемых ресурсов и их параметров. Если в конфигурации есть ошибки, Terraform на них укажет.
-
-
Разверните облачные ресурсы.
-
Если в конфигурации нет ошибок, выполните команду:
terraform apply -
Подтвердите создание секрета: введите в терминал слово
yesи нажмите Enter.
-
Чтобы создать секрет, воспользуйтесь методом REST API create для ресурса Secret или вызовом gRPC API SecretService/Create.
Подготовьте ZIP-архив с кодом функции
-
Сохраните следующий код в файл с названием
index.js:import { serviceClients, Session, cloudApi } from '@yandex-cloud/nodejs-sdk'; const { compute: { instance_service: { ListInstancesRequest, GetInstanceRequest, StartInstanceRequest, }, instance: { IpVersion, }, }, } = cloudApi; const FOLDER_ID = process.env.FOLDER_ID; const INSTANCE_ID = process.env.INSTANCE_ID; const OAUTHTOKEN = process.env.OAUTHTOKEN; export const handler = async function (event, context) { const session = new Session({ oauthToken: OAUTHTOKEN }); const instanceClient = session.client(serviceClients.InstanceServiceClient); const list = await instanceClient.list(ListInstancesRequest.fromPartial({ folderId: FOLDER_ID, })); const state = await instanceClient.get(GetInstanceRequest.fromPartial({ instanceId: INSTANCE_ID, })); var status = state.status if (status == 4){ const startcommand = await instanceClient.start(StartInstanceRequest.fromPartial({ instanceId: INSTANCE_ID, })); } return { statusCode: 200, body: { status } }; }; -
Сохраните следующий код в файл с названием
package.json:{ "name": "my-awesome-package", "version": "1.0.0", "type": "module", "dependencies": { "@yandex-cloud/nodejs-sdk": "latest" } } -
Добавьте файлы
index.jsиpackage.jsonв ZIP-архивfunction-js.zip.
Создайте функцию
- В консоли управления
перейдите в каталог, в котором хотите создать функцию. - В списке сервисов выберите Cloud Functions.
- Создайте функцию:
- Нажмите кнопку Создать функцию.
- В открывшемся окне введите имя функции
function-restart-vms. - Нажмите кнопку Создать.
- Создайте версию функции:
- Выберите среду выполнения
nodejs18, отключите опцию Добавить файлы с примерами кода и нажмите кнопку Продолжить. - В поле Способ выберите
ZIP-архив. - В поле Файл нажмите кнопку Прикрепить файл и выберите архив
function-js.zip, который создали ранее. - Укажите точку входа
index.handler. - В блоке Параметры укажите:
- Таймаут —
3. - Память —
128 МБ. - Сервисный аккаунт — выберите созданный ранее сервисный аккаунт с правами на вызов функции.
- Переменные окружения:
FOLDER_ID— идентификатор каталога, в котором вы хотите запускать остановленные ВМ.INSTANCE_ID— идентификатор ВМ, которую вы хотите запускать при прерывании.
- Секреты Lockbox:
- В поле Переменная окружения укажите
OAUTHTOKEN. - В поле Идентификатор секрета выберите созданный ранее секрет
oauth-token. - В поле Идентификатор версии выберите версию секрета.
- В поле Ключ секрета выберите имя ключа
key_token.
- В поле Переменная окружения укажите
- Если вы не хотите сохранять логи и платить за использование сервиса Cloud Logging, в блоке Логирование, в поле Назначение, выберите
Не задано, чтобы отключить логирование.
- Таймаут —
- Нажмите кнопку Сохранить изменения.
- Выберите среду выполнения
-
Создайте функцию
function-restart-vms:yc serverless function create --name function-restart-vmsРезультат:
id: d4ebrmenrr7l******** folder_id: b1g9d2k0itu4******** created_at: "2023-10-28T17:26:58.200799757Z" name: function-restart-vms http_invoke_url: https://functions.yandexcloud.net/d4ebrmenrr7l******** status: ACTIVE -
Создайте версию функции
function-restart-vms:yc serverless function version create \ --function-name function-restart-vms \ --memory=128m \ --execution-timeout=3s \ --runtime=nodejs18 \ --entrypoint=index.handler \ --service-account-id=<идентификатор_сервисного_аккаунта> \ --environment FOLDER_ID=<идентификатор_каталога>,INSTANCE_ID=<идентификатор_ВМ> \ --secret name=oauth-token,version-id=<идентификатор_версии_секрета>,key=key_token,environment-variable=OAUTHTOKEN \ --source-path=./function-js.zip \ --no-loggingГде:
--function-name— имя функции, версия которой создается.--memory— объем RAM.--execution-timeout— максимальное время выполнения функции до таймаута.--runtime— среда выполнения.--entrypoint— точка входа.--service-account-id— идентификатор сервисного аккаунта с правами на вызов функции.--environment— переменные окружения:FOLDER_ID— идентификатор каталога, в котором вы хотите запускать остановленные ВМ.INSTANCE_ID— идентификатор ВМ, которую вы хотите запускать при прерывании.
--secret— данные секрета Yandex Lockbox:name— имя секрета.version-id— идентификатор версии секрета.key— ключ секрета.environment-variable— переменная окружения, в которой будет храниться секрет.
--source-path— путь к созданному ранее ZIP-архивуfunction-js.zip.- (опционально)
--no-logging— укажите этот флаг, если вы не хотите сохранять логи и платить за использование сервиса Cloud Logging.
Результат:
done (16s) id: d4etv5f4sjet******** function_id: d4ebrmenrr7l******** ... log_options: disabled: true folder_id: b1g9d2k0itu4********
Если у вас еще нет Terraform, установите его и настройте провайдер Yandex Cloud.
-
Опишите в конфигурационном файле параметры функции
function-restart-vmsи ее версии:resource "yandex_function" "function-restart-vms" { name = "function-restart-vms" user_hash = "first function" runtime = "nodejs18" entrypoint = "index.handler" memory = "128" execution_timeout = "3" service_account_id = "<идентификатор_сервисного_аккаунта>" folder_id = "<идентификатор_каталога>" environment = { FOLDER_ID = "<идентификатор_каталога>" INSTANCE_ID = "<идентификатор_ВМ>" } secrets { id = "<идентификатор_секрета>" version_id = "<идентификатор_версии_секрета>" key = "key_token" environment_variable = "OAUTHTOKEN" } content { zip_filename = "./function-js.zip" } }Где:
name— имя функции.user_hash— произвольная строка, определяющая версию функции.runtime— среда выполнения функции.entrypoint— точка входа.memory— объем памяти в мегабайтах, отведенный для выполнения функции.execution_timeout— таймаут выполнения функции.service_account_id— идентификатор сервисного аккаунта с правами на вызов функции.folder_id— идентификатор каталога, в котором вы создаете функцию.environment— переменные окружения:FOLDER_ID— идентификатор каталога, в котором вы хотите запускать остановленные ВМ.INSTANCE_ID— идентификатор ВМ, которую вы хотите запускать при прерывании.
secrets— данные секрета Yandex Lockbox:id— идентификатор секрета.version_id— идентификатор версии секрета.key— ключ секрета.environment_variable— переменная окружения, в которой будет храниться секрет.
zip_filename— путь к созданному ранее ZIP-архивуfunction-js.zip.
Более подробную информацию о параметрах ресурса
yandex_functionсм. в документации провайдера. -
Проверьте корректность конфигурационных файлов.
-
В командной строке перейдите в папку, где вы создали конфигурационный файл.
-
Выполните проверку с помощью команды:
terraform plan
Если конфигурация описана верно, в терминале отобразится список создаваемых ресурсов и их параметров. Если в конфигурации есть ошибки, Terraform на них укажет.
-
-
Разверните облачные ресурсы.
-
Если в конфигурации нет ошибок, выполните команду:
terraform apply -
Подтвердите создание функции: введите в терминал слово
yesи нажмите Enter.После этого в указанном каталоге будет создана функция
function-restart-vms. Проверить появление ресурсов и их настройки можно в консоли управления или с помощью команды CLI:yc serverless function get function-restart-vmsРезультат:
id: d4ees84gsdsd******** folder_id: b1g9d2k0itu4******** created_at: "2023-08-09T10:11:40.740Z" name: function-restart-vms log_group_id: ckgjitlio5aj******** http_invoke_url: https://functions.yandexcloud.net/d4ees84gsdsd******** status: ACTIVE
-
Чтобы создать функцию, воспользуйтесь методом create для ресурса Function или вызовом gRPC API FunctionService/Create.
Чтобы создать версию функцию, воспользуйтесь методом createVersion для ресурса Function или вызовом gRPC API FunctionService/CreateVersion.
Создайте триггер
Примечание
Триггер начинает работать в течение 5 минут после создания.
- В консоли управления
перейдите в каталог, в котором хотите создать триггер. - В списке сервисов выберите Cloud Functions.
- На панели слева выберите
Триггеры. - Нажмите кнопку Создать триггер.
- В блоке Базовые параметры:
- Введите имя триггера —
timer. - В поле Тип выберите
Таймер. - В поле Запускаемый ресурс выберите
Функция.
- Введите имя триггера —
- В блоке Настройки таймера введите
* * ? * * *или выберитеКаждую минуту. - В блоке Настройки функции выберите функцию
function-restart-vmsи укажите:- Тег версии функции —
$latest. - Сервисный аккаунт с правами на вызов функции, который создали ранее.
- Тег версии функции —
- Нажмите кнопку Создать триггер.
Чтобы создать триггер, который вызывает функцию, выполните команду:
yc serverless trigger create timer \
--name timer \
--cron-expression '* * ? * * *' \
--invoke-function-name function-restart-vms \
--invoke-function-service-account-id <идентификатор_сервисного_аккаунта>
Где:
--name— имя триггера.--cron-expression— расписание вызова функции в формате cron-выражения.--invoke-function-name— имя вызываемой функции.--invoke-function-service-account-id— идентификатор сервисного аккаунта с правами на вызов функции.
Результат:
id: a1sv54ekvknb********
folder_id: b1g9d2k0itu4********
created_at: "2023-08-08T19:46:22.860681482Z"
...
function_tag: $latest
service_account_id: ajeh2dukocg3********
status: ACTIVE
Чтобы создать триггер, который запускает функцию:
-
Опишите в конфигурационном файле параметры триггера
timer:resource "yandex_function_trigger" "timer" { name = "timer" timer { cron_expression = "* * ? * * *" } function { id = "<идентификатор_функции>" service_account_id = "<идентификатор_сервисного_аккаунта>" } }Где:
name— имя триггера.cron_expression— расписание вызова функции в формате cron-выражения.id— идентификатор функции, которую будет запускать триггер.service_account_id— идентификатор сервисного аккаунта с правами на вызов функции.
Более подробную информацию о параметрах ресурсов в Terraform см. в документации провайдера.
-
Проверьте корректность конфигурационных файлов.
-
В командной строке перейдите в папку, где вы создали конфигурационный файл.
-
Выполните проверку с помощью команды:
terraform plan
Если конфигурация описана верно, в терминале отобразится список создаваемых ресурсов и их параметров. Если в конфигурации есть ошибки, Terraform на них укажет.
-
-
Разверните облачные ресурсы.
-
Если в конфигурации нет ошибок, выполните команду:
terraform apply -
Подтвердите создание ресурсов: введите в терминал слово
yesи нажмите Enter.После этого в указанном каталоге будет создан триггер
timer. Проверить появление ресурсов и их настройки можно в консоли управления или с помощью команды CLI:yc serverless trigger get timerРезультат:
id: a1s4bvdvmod0******** folder_id: b1g9d2k0itu4******** created_at: "2023-08-09T10:19:12.356Z" ... function_id: d4ebrmenrr7l******** service_account_id: ajeh2dukocg3******** status: ACTIVE
-
Чтобы создать таймер, воспользуйтесь методом REST API create для ресурса Trigger или вызовом gRPC API TriggerService/Create.
Протестируйте работу функции
- В консоли управления
перейдите в каталог, в котором создана ваша прерываемая ВМ. - В списке сервисов выберите Compute Cloud.
- На панели слева выберите Виртуальные машины.
- Напротив имени нужной ВМ нажмите значок
и выберите Остановить. - В открывшемся окне нажмите кнопку Остановить. Статус ВМ изменится на
Stopped. - Проверьте состояние ВМ через 1 минуту или более. Статус ВМ должен измениться на
Running.
Как удалить созданные ресурсы
Чтобы перестать платить за созданные ресурсы:
- Удалите триггер.
- Удалите функцию.
- Удалите секрет.
- Удалите ВМ.
- Если вы записывали логи в лог-группу, удалите ее.