Новый сервис Container Service в VMware Cloud Foundation (VCF) представляет собой простую отправную точку для использования Kubernetes (K8s) в компании, не требующую экспертизы в этой области. Многие организации сообщают, что им порой «просто нужно запустить контейнер», что они не могут нанять специалистов для работы с нагрузками в Kubernetes или что они только начинают путь модернизации приложений — берут старые приложения на .Net Framework, рефакторят их на .Net Core и приступают к контейнеризации.
Обычно, когда требуется запустить простые контейнерные приложения, рабочий процесс выглядит так:
Подготовить хостовую ОС
Установить и настроить среду выполнения контейнеров
Настроить аутентификацию в реестре образов
Загрузить и запустить образ контейнера
И это не считая управления жизненным циклом, установки патчей ОС, обновления среды выполнения, усиления безопасности и прочих задач, необходимых для эксплуатации такой системы в долгосрочной перспективе.
Какова бы ни была причина, заказчики ясно дали понять, что им нужен простой управляемый сервис, позволяющий получить преимущества Kubernetes без рутины и внутренней экспертизы. Поэтому новый Container Service был встроен в VCF Automation (а также в Local Consumption Interface, если VCF Automation не используется), чтобы можно было легко запускать готовые контейнеры. Рассмотрим, как это работает, что умеет сервис и как его можно применять уже сегодня.
Демонстрация
Технический обзор
VCF Container Service — это удобная обёртка вокруг концепции vSphere Pods в кластере Supervisor. vSphere Pods позволяют запускать контейнеры как виртуальные машины, что полезно в целом ряде случаев: когда требуется жёсткая граница ядра между контейнерами, когда не хочется нести накладные расходы на выделенные управляющие плоскости K8s или когда нет желания управлять кластерами K8s и их жизненным циклом.
Эта обёртка открывает практически всё, что можно ожидать от работы с контейнерной нагрузкой в K8s. Платформа даже принимает интеллектуальные решения на основе указанных спецификаций нагрузки — например, следует ли запускать приложение как Deployment или как StatefulSet в терминах Kubernetes.
Развернуть контейнер ещё никогда не было так просто
Начать работу очень легко: достаточно передать Container Service образ, совместимый с OCI, и сервис запустит его самостоятельно. При этом конфигурацию можно усложнять по мере необходимости: определять, в какие зоны (Zones) должна быть развёрнута нагрузка, какие ресурсы требуются для её эффективного планирования, а также сколько реплик нужно для этой нагрузки. Сервис даже берёт на себя аутентификацию в OCI-реестре. В результате пользователь получает конечную точку (endpoint), по которой доступно работающее приложение.
Обратите внимание на скриншот ниже: любые настройки, сделанные через UI, автоматически преобразуются в валидный K8s YAML в правой части экрана. Его можно скачать или скопировать и добавить в любую другую систему для воспроизводимых развёртываний. Так же устроены и другие сервисы в интерфейсе VCF, например «Виртуальные машины» или «Кластеры Kubernetes».
Заданные запросы CPU и памяти (значения по умолчанию уже установлены)
Всё остальное, описанное ниже, опционально и предназначено для более специфических сценариев.
Расширенные настройки
Если к работе приложения предъявляются особые требования — это не проблема: Container Service отнюдь не ограничен базовыми сценариями. Через сервис доступно практически всё, что может понадобиться контейнерной нагрузке: хранилище, балансировка нагрузки, управление конфигурациями и секретами, настройки среды выполнения вроде переменных окружения и даже sidecar-контейнеры для более продвинутых случаев.
Хранилище
Большинство (полезных) приложений так или иначе хранят состояние. Это не значит, что не бывает полезных приложений без него, но почти каждое приложение как минимум обрабатывает данные, если не хранит их. Поэтому одной из фундаментальных возможностей, которую нужно было представить в понятной форме, стали тома PersistentVolume. В Kubernetes тома PersistentVolume могут вести себя не так, как ожидают пользователи, в зависимости от их политики reclaimPolicy: по умолчанию том удаляется.
С учётом ожиданий заказчиков поведение по умолчанию было сделано разумным и осторожным: при удалении нагрузки тома сохраняются, чтобы позже их можно было примонтировать к другой нагрузке. Разумеется, тома по-прежнему можно удалить, чтобы освободить место. Кроме того, сервис упрощает идентификацию и повторное монтирование нескольких томов к нескольким экземплярам.
Возьмём пример StatefulSet с двумя репликами. Если удалить этот StatefulSet, тома сохранятся, и впоследствии, когда пользователь создаст другой экземпляр Container Service с двумя репликами и томами PersistentVolume, ему будет предложен выбор: создать новые тома или примонтировать существующие. Аналогично при уменьшении масштаба тома сохраняются и повторно монтируются при последующем увеличении.
Балансировка нагрузки
Следующий важный компонент любого приложения — то, как оно открывается сети, другим приложениям и пользователям. В K8s это делается с помощью объектов Service и Ingress/Gateway, при этом самый распространённый способ публикации нагрузки — LoadBalancer. Container Service позволяет создать LoadBalancer, выбрать протокол (TCP/UDP), внешний порт и внутренний порт контейнера, если выполняется трансляция портов. Такой Service распределяется по всем репликам данного экземпляра Container Service, обеспечивая доступность и отказоустойчивость при сбое экземпляра или нижележащего узла.
Конфигурация
Контейнеры принимают аргументы и настройки самыми разными способами. Распространённый паттерн — конфигурационные файлы, содержимое которых полностью зависит от конкретного приложения. Поэтому в сервисе реализована возможность создавать и монтировать объекты ConfigMap в контейнер, причём очень гранулярно.
Можно выбрать один из существующих в окружении объектов ConfigMap или создать новый. При создании нового достаточно вставить конфигурационный файл как текст через UI и выбрать способ монтирования — как том (Volume) или как переменные окружения.
Кроме того, при инъекции в виде переменных окружения предоставляется дополнительная гибкость: можно выбрать, инжектировать все ключи из конфигурационного файла или только отдельные, а также указать, как именно они будут отображены внутри контейнера.
Секреты
Секреты — API-ключи, токены, пароли и т.п. — критичны для многих приложений. Как и объекты ConfigMap, они передаются в контейнер практически теми же способами: как том или как переменные окружения, причём второй вариант наиболее распространён, поскольку данные никогда не оказываются «на диске» внутри контейнера. Отличие от раздела ConfigMap в том, что под капотом эти данные хранятся как объекты Kubernetes Secret.
Конфигурация среды выполнения
В этом разделе собраны параметры, определяющие, как контейнер должен работать в рамках конкретного экземпляра. Например, если нужно повысить уровень логирования или детализацию именно этого экземпляра, не затрагивая другие контейнеры, использующие тот же ConfigMap, можно добавить переменную окружения вроде LOG_LEVEL и установить желаемое значение, чтобы приложение отреагировало на него.
Кроме того, если контейнеру или приложению требуется указание, какую команду выполнить при запуске или какие аргументы передать приложению на старте, их можно задать в разделе Command and Arguments, следуя приведённому примеру.
Во всём интерфейсе Container Service выполняется встроенная проверка (линтинг) вводимых команд и конфигураций — это гарантирует их корректность и наличие всех обязательных аргументов, обеспечивая пользователям комфортную работу и избавляя от копания в логах при выяснении, почему контейнеры не развернулись.
Дополнительные контейнеры
Значительно более продвинутая опция — использование sidecar-контейнеров, которые работают рядом с основной нагрузкой в том же поде Kubernetes. Это означает, что под капотом они разделяют некоторые технические характеристики (например, сетевое пространство имён), что позволяет им получать доступ к информации друг друга. Типичные сценарии применения sidecar-контейнеров — сбор логов или метрик, добавление контейнера в сервисную сетку (service mesh) и т.д.
Ещё один пример sidecar-контейнера — InitContainers. Допустим, стек приложения включает базу данных, и при первом запуске нужно выполнить скрипт, который наполнит пустую базу схемой, чтобы приложение могло использовать её при старте. Полезная особенность InitContainers — последовательность выполнения (они блокируют запуск основного контейнера до своего успешного завершения), что помогает гарантировать, например, что база данных запустится раньше основного контейнера.
В конце пользователь получает наглядную сводку всей собранной конфигурации контейнера и возможность скачать описывающий её манифест перед развёртыванием.
Масштабирование рабочих нагрузок
Разумеется, после развёртывания приложение можно масштабировать в большую или меньшую сторону через тот же интерфейс, который использовался при его создании. Как всегда, с подробными подсказками, чтобы было понятно, что именно сделает платформа при использовании этих опций.
Заключение
Чтобы начать работу с новым Container Service в VCF, попробуйте VCF 9.1, доступный на сайте Broadcom. Техническая документация доступна здесь.