Понимание того как Kubernetes обрабатывает контейнеры дает большую гибкость при создании пользовательских конфигураций под конкретные нужды.

Kubernetes позволяет выполнять много полезной работы без глубокого понимания деталей. Утилита командной строки kubectl и дашборды в Openshift помогают управлять вашими контейнерами. Однако, как только вы заглянете глубже в Kubernetes все может быстро усложниться.

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

Такая аналогия правдива и для работы с Kubernetes. Просто сказать: "Давайте оставим это на усмотрение разработчиков" - недостаточно, с таким же успехом можно предоставить выбор системы кондиционирования обычным рабочим со строительной площадки. За каждой хорошо спроектированной системой стоит как множество деталей, так и архитектор, который понимает их значение.

Для системного архитектора в IT важно понимать как Kubernetes создает и запускает контейнеры. Изучение контейнерной оркестрации необходимо по двум причинам. Во-первых, это хорошее знание для архитектора уровня компании (как для обычного архитектора знание систем кондиционирования). Во-вторых, понимание механизмов, благодаря которым Kubernetes создает и запускает контейнеры, позволяет настраивать пользовательские конфигурации кластеров Kubernetes для специфичных кейсов, но для этого необходимо понимать основы

В данной статье объясняются основы того, как Kubernetes создает и запускает контейнеры. Для начала я опишу общую архитектуру процесса. Также поговорим о kubelet - части программного обеспечения, которая управляет контейнерами на worker ноде. Далее опишу как kubelet работает с container manager для скачивания образов контейнеров из репозиториев. В конце рассмотрим как container runtime запускает контейнеры.

Данная статья подразумевает, что вы обладаете высоким уровнем знаний о Kubernetes, как фреймворке для оркестрировании контейнеров, и понимаете базовые вещи о linux контейнерах. Если хотите ознакомиться с основами контейнеров, изучите документацию Red Hat "Начало работы с контейнерами". Для быстрого ознакомления с Kubernetes прочитайте "Основы изучения Kubernetes".

Кроме того, имейте в виду, что термины container manager и среда container runtime использовались по-разному на протяжении многих лет. Я использую их очень специфическим образом, чуть позже объясню как именно.

Архитектура Kubernetes и kubelet

Kubernetes - это среда оркестрации контейнеров. Архитектура Kubernetes имеет control plane, состоящий из одной и более вычислительных машин, виртуальных или реальных. Control plane выступает в качестве посредника между миром снаружи кластера и его внутренностями (кластер - это совокупность одной или нескольких вычислительных машин, виртуальных или реальных). Control plane координирует действия вычислительных машин (виртуальных или реальных). Эти машины называются worker node. На них размещаются контейнеры с приложениями.

Каждая worker node имеет часть программного обеспечения, которая называется kubelet. Kubelet занимается координацией работы по созданию и удалению контейнеров в соответствии с конфигурацией сохраненной в control plane. Создание контейнера разбито на 3 этапа. Сначала, control plane определяет необходимость создания нескольких контейнеров. Далее, control plane определяет, какая worker node имеет нужные ресурсы для размещения контейнеров. В конечном итоге, control plane уведомляет kubelet, на выбранной worker ноде, создать контейнеры.

Рисунок 1: Плоскость управления Kubernetes работает с kubelet, установленным на каждой ноде, для создания и запуска контейнеров. (Bob Reselman, CC BY-SA 4.0)
Рисунок 1: Плоскость управления Kubernetes работает с kubelet, установленным на каждой ноде, для создания и запуска контейнеров. (Bob Reselman, CC BY-SA 4.0)

Вы можете подумать о kubelet как о контроллере рабочего узла для создания и запуска контейнеров. Он ответственный за проверку выполнения работы, но не делает все сам. Container manager и container runtime выполняют остальную работу.

Разница между container manager и container runtime

Создание контейнера разбито на две задачи. Первая включает в себя скачивание образов контейнеров с репозиториев таких как Quay.io или Docker Hub. Другая задача - это создание и запуск контейнеров из образов.

Container manager отлавливает задачи связанные с извлечением и хранением образов контейнеров. Примерами container manager выступают containerd и CRI-O. Container runtime выполняет создание и запуск контейнеров, например, runC или Clear Containers. Ранее, container manager и container runtime были единым компонентом. Но с течением времени они были разделены в соответствии со стандартом технических характеристик, опубликованным OCI. OCI - это open source организация, которая имеет "явную цель создания открытых отраслевых стандартов в отношении форматов контейнеров и runtime".

Стандартизация контейнерной инфраструктуры с помощью OCI

Container managers и container runtimes существуют уже давно. FreeBSD jail был одним из первых, появившись в начале 2000 года. Другие последовали за ним. Каждый имел свой собственный способ работы, что ограничивало взаимодействие между различными системами.

Ранние версии Kubernetes использовали docker по умолчанию. Первоначально docker имел монолитную архитектуру и совмещал в себе container manager и container runtime. Однако, по ряду причин, компании разрабатывающие контейнерные технологии начали отделять container manager от container runtime. Docker тоже отделил. Разделение было сделано в соответствии со стандартами установленными OCI в 2017.

OCI опубликовал 3 спецификации: образ, распространение и runtime. Спецификация образа определяет структуру и представление образа контейнера. Спецификация распространения - как container manager будут доставлять образы контейнеров в репозитории, а затем до окружений. Спецификация runtime определяет как container runtime запускает контейнеры.

Рисунок 2: Спецификации OCI предоставляют стандартный способ создания и развертывания образов контейнеров, а также запуска контейнеров на основе определенного образа. (Боб Реселман, CC BY-SA 4.0)
Рисунок 2: Спецификации OCI предоставляют стандартный способ создания и развертывания образов контейнеров, а также запуска контейнеров на основе определенного образа. (Боб Реселман, CC BY-SA 4.0)

Стандартизация трех данных аспектов контейнерной активности в общую спецификацию сделала транспортабельность и совместимость между различными платформами и окружениями возможной. Разработчики сделали OCI совместимый контейнерный образ, который может храниться в OCI совместимых контейнерных хранилищах, таких как Quay.io или Docker Hub. Затем этот образ может быть скачан container manager, таким как containerd и запущен OCI совместимым runtime, например, runC или gVisor.

Спецификация OCI ставит контейнерные технологии на равные условия. Природа спецификации сделала инновации проще. Каждый новый проект, который поддерживает спецификацию OCI, может стать частью контейнерной экосистемы. Можно провести аналогию с железной дорогой. Стандартизация ширины рельс в железнодорожной системе (калибр рельсы) сделала так, что любое производство, которое придерживалось стандарту рельсового калибра, могло запускать свои поезда на системе. Не важно движется ли поезд на паровой тяге или за счет электропривода. Стандартизация сделала разнообразие возможным.

Стандартизация контейнерных технологий открыла дверь для возможности использования различных container manager и container runtime в Kubernetes. Взаимодействие между container manager и container runtime происходит в соответствии с OCI. Это хорошо. Но в условиях эволюции Kubernetes оставался все еще нерешенный вопрос: “Как сделать общий путь в Kubernetes для взаимодействия с container manager?” CRI решил эту проблему.

Понимание container runtime interface

CRI это общая модель создания container manager, который может запускаться под Kubernetes. Данная модель появилась в Kubernetes начиная с 1.5 в 2015. CRI - больше чем стандарт. Это программный интерфейс, написанный для protocol buffer и gRPC, разделенный на две части. Первая - ImageService, вторая - RuntimeService.

Рисунок 3: Теоретическая реализация спецификации Kubernetes CRI (Боб Реселман, CC BY-SA 4.0)
Рисунок 3: Теоретическая реализация спецификации Kubernetes CRI (Боб Реселман, CC BY-SA 4.0)

ImageService - интерфейс, который решает задачи container manager. RuntimeService решает задачи container runtime.

Как и в случае с любым программным интерфейсом, CRI описывает методы работы с container manager и container runtime, но не то, как это должно происходить. "Как" относится к области программиста и языка программирования. Иногда "как" в реализации под Kubernetes может стать довольно сложным, особенно при добавлении сети Kubernetes, которая определяется еще одной спецификацией: сетевым интерфейсом контейнера (CNI).

Рисунок показывает реализацию работы worker node, использующей container manager - containerd, и container runtime - runC.

Рисунок 4: Запуск диспетчера контейнеров containerd и среды выполнения контейнера runC в Kubernetes (Джо Джулиан, CC BY-SA 4.0)
Рисунок 4: Запуск диспетчера контейнеров containerd и среды выполнения контейнера runC в Kubernetes (Джо Джулиан, CC BY-SA 4.0)

Kubernetes обладает сложностью, необходимой для упрощения работы на более высоких уровнях. Но во всем этом есть значительная выгода.

Преимущество понимания деталей

Использование CRI и OCI спецификаций вместе позволяет Kubernetes поддерживать именно те container manager и runtime, которые вы хотите использовать для кластера Kubernetes. Также, CRI и OCI позволяют запускать различные container manager и runtime в одном кластере.

Преимущество этого всего в гибкости, которую CRI и OCI предоставляют архитекторам для настройки Kubernetes под специфические нужды. Потребности различаются, соответственно, разные container manager и runtime лучше подходят для различных случаев. В качестве примера, использование нативного container runtime, такого как runC - хороший выбор для контейнеризированных приложений, выполняющихся за миллисекунды, требующих быстрой загрузки и выхода. runC использует ядро хостовой машины, таким образом достигается оптимальная производительность.

Другой случай, приложению нужна поддержка security policy, чтобы контейнер не мог получить доступ к ядру хостовой машины, для этого нужно использовать Kubernetes с kata контейнерами. Kata контейнеры - это проект container runtime, который запускает контейнеры в своей квази виртуальной машине, изолированной от хостовой машины.

Опять же, приятная особенность стандартизации, гарантируемой спецификациями OCI и CRI, заключается в том, что они обеспечивают большую гибкость в настройке container manager и container runtime контейнеров в Kubernetes. Это значительное преимущество. Обратите внимание, что в одном кластере может использоваться несколько сред выполнения. Например, OpenShift использует runC по умолчанию, но когда включены изолированные контейнеры, контейнеры kata могут запускаться в одном кластере.

Итоги

Когда дело доходит до проектирования инфраструктуры Kubernetes для поддержки современных приложений, выбор имеет значение. К счастью, выбор существует благодаря преимуществам, предоставляемым спецификациями OCI и CRI. Компромисс заключается в необходимости понимания множества деталей Kubernetes и технологий контейнеров, чтобы заставить все это работать.

С архитектурной точки зрения важно понимать, что временные затраты, необходимые для изучения деталей создания и запуска контейнеров в Kubernetes, того стоят. От вас требуется множество знаний, однако, взамен вы сможете многое делать очень гибко.

Комментарии (1)


  1. sergikotikov
    29.03.2022 20:38

    Спасибо, продолжайте не останавливайтесь