Kubernetes: большой обзор технологии, установка и настройка

Kubernetes: большой обзор технологии, установка и настройка

Михаил Фомин
Михаил Фомин Продуктовый копирайтер
13 октября 2023

Что такое Kubernetes (K8s): архитектура и основные компоненты, работа с кластерами в контейнерах.

Изображение записи

Kubernetes за несколько лет прошел большой путь от проекта небольшой команды из Google до первого выпускника CNCF и надежды всего сообщества разработчиков облачно-ориентированных приложений. Так получилось не за один день, а по сумме накопившихся предпосылок и решений. 

С развитием технологий все больше ожиданий стали ложиться на бизнес. Появлялись стриминги, крупные EdTech и FinTech проекты со своей спецификой. Пользователи ждали, что сервисы будут не только быстро загружать контент и проводить транзакции, но также обладать высокой доступностью. В это же время нужно было оптимизировать те решения, что уже были на рынке, например, контейнеры.

Что такое контейнеризация

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

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

Контейнеризацию можно рассматривать как усовершенствованный вариант виртуальной машины. Только с максимальной изоляцией в рамках одной ОС. В отличие от обычной ВМ, контейнер не связан с базовой аппаратной инфраструктурой и может легко переноситься между облаками и несколькими ОС.

Преимущества контейнеризации

  • Простота и гибкость развертывания приложений относительно работы с ВМ.
  • CI/CD с возможностью моментально откатить апдейты.
  • Разделение приложений на изолированные микросервисы с гибким развертыванием и управлением.
  • Создание контейнеров приложений в процессе сборки/релиза и отделение приложения от конкретного железа.
  • Среды разработки и тестирования на сервере и в локальных машинах не отличаются.

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

Решением для оптимизации работы с контейнерами стали оркестраторы. Одним из первых таких решений был Apache Mesos, выпущенный еще в 2009 году. Kubernetes появится только в 2014, но обо всем по порядку.

Что такое Kubernetes и как он работает

Kubernetes (K8s) — это программная платформа для автоматического управления контейнеризованными приложениями. Он позволяет развертывать, масштабировать и поддерживать контейнеры и микросервисы.

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

Что можно сделать, используя оркестраторы:

  • равномерно распределить аппаратные ресурсы,
  • настроить автоматизацию процессов обновления и отладки,
  • отладить процесс масштабирования.

Kubernetes действует на уровне логики, а не аппаратного обеспечения, по принципу «ведущий — ведомый». Управление системой основано на двух подходах:

  • Декларативном — разработчик задает цели, а не пути их достижения, которые система выбирает автоматически.
  • Императивном — разработчик может управлять ресурсами с помощью команд «Создать», «Изменить», «Удалить».

Чтобы Kubernetes мог запускать приложения и службы в контейнерах, каждый должен быть оснащен средой выполнения. Это может быть Docker, rkt или runc. На заре K8s технологию нельзя было представить без Docker — эта связка считалась best practice на рынке, но в 2020 году сообщество решило отказаться от среды исполнения в пользу containerd и CRI-O.

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

Концепции Kubernetes

В Kubernetes есть ряд собственных понятий, которые описывают архитектуру и функциональность системы.

  • Nodes (node.md) — машины в кластере K8s.
  • Pods (pods.md) — группа контейнеров с общими разделами, которые запускаются как одно приложение.
  • Replication Controllers (replication-controller.md) способ репликации, который гарантирует, что определенное количество «реплик» будут запущены в любой момент времени.
  • Services (services.md) — набор логически объединенных подов и политик доступа.
  • Volumes (volumes.md) — доступная в контейнере директория с данными или без них.
  • Labels (labels.md) — пары ключ/значение, которые прикрепляются к объектам. Например, к подам. Labels могут применяться для создания и выбора наборов объектов.
  • Операторы (operators.md) — программное обеспечения Kubernetes, необходимое для включения в кластер сервисов, сохраняющих состояние между выполнениями (stateful). Например, СУБД.
  • Kubectl Command Line Interface (kubectl.md) — интерфейс командной строки для управления Kubernetes.

Далее разберем некоторые из этих концепций в контексте архитектуры Kubernetes, а прочие — как элементы управления платформой.

Архитектура Kubernetes: основные объекты кластера

Кластер. Развертывание Kubernetes — это, в первую очередь, поднятие кластера. В кластере обязательно есть хотя бы одна нода. Она состоит из набора машин, которые запускают контейнерные приложения. Обычно на одной ноде кластер не ограничивается, поскольку дополнительные ноды решают проблему отказустойчивости.

Nods (узлы). Это физические или виртуальные машины, на которых развертываются и запускаются контейнеры с приложениями. Каждый узел содержит сервисы, необходимые для запуска подов.

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

Типы нод

  • Master (мастер-нода) — узел, управляющий всем кластером. Он следит за остальными нодами и распределяет между ними нагрузку с помощью менеджера контроллеров (controller manager) и планировщика (scheduler). Как правило, мастер-нода занимается только управлением и не берет на себя рабочие нагрузки. Для повышения отказоустойчивости существует несколько мастер-нод.
  • Worker (рабочие ноды) — узлы, на которых работают контейнеры. В зависимости от параметров ноды (объема памяти и центрального процессора) на одном узле может работать множество контейнеров. Чем больше рабочих узлов, тем больше приложений можно запустить. Также количество влияет на отказоустойчивость кластера, потому что при выходе из строя одной ноды нагрузка распределяется по оставшимся.

Работающий кластер Kubernetes включает в себя агента, запущенного на нодах (kubelet), и компоненты мастера (APIs, scheduler, etc), поверх решения с распределенным хранилищем.

Pods (отсеки). Pod определяется представлением запроса на запуск (execute) одного или более контейнеров на одном узле. Они разделяют доступ к таким ресурсам, как: тома хранилища и сетевой стек.

Термин «pod» может употребляться и в смысле этого запроса, и в смысле совокупности контейнеров, которые запускаются в ответ на запрос. Далее мы будем использовать слово «pod», когда будем говорить о запросе, а для второго случая — употреблять выражение «набор контейнеров».

Поды считаются базовыми строительными блоками Kubernetes, поскольку все рабочие нагрузки в Kubernetes — например, Deployments, ReplicaSets и Jobs — могут быть выражены в виде pods. Конкретнее об этих понятиях мы поговорим позже.

Pod — это единственный объект в Kubernetes, который приводит к запуску контейнеров. Нет пода — нет контейнера.

Плоскость управления. Плоскость управления Kubernetes состоит из набора процессов, запущенных в кластере. Master Kubernetes — это коллекция из трех процессов, которые выполняются на одном pod в кластере, который обозначен как главный узел. Это процессы: kube-apiserver, kube-controller-manager и kube-scheduler. Эти компоненты мы разберем, когда дойдем до схемы организации кластера.

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

Объекты. Сущности, которые в архитектуре Kubernetes используются для представления состояния кластера.

  • Kube-apiserver. С помощью сервера API обеспечивается работа API кластера, обрабатываются REST-операции и предоставляется интерфейс, через который остальные компоненты взаимодействуют друг с другом. Кроме этого, через него проходят запросы на изменение состояния или чтение кластера. Работает на master-нодах.
  • Kube-scheduler. Компонент-планировщик, который определяет на каких узлах разворачивать pods. Он учитывает такие факторы, как ограничения, требования к ресурсам, местонахождение данных и пр. Работает на master-нодах.
  • Etcd. Распределенное хранилище в формате «ключ-значение». В нем хранится состояние всего кластера. Главная задача etcd — обеспечить отказоустойчивость кластера и консистентность данных. Etcd — самостоятельный проект. Он развивается отдельно от Kubernetes и применяется в разных продуктах. Работает на master-нодах.
  • Kube-proxy. Служба, которая управляет правилами балансировки нагрузки. Она конфигурирует правила IPVS или iptables, через которые выполняются проксирование и роутинг. Работает на worker-нодах.
  • Kube-controller-manager. Компонент запускает работу контроллеров. Работает на master-нодах.
  • Kubelet. Cлужба управляет состоянием ноды: запуском, остановкой и поддержанием работы контейнеров и подов. Работает на worker-нодах.

Контейнер Cloud. Код работающего контейнера невозможно поменять (immutable). Чтобы внести правки в контейнеризованное приложение, необходимо собрать новый образ, содержащий апдейты, а далее запустить контейнер на базе обновленного образа.

Исполняемые среды контейнеров. Исполняемая среда контейнера — это программа, предназначенная для запуска контейнера в Kubernetes. Оркестратор поддерживает различные среды для запуска контейнеров: Docker, containerd, CRI-O, и любые реализации Kubernetes CRI (Container Runtime Interface).

Развертывание. При разворачивании приложения в Kubernetes, мы сообщаем мастеру, что нужно запустить контейнеры приложений. Мастер планирует запуск контейнеров на узлах кластера. Узлы связываются с мастером с помощью Kubernetes API, который предоставляет мастер.

Есть различные готовые реализации кластера Kubernetes (K8S), например:

  • Minikube — готовый кластер, который разворачивается на один компьютер.
  • Kubespray — набор ansible ролей.
  • Готовые кластеры в облаке или Container Registry.

Набор реплик. Набор реплик гарантирует, сколько реплик модуля должно быть запущено. Это можно рассматривать как замену контроллера репликации. Основное различие между набором реплик и контроллером репликации состоит в том, что контроллер репликации поддерживает только селектор на основе равенства, тогда как набор реплик поддерживает селектор на основе набора.

Сервис. Сервис в Kubernetes — абстракция, определяющая логический набор подов и политику доступа к ним (иногда такой набор подов еще называют микросервисом). Как правило, этот набор подов определяется на основе меток (присваиваются в момент создания подов) и селекторов.

Например, backend — это 3 реплики подов, занимающихся обработкой изображений. Все три пода абсолютно идентичны с функциональной точки зрения (так как это реплики), поэтому frontend не должен беспокоиться на какой именно backend-под попадет запрос — это работа сервиса.

Возможности Kubernetes

Теперь, когда мы разобрались с устройством платформы, можно переходить к возможностям K8s.

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

Нужно отметить, что все эти автоматизации можно сделать и без Kubernetes, но для этого придется потратить больше времени и разбираться с целым арсеналом различных инструментов. Например, для автоматизации деплоя и обновлений приложений можно использовать Ansible — систему управления конфигурациями. Такая система может обновить все инстансы приложения и убедиться, что оно работает. Но для этого она должна знать, какие хосты сейчас работают, как к ним обратиться, на каких именно хостах работают инстансы нужного приложения. Здесь не обойтись без написания скриптов, которые будут за этим следить.

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

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

Взрывной рост не мог пройти без последствий: Kubernetes все чаще становится целью различных атак. Ситуация усугубляется тем, что типичный кластер K8s обрастает множеством компонентов, которые необходимы для его полноценной работы. Подобное сращивание усложняет инфраструктуру, расширяя спектр направлений для «ударов» со стороны злоумышленников.

Преимущества и недостатки Kubernetes

Преимущества

Портативность и гибкость. K8s помогает автоматизировать ряд процедур, например, поднятие контейнеров, чтобы разработчики могли уделять больше времени написанию кода. Это положительно сказывается на time-to-market приложений. 

Экономичность. K8s помогает оптимально утилизировать ресурсы, использовать готовые контейнеры и удобно фрагментировать данные у разных провайдеров IT-инфраструктуры.

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

Эффективное распределение задач. Разработчики могут создавать окружения для автоматизированного тестирования, которые в точности повторяют прод. Общие логи работы приложения и работы Kubernetes с приложением ускоряют процесс разработки и поиск ошибок.

Безопасность. Контейнеры и сам Kubernetes предоставляет большие возможности по организации и наблюдению за происходящим. Вопросы безопасности Kubernetes стоит рассматривать в трех аспектах: control plane, worker node и cluster network. При последовательном подходе к организации безопасности в каждом компоненте, K8s предлагает высокий уровень безопасности для приложений.

Недостатки

Высокий порог входа. Работа с платформой даже сейчас, с обилием вспомогательных инструментов, остается достаточно сложной. Многие процессы необходимо настраивать вручную, сложно организована миграция между облаками и серверами. От команды требуется большой опыт даже для решения повседневных задач. 

Обслуживание и команда. Недостаток и высокая стоимость специалистов, владеющих достаточным опытом.

Что такое Managed Kubernetes

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

В таком случае часть задач можно делегировать провайдеру услуги. Подход Managed Kubernetes упрощает работу с кластерами: развертывание, масштабирование и как следствие — обслуживание самой инфраструктуры.

Доступность кластеров в Managed Kubernetes определяется и фиксируется в SLA, поэтому, пользуясь услугой, компания может снять с себя часть рисков и делегировать их провайдеру услуги.

Почему стоит использовать Managed Kubernetes

Быстрое создание и масштабирование кластеров

Кластер любой конфигурации можно создать через панель управления за несколько кликов. Можно настроить автоматическое масштабирование на случай, если нагрузка резко изменится. Платформа может поднять до 120 нод.

Простое управление кластерами

Несколько способов для обеспечения гибкого управления: панель управления, API и terraform-провайдер.

Кластеры с GPU

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

Основные объекты и компоненты кластера Kubernetes

Persistent Volumes (постоянные тома)

Подсистема позволяет создавать ресурс хранения, который не зависит от модульности. Использование PV гарантирует, что хранилище будет постоянным. 

Namespaces (пространства имен) 

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

ReplicaSet (набор реплик) 

Сейчас вместо ReplicaSet используется Deployment, поэтому блок нужен скорее для полнтоты картины.

ReplicaSet можно рассматривать, как следующее поколение Replication Controller. Различие между ReplicaSet и Replication Controller заключается в поддержке селекторов. ReplicaSet поддерживает множественный выбор в селекторе, а Replication Controller — только выбор на основе равенства.

Deployment (развертывание) 

Развертывание можно определить для создания новых наборов реплик или для удаления существующих развертываний и принятия всех их ресурсов новыми развертываниями. А также процесс реконфигурации кластера с его текущего состояния на желаемое состояние. 

StatefulSet (набор состояния) 

Это контроллер Kubernetes, который используют для эксплуатации сохраняющих состояние приложений в виде контейнеров (подов) в кластере Kubernetes. StatefulSet присваивают каждому поду идентификатор-липучку (sticky identity) — порядковый номер начиная с нуля — а не случайные ID каждой реплике пода. 

DaemonSet (набор демона) 

Это объект Kubernetes, который гарантирует, что копия модуля пода, определенного в конфигурации, всегда будет доступна на каждом рабочем узле в кластере. При добавлении нового узла в кластер DaemonSet автоматически выделяет модуль пода на этом узле. 

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

Job (задания)

Это yaml-манифест, который создает под для выполнения разовой задачи. Если запуск задачи завершается с ошибкой, Job перезапускает поды до успешного выполнения или до истечения таймаутов. Когда задача выполнена, Job считается завершенным и больше никогда в кластере не запускается. Job — это сущность для разовых задач.

Когда используют Job:

  • При установке и настройке окружения. Например, мы настроили CI/CD, который при создании новой ветки создает для нее окружение .dev. В новую ветку стали прилетать коммиты — CI/CD создал в кластере отдельный namespace и запустил Job — далее он создает БД, налил туда данные, все конфиги сохранил в Secret и ConfigMap. То есть Job предоставил готовое окружение, в котором можно тестировать и отлаживать новые фичи.
  • При выкатке helm chart. Когда helm chart пройдет деплой, с помощью хуков (hook) запускается Job, чтобы понять, готово ли приложение к работе.

Job позволяет выполнить разовые задачи, но на практике постоянно возникает потребность делать что-то в календарном режиме. Здесь Kubernetes подключает CronJob.

CronJob (задачи по расписанию)

Это yaml-манифест, на основании которого по расписанию создаются Jobs, которые в дальнейшем создают поды.

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

В манифесте CronJob прописывают расписание и пару параметров:

  • startingDeadlineSeconds,
  • concurrencyPolicy.

Label (метки) 

Метки — это пары ключ-значение, которые добавляются к объектам (как поды). Они предназначены для идентификации атрибутов объектов, которые имеют значимость и важны для пользователей, но при этом не относятся напрямую к основной системе. Метки можно применять для группировки и выбора подмножеств объектов. Их можно добавить к объектам во время создания и изменены в любое время после этого. Каждый объект может иметь набор меток в виде пары ключ-значение. Все ключи должны быть уникальными в рамках одного и того же объекта. Метки используются при получении и отслеживании объектов и в веб-панелях и CLI-инструментах. Любая неидентифицирующая информация должна быть занесена в аннотацию.

Если сравнивать имена идентификаторов и метрики — вторые не обязаны обеспечивать уникальность. Придется принять, что разрозненные объекты могут иметь одинаковые метки.

Selectors (селекторы)

  • С помощью селектора меток клиент/пользователь может идентифицировать набор объектов. Селектор меток — базовый инструмент группировки в Kubernetes.
  • API поддерживает два типа селекторов: на равенстве и на наборе. Селектор меток может состоять из нескольких условий, разделенных запятыми. В таком случае все условия должны быть выполнены, поэтому запятая-разделитель работает как логический оператор И (&&).
  • Работа пустых или неопределенных селекторов зависит от контекста. Типы API, которые использует селекторы, должны задокументировать это поведение.

Начало работы с Kubernetes

Для запуска сервиса необходимо подготовить docker контейнер, на основе которого будет создан сервис. Дабы не усложнять, в примере будет использован общедоступный контейнер nginx. Обязательными составляющими сервиса являются Replication Controller, обеспечивающие запущенность необходимого набора контейнеров (точнее pod) и service, который определяет, на каких IP-адресах и портах будет слушать сервис и правила распределения запросов между pod’ами.

Любой сервис можно запустить несколькими способами: вручную и с помощью конфиг-файла.

Запуск сервиса через Deployment

Развернем первое приложение в Kubernetes с помощью команды:


    kubectl create deployment

Для этого потребуется указать имя деплоймента и путь к образу приложения (используйте полный URL репозитория для образов, которые располагаются вне Docker Hub).


    kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1

Так разворачивается первое приложение. Команда привела к выполнению следующих действий:

  • Поиск подходящего узла, на котором можно запустить инстанс приложения (доступен только 1 узел).
  • Планирование (размещение) приложения для запуска на этом узле.
  • Настройка кластера на повторное размещение экземпляра на новом узле, когда это потребуется.

Чтобы увидеть список деплойментов, нужно использовать команду:


    kubectl get deployments

Есть один деплоймент, в котором запущен единственный экземпляр приложения. Этот экземпляр работает в контейнере на узле кластера.

conf% /opt/bin/kubectl run-container nginx --port=80 --port=443 --image=nginx --replicas=4 -s "http://192.168.0.10:8080"

Где:

nginx — имя будущего rc.
—port — порты, на которых будут слушать контейнеры rc.
—image — образ, из которого будут запущены контейнеры.
—replicas=4 — количество реплик.

Посмотрим, что у нас получилось:
/opt/bin/kubectl get pods,rc -s «http://192.168.0.10:8080»

Резюме
Был создан Replication Controller с именем nginx и количеством реплик равным четырем. Реплики в произвольном порядке уже запущены на нодах.

Картина может отличаться, например:

  • Часть подов находится в состоянии pending. Значит, что они еще не запустились, нужно дополнительное время.
  • У подов не определен HOST. Значит, что планировщик еще не назначил ноду, где будет запущен pod.

Далее создаем service, который будет использовать Replication Controller как бекенд.

Для http:

conf% /opt/bin/kubectl expose rc nginx —port=80 —target-port=80 —service-name=nginx-http -s «http://192.168.0.10:8080»

Для https:

conf% /opt/bin/kubectl expose rc nginx —port=443 —target-port=443 —service-name=nginx-https -s «http://192.168.0.10:8080»

Где:

rc nginx — тип и имя используемого ресурса (rc = Replication Controller).
—port — порт, на котором будет «слушать» сервис.
—target-port — порт контейнера, где будет производиться трансляция запросов.
—service-name — будущее имя сервиса.

Проверяем результат:

/opt/bin/kubectl get rc,services -s «http://192.168.0.10:8080»

Резюме

Чтобы проверить готовность, можно зайти на любую ноду и выполнить в консоли:

node% curl http://192.168.3.66

В выводе curl увидим стандартную приветственную страницу nginx. Готово.

Для этого способа запуска необходимо создать конфиги для Replication Controller’а и service’а. Kubernetes принимает конфиги в форматах yaml и json, но будем использовать yaml.

Сначала почистим кластер:

Можем приступать к написанию конфигов.

nginx_rc.yaml

Применяем конфиг:

conf% /opt/bin/kubectl create -f ./nginx_rc.yaml -s «http://192.168.0.10:8080»

Проверяем результат:

conf% /opt/bin/kubectl get pods,rc -s «http://192.168.0.10:8080»

Резюме

Был создан Replication Controller с именем nginx и количеством реплик равным четырем. Реплики в произвольном порядке запущены на нодах, местоположения каждой pod’ы указано в столбце HOST.

nginx_service.yaml

Можно заметить, что при использовании конфига за одним сервисом могут быть закреплены несколько портов.

Применяем конфиг:

conf% /opt/bin/kubectl create -f ./nginx_service.yaml -s «http://192.168.0.10:8080»

Проверяем результат:

/opt/bin/kubectl get rc,services -s «http://192.168.0.10:8080»

Резюме

Чтобы проверить готовность, можно зайти на любую из нод и выполнить в консоли:

В выводе curl увидим стандартную приветственную страницу nginx.

Пример настройки кластера

Нужно указать сервер, на котором установлен K8s (он будет первичным — там будут запускаться остальные операции) и выполнить инициализацию кластера:


    kubeadm init --pod-network-cidr=10.244.0.0/16

В данном примере будем использован наиболее распространенный сетевой плагин — Flannel (альтернативы: Calico, Canal, Romana или Weave). По умолчанию он использует сеть «10.244.0.0/16», которая была указана в параметре, приведенном выше.

При выполнении команды в консоли, есть вероятность появления ошибок или предупреждений. Ошибки нужно исправлять в обязательном порядке, а на предупреждения можно не обращать внимание, если это не окружение «production».

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

Остается выполнить следующие команды от имени пользователя, который будет управлять кластером:


    mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

Установка kubeadm, kubelet и kubectl в Ubuntu или в CentOS

kubeadm

Kubeadm автоматизирует установку и настройку компонентов Kubernetes, в том числе сервера API, Controller Manager и Kube DNS. Однако данное средство не создает пользователей и не выполняет установку зависимостей уровня операционной системы и их конфигурации. Для предварительных задач существует возможность использования инструментов управления конфигурацией, таких как Ansible и SaltStack. Использование этих инструментов упрощает создание дополнительных кластеров или воссоздание существующих кластеров, а также снижает вероятность ошибок.

Kubelet

Kubelet является основным агентом узла, который запускается на каждом узле. Он может зарегистрировать узел в apiserver, используя одно из следующих значений: имя хоста, флаг, переопределяющий имя хоста, или специальную логику для облачного провайдера.

Kubelet работает в терминах PodSpec. PodSpec — это объект YAML или JSON, описывающий pod. Куплет принимает набор PodSpec, предоставляемых через различные механизмы (в основном через apiserver), и обеспечивает работу и работоспособность контейнеров, описанных в этих PodSpec. Kubelet не управляет контейнерами, которые не были созданы Kubernetes.

Kubectl

Инструмент командной строки Kubernetes kubectl позволяет запускать команды для кластеров Kubernetes. Вы можете использовать kubectl для развертывания приложений, проверки и управления ресурсов кластера, а также для просмотра логов.

Используемая вами мажорная версия Kubectl не должна отличаться от той, которая используется в кластере. Например, версия v1.2 может работать с версиями v1.1, v1.2 и v1.3. Использование последней версии Kubectl поможет избежать непредвиденных проблем.

Требования для запуска

В качестве примера приведем минимальные требования для запуска kubeadm:

  • 2 ГБ оперативной памяти на узел.
  • 2 ядра процессора или больше.
  • Сетевое подключение между узлами (главный узел должен иметь возможность общаться с рабочими узлами).
  • Уникальное имя хоста и MAC-адрес для каждого узла (это легко не заметить при работе с виртуализированными узлами).
  • Откройте порты для любых служб, которые вы планируете запускать (например, HTTP-порт 80 для кластера веб-серверов).
  • Уровень контейнеризации (наиболее популярным выбором для этого является Docker).
  • На машинах Linux должно быть отключено пространство подкачки.

Настройка Kubernetes

Далее приведем основные настройки, которые можно применить для начала работы с оркестратором.

Инициализация кластера

Kubeadm позволяет развернуть mvp-кластер Kubernetes. С помощью kubeadm можно создать кластер, который выполнит тесты Kubernetes Conformance. Kubeadm также поддерживает другие функции жизненного цикла кластера. Например bootstrap-токены и обновления.

Kubeadm стоит использовать в нескольких случаях:

  • Развернуть кластер в тестовом режиме, чтобы познакомиться с технологией.
  • Автоматизировать настройку кластера и протестировать приложения.
  • Использовать как строительный блок для других инструментов экосистемы.

Инициализация узла управляющей плоскости

Узел control plane представляет собой ВМ, на которой работают компоненты плоскости управления, включая etcd (БД кластера) и сервер API (с ним взаимодействует инструмент командной строки kubectl).

Если планируется модернизация кластера kubeadm с одной плоскостью управления до уровня высокой доступности, то следует указать параметр:


    --control-plane-endpoint

Это необходимо для установки общей конечной точки для всех узлов плоскости управления. Конечной точкой может стать DNS-имя или IP-адрес балансировщика нагрузки.

Выберите сетевое дополнение Pod и проверьте, требует ли оно передачи каких-либо аргументов в kubeadm init. В зависимости от выбранного стороннего провайдера может потребоваться установить в параметре —pod-network-cidr значение, характерное для конкретного провайдера. 

Для инициализации узла плоскости управления используйте команду:


    kubeadm init <args>

Установка сетевого дополнения Pod

До того, как приступить к работе, прочитайте информацию о настройке сети и порядке деплоя.

Чтобы модули могли корректно взаимодействовать друг с другом, нужно установить сетевое дополнение Pod, основанное на сетевом интерфейсе контейнеров (CNI). Кластерный DNS (CoreDNS) не будет запускаться до установки сети.

Сеть Pod не должна пересекаться ни с одной из сетей хоста: при любом пересечении есть риск появления проблем. Если появилась коллизия между предпочтительной сетью Pod сетевого плагина и некоторыми сетями хостов, следует придумать подходящий блок CIDR, который можно использовать вместо него, а затем использовать его во время kubeadm init с параметром: 


    --pod-network-cidr 

В качестве замены в YAML вашего сетевого плагина.

По умолчанию kubeadm настраивает кластер на использование и принудительное применение RBAC (role-based access control). Убедитесь, что сетевой плагин Pod поддерживает RBAC, а также все манифесты, которые используются для деплоя.

Если планируется использовать в кластере IPv6 (либо двухстековую, либо одностековую сеть с поддержкой IPv6), убедитесь, что сетевой плагин Pod поддерживает IPv6. Поддержка IPv6 была добавлена в CNI в версии 0.6.0.

Установить дополнение Pod-сети можно с помощью следующей команды на узле плоскости управления или узле, имеющем учетные данные kubeconfig:


    kubectl apply -f <add-on.yaml>

На один кластер можно установить только одну Pod-сеть. После установки Pod-сети необходимо убедиться в ее работоспособности. Следует проверить, что CoreDNS Pod запущен в выводе kubectl get pods —all-namespaces. Когда CoreDNS Pod заработает, можно продолжить присоединение узлов.

Если сеть не работает или CoreDNS не находится в состоянии Running, ознакомьтесь с руководством по устранению неисправностей для kubeadm.

Docker и cri-dockerd

Подход к инициализации кластера через Docker + cri-dockerd сейчас устарел, но важно рассказать про эту возможность. Как это делать для Docker + cri-dockerd, расскажем чуть дальше. Инициализация кластера проводится одной командой:


    kubeadm init --pod-network-cidr=10.244.0.0/16

Здесь в параметре —pod-network-cidr указываем IP-подсеть, которая будет использоваться подами. Конкретный диапазон 10.244.0.0/16 выбран таким образом, чтобы совпадать с диапазоном по умолчанию для сетевого плагина flannel, который установим далее.

Как отмечалось выше, сейчас этот блок приводится в формате исторической справки. Для варианта с Docker + cri-dockerd рассмотренную ранее команду нужно изменить:


    kubeadm init \
               --pod-network-cidr=10.244.0.0/16 \
               --cri-socket unix:///var/run/cri-dockerd.sock

Добавим параметр:


    --cri-socket

Он нужен, чтобы указать, через какой Unix сокет Kubernetes должен общаться с контейнерным движком. Для cri-o или containerd так не делали, поскольку доступный сокет был только один, и kubeadm об этом знал. Связка Docker + cri-dockerd создает на узле два сокета: один для Docker, а второй для cri-dockerd, поэтому Kubernetes требуется явно указать, какой из них использовать.

Настройка CNI

Перед тем, как начать запускать в кластере приложения, нужно выполнить настройку Container Network Interface («сетевой интерфейс контейнера» или CNI). CNI нужен для настройки взаимодействия и управления контейнерами внутри кластера.

Существует много плагинов для создания CNI. В данном примере применяется Flannel, так как это наиболее простое и проверенное решение. Однако, не меньшей популярностью пользуются плагины Weave Net от компании Weaveworks и Calico (Project Calico), обладающие более широким функционалом и возможностями сетевых настроек.

Чтобы установить Flannel, выполните в терминале команду:


    kubectl apply -f 

Kubernetes 1.28 поддерживает плагины Container Network Interface (CNI) для организации сети кластера. Вы должны использовать плагин CNI, совместимый с вашим кластером и отвечающий вашим потребностям. В широкой экосистеме Kubernetes доступны различные плагины (как с открытым, так и с закрытым исходным кодом).

Плагин CNI необходим для реализации сетевой модели Kubernetes.

Вы должны использовать плагин CNI, совместимый со спецификацией CNI версии v0.4.0 или более поздней. Проект Kubernetes рекомендует использовать плагин, совместимый со спецификацией CNI v1.0.0 (плагины могут быть совместимы с несколькими версиями спецификации).

Добавление node (узлов) в кластер

Перед добавлением новой ноды в кластер Kubernetes нужно проверить, возможно данный хост уже добавлен в кластер. Если это так, то на хосте уже установлены два компонента: kubelet и kubeproxy. Проверить это можно командой:


    systemctl status kubelet.service

В ответ команда вернет либо ошибку (если kubelet не установлен), либо статус службы kubelet.

Предположим, что kubelet на машине установлен. Это может говорить о том, что машина уже является нодой кластера. Параметры кластера Kubernetes, к которому принадлежит машина, хранятся в конфигурационном файле:


    /var/lib/kubelet/config.yaml 

Если хост не добавлен в кластер, нужно сгенерировать команду присоединения ноды. Для этого на control plane ноде Kubernetes пропишем команду:


    kubeadm token create --print-join-command

Команда генерирует временный токен и команду присоединения Worker ноды к кластеру. Готовая команда присоединения имеет вид:


    kubeadm join <kubeAPI URL > --token <token> 
--discovery-token-ca-cert-hash sha256:<hash>

Теперь переключитесь на ваш хост и выполните команду присоединения рабочей (Worker) ноды к кластеру Kubernetes:


    sudo kubeadm join

Выведите на control plane ноде список текущих нод кластера. Проверим, чтобы новый хост был добавлен в кластер Kubernetes:


    kubectl get node

Получение токена авторизации кластера (<token>)

Порядок действий лучше соблюдать такой.

  • Подключиться к серверу через SSH.
  • Запустить команду, которая присутствовала на выводе команды «kubeadm init». Например:

    kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>
  • Если токен отсутствует, его можно получить, выполнив команду на мастер-ноде:

    kubeadm token list
  • По умолчанию, срок действия токена — 24 часа. Если требуется добавить новый узел в кластер по окончанию этого периода, можно создать новый токен следующей командой:

    kubeadm token create
  • Результат будет такого вида:

    5didvk.d09sbcov8ph2amjw

Если значение параметра —discovery-token-ca-cert-has неизвестно, то его можно получить такой командой:


    openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'

Получится подобный вывод:


    8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78

Для ввода IPv6-адреса в параметр «<control-plane-host>:<control-plane-port>», адрес должен быть заключен в квадратные скобки. Например:


    [fd00::101]:2073
  • Через пару секунд, нода должна появиться в выводе команды:

    kubectl get nodes

Проверка работоспособности кластера

Проверяем, насколько совпадает версия клиента и сервера, чтобы не получить несовместимость функциональности при дальнейшей работе:


    kubectl get version

Теперь смотрим основные ресурсы нашего кластера:


    kubectl cluster-info 

Обращаем внимание на ip-адрес, порт, состояние CoreDNS в кластере:


    kubectl get cs -A

Получаем статус основых компонентов K8s. Оценим состояние наших нод, подов, а также их статус. Выполним команды:


    kubectl get nodes -A -owide
kubectl get pods -owide

Здесь обращаем внимание на время жизни и количество рестартов подов: частые рестарты могут свидетельствовать о проблемах в кластере.

Посмотрим на события в кластере за последнее время:


    kubectl get events -owide

В выводе этой команды обращаем внимание на то:

  • какие поды разворачивались и когда,
  • были ли проблемы с хелсчеками,
  • не заходил ли oom-киллер и т. п.

При установленном metrics-server также можно посмотреть на его нагрузку в кластере:


    kubectl top nodes
kubectl top pods -A

Оценив состояние кластера, перейдем к просмотру состояния всех компонентов.

Оцениваем состояние компонентов k8s

Посмотрим на работу сердца нашего кластера — etcd. Для этого обратимся к логам пода (или юнита):


    kubectl logs -n kube-system etcd-cluster-m1 --follow --tail 1000
  • не отваливаются ли реплики,
  • нет ли троттлинга,
  • время сжатия данных.

Здесь уже могут вскрыться признаки проблем с производительностью дисков и сети. Если компоненты K8s стоят на машинах, можно посмотреть логи юнитов:


    journalctl -u etcd -n 1000 --follow

То же самое делаем и с компонентами Kubernetes. Cмотрим:

  • логи kube-apiserver,
  • kube-scheduler,
  • kube-controller-manager.

Не забываем заглянуть и в логи kubelet на самих воркерах. Скорее всего, на этих этапах уже встретятся ошибки. Тут могут вскрыться и признаки проблем с сетью, средой запуска контейнеров, валидностью сертификатов, частой сменой лидеров шедулера и контроллера K8s и т. п. На этом этапе необходимо оценить их критичность и частоту.

Изучение работы компонентов может занять какое-то время, но в итоге это поможет лучше понять общее состояние кластера.

Не упускаем из виду и функционирование сети в самом кластере. У нас в кластерах в качестве CNI используется calico, так что покажу на его примере. Смотрим логи с подов calico. Обращаем внимание на частое изменение маршрутов и пересечения имен.


    kubectl logs -n kube-system calico-kube-controllers-755d84984b-qq9t2 --follow --tail 100
kubectl logs -n kube-system calico-node-pf6sv --follow --tail 1000

Также можно поставить утилиту calicoctl и быстренько посмотреть состояние с ее помощью. Запустить ее можно через под или исполняемый файл. Главное — обеспечить аналогичную установленной версию calicoctl.

Устанавливаем версию в кластер:


    kubectl apply -f https://docs.projectcalico.org/archive/v3.19/manifests/calicoctl.yaml
kubectl exec -ti -n kube-system calicoctl -- calicoctl get nodes -o wide
kubectl exec -ti -n kube-system calicoctl -- calicoctl get bgpPeer -o wide

Также можем использовать ту же утилиту со своей машины:


    calicoctl get nodes 
calicoctl get BGPpers

Можно измерить скорость сети между самими подами, например, утилитой iperf. Это также касается подов, размещенных на разных машинах.

Тестирование кластера на соответствие требованиям CNCF

Стандарт CNCF позволяет обеспечить ожидаемое поведение от кластера. 

Определим, имеет ли наш кластер стандартные настройки. Для этого обратимся к утилите Sonobuoy: мы используем ее для тестирования своих сборок K8s.

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

Определяемся с версией, которая поддерживает релиз нашего кластера. В данном случае скачаем последнюю версию программы.

Запустим проверку нашего кластера стандартными тестами:


    sonobuoy run

Если хотим ожидать завершения, можно использовать ключ —wait. Проверка кластера занимает около полутора часов. Смотреть прогресс тестирования можно командой:


    sonobuoy status

По завершении скачиваем архив с отчетом и смотрим ошибки:


    results=$(sonobuoy retrieve)
sonobuoy results $results

Вот один из примеров:


    [sig-api-machinery] AdmissionWebhook [Privileged:ClusterAdmin] should be able to deny attaching pod [Conformance]
[sig-api-machinery] AdmissionWebhook [Privileged:ClusterAdmin] should deny crd creation [Conformance]
[sig-api-machinery] CustomResourcePublishOpenAPI [Privileged:ClusterAdmin] works for CRD with validation schema [Conformance]
[sig-api-machinery] CustomResourcePublishOpenAPI [Privileged:ClusterAdmin] works for CRD without validation schema [Conformance]
[sig-cli] Kubectl client Guestbook application should create and stop a working application  [Conformance]
[sig-network] DNS should provide DNS for pods for Subdomain [Conformance]
[sig-network] Ingress API should support creating Ingress API operations [Conformance]

Следующей командой можно более подробно посмотреть на проблемы:


    sonobuoy results $results --mode detailed | jq '. | select(.status == "failed") | .details'

Для соответствия рекомендациям нам пришлось поправить параметры запуска компонентов K8s, внести изменения в настройку ingress и API кластера. После устранения неисправности, чтобы не ждать прохождения полного теста, можно запустить только конкретный:


    sonobuoy run --e2e-focus "Ingress API should support creating Ingress API operations" --e2e-skip "" --wait

Теперь у нас на руках есть базовое представление о состоянии нашего кластера. Дальше при желании можно углубиться в работу самих компонентов, обратиться к метрикам из prometheus-operator, устроить тест etcd, балансировщика и проверить iops на сторадже. Главное – четко понимать, что вы хотите получить в итоге.

Сравнение Kubernetes и Docker

Сравнивать напрямую Kubernetes и Docker Swarm в 2023 уже не совсем честно. Kubernetes развился до несущего решения в тысячах приложений, а Docker Swarm остается достаточно локальным, но по-своему полезным решением. Это как сравнивать автомобили и двигатели. Только приняв этот момент, можно подойти к сравнению.

Оба оркестратора имеют свою специфику, сильные и слабые стороны, поэтому выбирать решение нужно, исходя из целей проекта.

Kubernetes для разработчиков

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

Экосистема и сообщество Kubernetes

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

Согласно отчету VMware State of Kubernetes 2022, в 2020-м 30% организаций использовали пять или менее кластеров, и всего 15% работали с 50-ю кластерами или более. В 2021-м эти цифры почти не изменились — в отличие от прошлого года, по итогам которого доля компаний с малым числом кластеров сократилась до 12%, а доля тех, у кого их больше 50-и, выросла до 29%.

Что такое KubeCon

Мы рассмотрели все основные понятия, необходимые для изучения Kubernetes. Кроме этого, вы можете посмотреть ежегодные рекапы KubeCon. Это событие считается самым знаковым в мире контейнеров и оркестраторов с момента первой конференции в 2015 году. KubeCon стал важным мероприятием для сообщества Cloud Native-технологий.

Заключение

Технология Kubernetes получает все большее распространение как у больших компаний, так и в среде стартапов. Особенно среди тех, что работают с ML-моделями и нейросетями. Решение позволяет автоматизировать многие процессы, которые ранее приходилось делать вручную. Например, поднимать контейнеры, которые перестали работать или интегрировать GPU. 

Kubernetes как оркестратор доказал свое превосходство, работая в самых разных сервисах и в самой разнообразной архитектуре, поэтому использовать аналоги сегодня — это скорее узкоспециальный выбор, чем следование концепции Cloud Native в чистом виде. 

Несмотря на относительно высокий порог входа, для реализации K8s в своих проектах, можно использовать Managed-подход и делегировать большую часть процессов DevOps-инженерам провайдера, которые каждый день сталкиваются с подобными задачами, поэтому знают, как выиграть здесь время и предоставить отказоустойчивую платформу.