Если нужно запустить сайт или веб-приложение в облаке, то привычным для многих способом будет аренда виртуальной машины с определённым объёмом памяти и параметрами CPU. Берём ресурсы чуть-чуть с запасом, чтобы приложение не тормозило и не теряло пользовательские запросы, и платим постоянный тариф за аренду мощностей провайдера. Но в таком случае всегда есть переплата за фактически неиспользуемую часть ресурсов, а часть ответственности за надёжность решения несёт сам пользователь.
Облачные решения сегодня предлагают несколько вариантов запуска контейнеров, и serverless-подход — один из них. Если разместить код приложения в Serverless Containers, облако само запустит нужный контейнер с вашим сервисом тогда, когда появится потребность в его вызове. Разница не только в тарификации по времени работы контейнера, но и в эластичности. Если нагрузка резко возрастёт, то сервис запустит дополнительные экземпляры контейнера. Но и здесь есть свои ограничения.
В этой статье покажем, какие есть способы запуска контейнеров в Yandex Cloud, и расскажем, как и когда лучше запускать контейнеры в Serverless Containers. Материал может пригодиться бэкенд-разработчикам, DevOps-инженерам и системным администраторам.
Итак, у нас есть контейнеры, которые мы хотим запустить в облаке. Кратко напомним, какие возможности есть у разных способов запуска.
Таким образом, Serverless Containers наиболее выгоден для проектов с плавающей нагрузкой, где не требуется высокий порог входа. Покажем особенности настройки на примере запуска готового контейнера.
Для нашего эксперимента возьмём docker-образ mongo-express, который развернёт административную панель над MongoDB. Он достаточно популярен (более ста миллионов скачиваний) и кроме того, удовлетворяет ограничениям Serverless Containers: не имеет своего состояния и служит довольно тонкой прослойкой для существующего кластера Mongo.
Перед запуском нужно подготовиться и установить интерфейс командной строки Yandex Cloud CLI: здесь инструкция для разных ОС.
Шаг 1. Заводим реестр в сервисе Container Registry Yandex Cloud и загружаем в него docker-образ с приложением. Serverless-контейнер разворачивается из образов, которые добавлены в Container Registry, поэтому начнём с создания реестра:
Получаем ID для обращения к созданному реестру:
Не забудем аутентифицироваться в Container Registry с помощью Docker Credential helper: cконфигурируем Docker
и проверим, что в конфигурационном файле /home/<user>/.docker/config.json появилась строка:
Нам необходимо загрузить в реестр образ mongo-express с Docker Hub. Для этого присвоим скачанному образу тег вида cr.yandex/<ID реестра>/<имя Docker-образа>:<тег>.
Отправим образ в реестр Container Registry.
Шаг 2. Создаём контейнер. Для этого можно воспользоваться консолью управления, CLI, Terraform или API.
В консоли просто выбираем каталог, в котором нужно создать контейнер, переходим в сервис Serverless Containers, нажимаем Создать контейнер, вводим имя и описание контейнера.
На этом шаге можно что-то настроить — например, увеличить память. Но пока аргументы и опции трогать не будем — в нашем случае они, скорее всего, не пригодятся.
Шаг 3. Создаём сервисные аккаунты для использования образа и работы с секретами, назначаем роли. Подробнее о работе с сервисными аккаунтами и особенностях назначения прав поговорим в следующий раз. А пока лишь отметим, что на этом шаге нам нужен сервисный аккаунт для использования образа из Container Registry, потому что по умолчанию он приватный.
В консоли управления на вкладке Сервисные аккаунты создадим новый аккаунт и присвоим ему уникальное имя.
Чтобы назначить сервисному аккаунту роль на текущий каталог, нажмём Добавить роль и выберем роль: serverless.containers.invoker и container-registry.images.puller на созданный нами реестр — они будут нужны для создания триггера, который запустит контейнер. Также создадим и добавим аккаунту роли, которые пригодятся на следующих шагах:
Назначить права доступа на секрет и ключ шифрования разным аккаунтам также поможет документация сервиса Yandex Lockbox.
Шаг 4. Настраиваем переменные окружения. В консоли управления для Serverless Containers выбираем наш контейнер, переходим на вкладку Редактор. В блоке Параметры образа укажем переменную окружения и нажмём Добавить.
В нашем случае указываем IP-адрес сервера MongoDB, над которым мы разворачиваем административную панель и порт через который приложение будет доступно.
В командной строке эти же действия мы будем делать через создание ревизии контейнера. Создавать новую ревизию необходимо при загрузке новой версии Docker-образа в Container Registry и при изменении настроек. Подробнее о других параметрах настройки рекомендуем почитать в документации.
Названия других необходимых переменных окружения можно взять из документации mongo-express на docker-hub.
Шаг 5. Настраиваем работу с секретами через сервис Yandex Lockbox. Для начала создаём секрет с credentials от MongoDB. Это можно сделать прямо из UI: на вкладке Редактор в блоке Параметры образа заполняем поле Секрет Yandex Lockbox.
Шаг 6. Поставим тайм-аут на работу контейнера. Рекомендуем взять значение с запасом, потому что мы не знаем, сколько времени могут занимать запросы к mongo-express. Например, 10 секунд.
В консоли управления этот параметр задаётся на вкладке Редактор для контейнера, всё в том же блоке Параметры образа.
Шаг 7. Создаём последнюю ревизию контейнера.
Работа по запуску контейнера закончена, теперь мы можем дать к нему публичный доступ и перейти по ссылке, чтобы увидеть административную панель, запущенную на техническом домене Serverless Containers. Здесь можно создавать таблицы, добавлять и удалять документы. А логи работы приложения будут записываться в сервис Yandex Cloud Logging.
Шаг 8. Настраиваем авторизацию через API Gateway. Мы протестировали работу приложения, теперь настроим работу через API-шлюз, ограничив к приложению доступ по IP-адресу. Для этого добавим возможность авторизации в приложении через интеграцию API Gateway с специальной функцией-авторайзером.
Пример спецификации для создания интеграции с авторизацией можно посмотреть здесь. В неё вам необходимо добавить интеграцию с созданным контейнером и указать корректные id контейнера, функции и сервисных аккаунтов.
В сервисе Serverless Containers не нужно платить за простой арендуемых мощностей, а оплачивается только время работы контейнеров, добавленных в сервис. Однако такой подход можно использовать не во всех приложениях, потому что Serverless Containers не хранит состояния контейнеров и сами контейнеры не работают в фоновом режиме.
Мы показали, как пошагово можно запустить в Serverless Containers контейнер — если есть готовый Docker-образ, это будет не сложно.
Облачные решения сегодня предлагают несколько вариантов запуска контейнеров, и serverless-подход — один из них. Если разместить код приложения в Serverless Containers, облако само запустит нужный контейнер с вашим сервисом тогда, когда появится потребность в его вызове. Разница не только в тарификации по времени работы контейнера, но и в эластичности. Если нагрузка резко возрастёт, то сервис запустит дополнительные экземпляры контейнера. Но и здесь есть свои ограничения.
В этой статье покажем, какие есть способы запуска контейнеров в Yandex Cloud, и расскажем, как и когда лучше запускать контейнеры в Serverless Containers. Материал может пригодиться бэкенд-разработчикам, DevOps-инженерам и системным администраторам.
Способы запуска контейнеров в Yandex Cloud
Итак, у нас есть контейнеры, которые мы хотим запустить в облаке. Кратко напомним, какие возможности есть у разных способов запуска.
-
Запуск контейнера в арендуемой виртуальной машине (ВМ). Это самый очевидный способ, и в нём нет никаких ограничений для запуска Docker-контейнеров — можно делать это вручную или с помощью инструмента для оркестрации контейнеров. Подойдёт тем, кому нужен контроль инфраструктуры и полная свобода выбора запускаемого ПО.
Главное ограничение — это уже упомянутое отсутствие эластичности по умолчанию: нужно заранее определить параметры ВМ, причём с запасом. Ещё одно ограничение связано с отказоустойчивостью — аренда только одной ВМ по умолчанию не может считаться отказоустойчивой. А с появлением трёх и более ВМ неизбежно возникают вопросы балансировки нагрузки, которые в IaaS нужно решать самому. Такой вариант подразумевает высокий порог входа: если в качестве оркестратора выбран Kubernetes, администрировать кластер k8s также нужно будет самостоятельно. -
Использование Managed Kubernetes. В этом сервисе уже можно в автоматическом режиме развертывать и масштабировать приложения на основе Kubernetes-спецификаций, а также управлять ими. При этом специалисты облака берут на себя обслуживание и обновление компонентов инфраструктуры кластера: не нужно думать о бэкапах, обновлениях, синхронизации данных в распределённой базе конфигураций etcd и так далее. С точки зрения масштабирования это более гибкий вариант: если нужно увеличить нагрузку, Autoscaler создаст новую виртуальную машину с учётом заданных в настройках лимитов и квот. И наоборот: если нагрузка на узлы недостаточная, число узлов в группе будет постепенно уменьшаться до указанного минимума. Также есть горизонтальное и вертикальное автомасштабирование подов.
Но при этом тарификация по-прежнему не близка к модели Pay as you go: клиент платит за работу ВМ, на которой развёрнут контейнер, а также отдельно за использование мастера кластера Kubernetes. Помимо сравнительно высокой стоимости ресурсов, у этого сервиса всё ещё остаётся довольно высокий порог входа: масштабирование и другие параметры необходимо настроить.
-
Запуск в Container Solution. В Marketplace есть готовый образ виртуальной машины, это позволяет быстро создать ВМ и запустить в ней Docker-контейнер или даже группу контейнеров. В этом случае можно работать с Docker-спецификациями и прописывать, какие образы и с какими параметрами будут запускаться на машине при старте Docker’a. Порог входа не такой высокий, как в случае Managed Kubernetes, но масштабирование и другие параметры всё же нужно будет реализовать самостоятельно.
В этом сервисе тоже тарифицируется арендованная ВМ, а если используются Docker-образы из сервиса Container Registry — будет тарифицироваться объём хранилища образов и исходящий трафик.
-
Serverless containers. Здесь клиент приносит Docker-контейнер, и когда приложение его вызывает, сервис в бессерверном режиме запускает контейнер самостоятельно. Это подходит для приложений, архитектура которых следует принципам событийно-ориентированного подхода.
Так как serverless предполагает, что время работы контейнера не должно превышать минуты, а в идеальном случае — секунды или доли секунд, необходимо как-то решать вопрос «слушающей» части приложения. Для этой цели отлично подходит API Gateway, который всегда готов принимать входящие запросы, чтобы по цепочке передать их дальше в контейнер для обработки. Для того чтобы ещё больше повысить надежность обработки запроса, в эту цепочку могут включить очередь сообщений. Тогда запрос не будет считаться выполненным, пока контейнер не вернёт сообщение об успешной обработке запроса обратно в очередь. Контейнеры могут запускаться по триггеру на события в других сервисах облака, например, при добавлении объекта в объектном хранилище.
Serverless Containers тарифицируется по модели Pay as You Go: клиент платит за вызовы контейнера и время использования CPU, RAM и сетевых ресурсов, пока контейнеры запущены, а также за хранение образа в Container Registry — если для работы используется этот реестр.
У сервиса есть свои ограничения:- Docker-контейнеры в Serverless Containers не работают в фоновом режиме, а только во время выполнения запроса.
- Отсутствует состояние контейнера: если трафика в контейнер нет, если события не наступают, то платформа «тушит» контейнер и его состояние исчезает из памяти. Причём она может делать это после каждого обращения к контейнеру, если между вызовами произошел довольно большой временной интервал.
- Бессерверные контейнеры не подходят для обслуживания произвольных сетевых протоколов. Сервис поддерживает обработку только HTTP-вызовов, событий в очередях и других сервисах Yandex Cloud. Но в нём не получится развернуть контейнер, обслуживающий, например, произвольный TCP-based протокол.
Таким образом, Serverless Containers наиболее выгоден для проектов с плавающей нагрузкой, где не требуется высокий порог входа. Покажем особенности настройки на примере запуска готового контейнера.
Запуск контейнера с помощью Serverless Containers
Для нашего эксперимента возьмём docker-образ mongo-express, который развернёт административную панель над MongoDB. Он достаточно популярен (более ста миллионов скачиваний) и кроме того, удовлетворяет ограничениям Serverless Containers: не имеет своего состояния и служит довольно тонкой прослойкой для существующего кластера Mongo.
Перед запуском нужно подготовиться и установить интерфейс командной строки Yandex Cloud CLI: здесь инструкция для разных ОС.
Шаг 1. Заводим реестр в сервисе Container Registry Yandex Cloud и загружаем в него docker-образ с приложением. Serverless-контейнер разворачивается из образов, которые добавлены в Container Registry, поэтому начнём с создания реестра:
yc container registry create --name my-first-registry
Получаем ID для обращения к созданному реестру:
..done
id: crpc9qeoft236r8tfalm
folder_id: b1g0itj57rbjk9thrinv
name: my-first-registry
status: ACTIVE
created_at: "2018-12-25T12:24:56.286Z"
Не забудем аутентифицироваться в Container Registry с помощью Docker Credential helper: cконфигурируем Docker
yc container registry configure-docker
и проверим, что в конфигурационном файле /home/<user>/.docker/config.json появилась строка:
"cr.yandex": "yc"
Нам необходимо загрузить в реестр образ mongo-express с Docker Hub. Для этого присвоим скачанному образу тег вида cr.yandex/<ID реестра>/<имя Docker-образа>:<тег>.
docker tag mongo-express \
cr.yandex/crpc9qeoft236r8tfalm/mongo-express:hello
Отправим образ в реестр Container Registry.
docker push cr.yandex/crpc9qeoft236r8tfalm/mongo-express:hello
Шаг 2. Создаём контейнер. Для этого можно воспользоваться консолью управления, CLI, Terraform или API.
В консоли просто выбираем каталог, в котором нужно создать контейнер, переходим в сервис Serverless Containers, нажимаем Создать контейнер, вводим имя и описание контейнера.
То же самое в командной строке
Здесь по умолчанию используется каталог, указанный в профиле CLI, но можно указать другой с помощью параметра --folder-name или --folder-id.
yc serverless container create --name <имя_контейнера>
Здесь по умолчанию используется каталог, указанный в профиле CLI, но можно указать другой с помощью параметра --folder-name или --folder-id.
На этом шаге можно что-то настроить — например, увеличить память. Но пока аргументы и опции трогать не будем — в нашем случае они, скорее всего, не пригодятся.
Шаг 3. Создаём сервисные аккаунты для использования образа и работы с секретами, назначаем роли. Подробнее о работе с сервисными аккаунтами и особенностях назначения прав поговорим в следующий раз. А пока лишь отметим, что на этом шаге нам нужен сервисный аккаунт для использования образа из Container Registry, потому что по умолчанию он приватный.
В консоли управления на вкладке Сервисные аккаунты создадим новый аккаунт и присвоим ему уникальное имя.
То же самое в командной строке
yc iam service-account create --name <имя аккаунта>
Чтобы назначить сервисному аккаунту роль на текущий каталог, нажмём Добавить роль и выберем роль: serverless.containers.invoker и container-registry.images.puller на созданный нами реестр — они будут нужны для создания триггера, который запустит контейнер. Также создадим и добавим аккаунту роли, которые пригодятся на следующих шагах:
- lockbox.payloadViewer для работы с секретами;
- kms.keys.encrypterDecrypter на ключ шифрования, если секрет создан с использованием ключа Yandex Key Management Service.
Назначение ролей на ресурсы в командной строке
yc resource-manager <категория_ресурса> add-access-binding <имя ресурса>|<идентификатор ресурса> \
--role <идентификатор_роли> \
--subject serviceAccount:<идентификатор_сервисного_аккаунта>
Назначить права доступа на секрет и ключ шифрования разным аккаунтам также поможет документация сервиса Yandex Lockbox.
Шаг 4. Настраиваем переменные окружения. В консоли управления для Serverless Containers выбираем наш контейнер, переходим на вкладку Редактор. В блоке Параметры образа укажем переменную окружения и нажмём Добавить.
В нашем случае указываем IP-адрес сервера MongoDB, над которым мы разворачиваем административную панель и порт через который приложение будет доступно.
В командной строке эти же действия мы будем делать через создание ревизии контейнера. Создавать новую ревизию необходимо при загрузке новой версии Docker-образа в Container Registry и при изменении настроек. Подробнее о других параметрах настройки рекомендуем почитать в документации.
Создание ревизии с переменными окружения в командной строке
yc serverless container revision deploy \
--container-name <имя_контейнера> \
--image cr.yandex/crpc9qeoft236r8tfalm/mongo-express:hello \
--cores 1 \
--memory 1GB \
--service-account-id <идентификатор_сервисного_аккаунта> \
--environment ME_CONFIG_MONGODB_PORT=27017
Названия других необходимых переменных окружения можно взять из документации mongo-express на docker-hub.
Шаг 5. Настраиваем работу с секретами через сервис Yandex Lockbox. Для начала создаём секрет с credentials от MongoDB. Это можно сделать прямо из UI: на вкладке Редактор в блоке Параметры образа заполняем поле Секрет Yandex Lockbox.
То же самое в командной строке
yc serverless container revision deploy \
--container-name <имя_контейнера> \
--image cr.yandex/crpc9qeoft236r8tfalm/mongo-express:hello \
--cores 1 \
--memory 1GB \
--service-account-id <идентификатор_сервисного_аккаунта> \
--secret environment-variable=KEY,id=fc3q4a***,version-id=fc3gvv**,key=key-id
Шаг 6. Поставим тайм-аут на работу контейнера. Рекомендуем взять значение с запасом, потому что мы не знаем, сколько времени могут занимать запросы к mongo-express. Например, 10 секунд.
В консоли управления этот параметр задаётся на вкладке Редактор для контейнера, всё в том же блоке Параметры образа.
В командной строке этот параметр задаётся через execution timeout
yc serverless container revision deploy \
--container-name <имя_контейнера> \
--image cr.yandex/crpc9qeoft236r8tfalm/mongo-express:hello \
--cores 1 \
--memory 1GB \
--concurrency 1 \
--execution-timeout 10s \
--service-account-id <идентификатор_сервисного_аккаунта>
Шаг 7. Создаём последнюю ревизию контейнера.
Работа по запуску контейнера закончена, теперь мы можем дать к нему публичный доступ и перейти по ссылке, чтобы увидеть административную панель, запущенную на техническом домене Serverless Containers. Здесь можно создавать таблицы, добавлять и удалять документы. А логи работы приложения будут записываться в сервис Yandex Cloud Logging.
Шаг 8. Настраиваем авторизацию через API Gateway. Мы протестировали работу приложения, теперь настроим работу через API-шлюз, ограничив к приложению доступ по IP-адресу. Для этого добавим возможность авторизации в приложении через интеграцию API Gateway с специальной функцией-авторайзером.
Пример спецификации для создания интеграции с авторизацией можно посмотреть здесь. В неё вам необходимо добавить интеграцию с созданным контейнером и указать корректные id контейнера, функции и сервисных аккаунтов.
Подведём итог
В сервисе Serverless Containers не нужно платить за простой арендуемых мощностей, а оплачивается только время работы контейнеров, добавленных в сервис. Однако такой подход можно использовать не во всех приложениях, потому что Serverless Containers не хранит состояния контейнеров и сами контейнеры не работают в фоновом режиме.
Мы показали, как пошагово можно запустить в Serverless Containers контейнер — если есть готовый Docker-образ, это будет не сложно.
Комментарии (5)
Naglec
07.09.2023 13:58+1Насколько это дороже арендуемых VM? Спотовых?
dpivovarov Автор
07.09.2023 13:58В этом сценарии - несоизмеримо дешевле (почти наверняка бесплатно). А в целом сравнивать можно, если иметь чуть больше данных. Как правило, с serverless сервисами работает подход - если нагрузка плавающая и не очень хорошо прогнозируемая, то их использование часто будет дешевле.
Если нагрузка постоянная и хорошо прогнозируется, то экономическая целесообразность serverless считается заметно сложней, через TCO и потенциальную экономию в процессах разработки, а не в явном виде в инфраструктуре.
kulaginds
Спасибо за туториал.
Я использую Serverless Containers в своем прод-сервисе, который генерирует картинку на основе архива с данными.
Сам генератор выполняется в группе ВМ и там настроено авто масштабирование при увеличении очереди. И сделано это из-за ограничения с диском в Serverless Container (его там нет, есть только tmpfs на 500 мб).
Все лето я потратил на тесты Serverless YDB, Serverless Containers и Message Queue и пришел к нескольким выводам по этой связке:
В базе могут быть долгие ответы (выше 1 секунды на селект по первичному ключу). В условиях 5 секунд на запрос, можно не успеть. Лучше работает Postgres в виртуалке 20% cpu (см. п. 3 про http веб-сервер). Держать pet-project на этой базе можно смело. Нагрузка меньше 1qps.
В очереди иногда долго отвечает SendMessage. Изначально в очередь писал http-сервис из Serverless Container. Потом перенес http-сервис в постоянную виртуалку с 20% cpu и стало реже долго отвечать SendMessage, но проблема полностью не ушла. Уже общаемся с поддержкой по этому поводу.
http веб-сервер работает хорошо, но иногда бывают то ли проблемы с сетью (она инициализируется медленнее, чем http веб-сервер на Golang), то ли с ресурсами (в логах биллится 5 сек, а первого сообщения в логах из функции main нет). Если вам критично, чтобы запрос отдавался за условные 5-10 сек, то Serverless Container не подойдет. Даже с подготовленным экземпляром (а он по цене примерно так же, как ВМ с 20% cpu). Для фоновых задач по крону или из очереди подходит на отлично.
С нетерпением жду фичу по монтированию s3 бакета в Serverless Container.
kulaginds
Спасибо ребятам, за то, что создали такое. Мощная работа. В РФ аналогов пока не нашел.
dpivovarov Автор
Спасибо за обратную связь! Про монтирование бакета - скоро будут апдейты, подключайтесь к трансляции нашего трека на https://scale.yandex.ru/