Управление объектами Kubernetes
В инструменте командной строки kubectl есть несколько разных способов создания и управления объектами Kubernetes. На этой странице рассматриваются различные подходы. Изучите документацию по Kubectl для получения подробной информации по управлению объектами с помощью Kubectl.
Способы управления
Предупреждение: Используйте только один способ для управления объектами Kubernetes. Применение нескольких методов управления к одному и тому же объекту может привести к неопределенному поведению.
| Способ управления | Область применения | Рекомендуемое окружение | Количество поддерживаемых авторов | Трудность изучения |
|---|---|---|---|---|
| Императивные команды | Активные объекты | Проекты в стадии разработки | 1+ | Низкая |
| Императивная конфигурация объекта | Отдельные файлы | Продакшен-проекты | 1 | Средняя |
| Декларативная конфигурация объекта | Директории или файлы | Продакшен-проекты | 1+ | Сложная |
Императивные команды
При использовании императивных команд пользователь работает непосредственно с активными (текущими) объектами в кластере. Пользователь указывает выполняемые операции команде kubectl в качестве аргументов или флагов.
Это самый простой способ начать или выполнять одноразовые задачи в кластере. Из-за того, что происходит работа с активными объектами напрямую, нет возможности посмотреть историю предыдущих конфигураций.
Примеры
Запустите экземпляр контейнера nginx, посредством создания объекта Deployment:
kubectl run nginx --image nginx
То же самое, но с другим синтаксисом:
kubectl create deployment nginx --image nginx
Плюсы и минусы
Преимущества по сравнению с конфигурацией объекта:
- Простые команды, которые легко выучить и запомнить.
- Для применения изменений в кластер нужно только выполнить команды.
Недостатки по сравнению с конфигурацией объекта:
- Команды не интегрированы с процессом проверки (обзора) изменений.
- У команд нет журнала с изменениями.
- Команды не дают источник записей, за исключением активных объектов.
- Команды не содержат шаблон для создания новых объектов.
Императивная конфигурация объекта
В случае использования императивной конфигурации объекта команде kubectl устанавливают действие (создание, замена и т.д.), необязательные флаги и как минимум одно имя файла. Файл должен содержать полное определение объекта в формате YAML или JSON.
Посмотрите Справочник API для получения более подробной информации про определения объекта.
Предупреждение: Императивная команда replace заменяет существующую спецификацию новой (переданной), удаляя все изменения в объекте, которые не определены в конфигурационном файле. Такой подход не следует использовать для типов ресурсов, спецификации которых обновляются независимо от конфигурационного файла. Например, поле externalIPs в сервисах типа LoadBalancer обновляется кластером независимо от конфигурации.
Примеры
Создать объекты, определенные в конфигурационном файле:
kubectl create -f nginx.yaml
Удалить объекты, определенные в двух конфигурационных файлах:
kubectl delete -f nginx.yaml -f redis.yaml
Обновить объекты, определенные в конфигурационном файле, перезаписав текущую конфигурацию:
kubectl replace -f nginx.yaml
Плюсы и минусы
Преимущества по сравнению с императивными командами:
- Конфигурация объекта может храниться в системе управления версиями, такой как Git.
- Конфигурация объекта может быть интегрирована с процессами проверки изменений и логирования.
- Конфигурация объекта предусматривает шаблон для создания новых объектов.
Недостатки по сравнению с императивными командами:
- Конфигурация объекта требует наличие общего представления об схеме объекта.
- Конфигурация объекта предусматривает написание файла YAML.
Преимущества по сравнению с декларативной конфигурацией объекта:
- Императивная конфигурация объекта проще и легче для понимания.
- Начиная с Kubernetes 1.5, конфигурация императивных объектов стала лучше и совершеннее.
Недостатки по сравнению с декларативной конфигурацией объекта:
- Императивная конфигурация объекта наилучшим образом работает с файлами, а не с директориями.
- Обновления текущих объектов должны быть описаны в файлах конфигурации, в противном случае они будут потеряны при следующей замене.
Декларативная конфигурация объекта
При использовании декларативной конфигурации объекта пользователь работает с локальными конфигурационными файлами объекта, при этом он не определяет операции, которые будут выполняться над этими файлами. Операции создания, обновления и удаления автоматически для каждого объекта определяются kubectl . Этот механизм позволяет работать с директориями, в ситуациях, когда для разных объектов может потребоваться выполнение других операций.
Примечание: Декларативная конфигурация объекта сохраняет изменения, сделанные другими, даже если эти изменения не будут зафиксированы снова в конфигурационный файл объекта. Это достигается путем использования API-операции patch , чтобы записать только обнаруженные изменения, а не использовать для этого API-операцию replace , которая полностью заменяет конфигурацию объекта.
Примеры
Обработать все конфигурационные файлы объектов в директории configs и создать либо частично обновить активные объекты. Сначала можно выполнить diff , чтобы посмотреть, какие изменения будут внесены, и только после этого применить их:
kubectl diff -f configs/ kubectl apply -f configs/
Рекурсивная обработка директорий:
kubectl diff -R -f configs/ kubectl apply -R -f configs/
Плюсы и минусы
Преимущества по сравнению с императивной конфигурацией объекта:
- Изменения, внесенные непосредственно в активные объекты, будут сохранены, даже если они не отражены в конфигурационных файлах.
- Декларативная конфигурация объекта лучше работает с директориями и автоматически определяет тип операции (создание, частичное обновление, удаление) каждого объекта.
Недостатки по сравнению с императивной конфигурацией объекта:
- Декларативную конфигурацию объекта сложнее отладить и понять, когда можно получить неожиданные результаты.
- Частичные обновления с использованием различий приводит к сложным операциям слияния и исправления.
Что дальше
- Управление объектами Kubernetes с помощью императивных команд
- Управление объектами Kubernetes с помощью императивной конфигурации объекта
- Управление объектами Kubernetes с помощью декларативной конфигурации объекта
- Управление объектами Kubernetes с помощью Kustomize (декларативный способ)
- Справочник по командам Kubectl
- Документация Kubectl
- Справочник API Kubernetes
Обратная связь
Эта страница была полезна?
Спасибо за обратную связь! Если у вас есть конкретный вопрос об использовании Kubernetes, спросите на Stack Overflow. Создайте issue в репозитории GitHub, если вы хотите сообщить о проблеме или предложить улучшение.
Архитектура для сбора логов
Логи помогают понять, что происходит внутри приложения. Они особенно полезны для отладки проблем и мониторинга деятельности кластера. У большинства современных приложений имеется тот или иной механизм сбора логов. Контейнерные движки в этом смысле не исключение. Самый простой и наиболее распространенный метод сбора логов для контейнерных приложений задействует потоки stdout и stderr .
Однако встроенной функциональности контейнерного движка или среды исполнения обычно недостаточно для организации полноценного решения по сбору логов.
Например, может возникнуть необходимость просмотреть логи приложения при аварийном завершении работы Pod’а, его вытеснении (eviction) или «падении» узла.
В кластере у логов должно быть отдельное хранилище и жизненный цикл, не зависящий от узлов, Pod’ов или контейнеров. Эта концепция называется сбор логов на уровне кластера.
Архитектуры для сбора логов на уровне кластера требуют отдельного бэкенда для их хранения, анализа и выполнения запросов. Kubernetes не имеет собственного решения для хранения такого типа данных. Вместо этого существует множество продуктов для сбора логов, которые прекрасно с ним интегрируются. В последующих разделах описано, как обрабатывать логи и хранить их на узлах.
Основы сбора логов в Kubernetes
В примере ниже используется спецификация Pod с контейнером для отправки текста в стандартный поток вывода раз в секунду.
apiVersion: v1 kind: Pod metadata: name: counter spec: containers: - name: count image: busybox:1.28 args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
Запустить его можно с помощью следующей команды:
kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml
Результат будет таким:
pod/counter created
Получить логи можно с помощью команды kubectl logs , как показано ниже:
kubectl logs counter
Результат будет таким:
0: Mon Jan 1 00:00:00 UTC 2001 1: Mon Jan 1 00:00:01 UTC 2001 2: Mon Jan 1 00:00:02 UTC 2001 .
Команда kubectl logs —previous позволяет извлечь логи из предыдущего воплощения контейнера. Если в Pod’е несколько контейнеров, выбрать нужный для извлечения логов можно с помощью флага -c :
kubectl logs counter -c count
Для получения дополнительной информации см. документацию по kubectl logs .
Сбор логов на уровне узла

Среда исполнения для контейнера обрабатывает и перенаправляет любой вывод в потоки stdout и stderr приложения. Docker Engine, например, перенаправляет эти потоки драйверу журналирования, который в Kubernetes настроен на запись в файл в формате JSON.
Примечание: JSON-драйвер Docker для сбора логов рассматривает каждую строку как отдельное сообщение. В данном случае поддержка многострочных сообщений отсутствует. Обработка многострочных сообщений должна выполняться на уровне лог-агента или выше.
По умолчанию, если контейнер перезапускается, kubelet сохраняет один завершенный контейнер с его логами. Если Pod вытесняется с узла, все соответствующие контейнеры также вытесняются вместе с их логами.
Важным моментом при сборе логов на уровне узла является их ротация, чтобы логи не занимали все доступное место на узле. Kubernetes не отвечает за ротацию логов, но способен развернуть инструмент для решения этой проблемы. Например, в кластерах Kubernetes, развертываемых с помощью скрипта kube-up.sh , имеется инструмент logrotate , настроенный на ежечасный запуск. Также можно настроить среду исполнения контейнера на автоматическую ротацию логов приложения.
Подробную информацию о том, как kube-up.sh настраивает логирование для образа COS на GCP, можно найти в соответствующем скрипте configure-helper .
При использовании среды исполнения контейнера CRI kubelet отвечает за ротацию логов и управление структурой их директории. kubelet передает данные среде исполнения контейнера CRI, а та сохраняет логи контейнера в указанное место. С помощью параметров containerLogMaxSize и containerLogMaxFiles в конфигурационном файле kubelet’а можно настроить максимальный размер каждого лог-файла и максимальное число таких файлов для каждого контейнера соответственно.
При выполнении команды kubectl logs (как в примере из раздела про основы сбора логов) kubelet на узле обрабатывает запрос и считывает данные непосредственно из файла журнала. Затем он возвращает его содержимое.
Примечание: Если ротацию выполнила внешняя система или используется среда исполнения контейнера CRI, команде kubectl logs будет доступно содержимое только последнего лог-файла. Например, имеется файл размером 10 МБ, logrotate выполняет ротацию, и получается два файла: первый размером 10 МБ, второй — пустой. В этом случае kubectl logs вернет второй лог-файл (пустой).
Логи системных компонентов
Существует два типа системных компонентов: те, которые работают в контейнере, и те, которые работают за пределами контейнера. Например:
- планировщик Kubernetes и kube-proxy выполняются в контейнере;
- kubelet и среда исполнения контейнера работают за пределами контейнера.
На машинах с systemd среда исполнения и kubelet пишут в journald. Если systemd отсутствует, среда исполнения и kubelet пишут в файлы .log в директории /var/log . Системные компоненты внутри контейнеров всегда пишут в директорию /var/log , обходя механизм ведения логов по умолчанию. Они используют библиотеку для сбора логов klog . Правила сбора логов и рекомендации можно найти в соответствующей документации.
Как и логи контейнеров, логи системных компонентов в директории /var/log необходимо ротировать. В кластерах Kubernetes, созданных с помощью скрипта kube-up.sh , эти файлы настроены на ежедневную ротацию с помощью инструмента logrotate или при достижении 100 МБ.
Архитектуры для сбора логов на уровне кластера
Kubernetes не имеет собственного решения для сбора логов на уровне кластера, но есть общие подходы, которые можно рассмотреть. Вот некоторые из них:
- использовать агент на уровне узлов (запускается на каждом узле);
- внедрить в Pod с приложением специальный sidecar-контейнер для сбора логов;
- отправлять логи из приложения непосредственно в бэкенд.
Использование агента на уровне узлов

Сбор логов на уровне кластера можно реализовать, запустив node-level-агент на каждом узле. Лог-агент — это специальный инструмент, который предоставляет доступ к логам или передает их бэкенду. Как правило, лог-агент представляет собой контейнер с доступом к директории с файлами логов всех контейнеров приложений на этом узле.
Поскольку лог-агент должен работать на каждом узле, рекомендуется запускать его как DaemonSet .
Сбор логов на уровне узла предусматривает запуск одного агента на узел и не требует изменений в приложениях, работающих на узле.
Контейнеры пишут в stdout и stderr , но без согласованного формата. Агент на уровне узла собирает эти логи и направляет их на агрегацию.
Сбор логов с помощью sidecar-контейнера с лог-агентом
Sidecar-контейнер можно использовать одним из следующих способов:
- sidecar-контейнер транслирует логи приложений на свой собственный stdout ;
- в sidecar-контейнере работает агент, настроенный на сбор логов из контейнера приложения.
Транслирующий sidecar-контейнер

Настроив sidecar-контейнеры на вывод в их собственные потоки stdout и stderr , можно воспользоваться преимуществами kubelet и лог-агента, которые уже работают на каждом узле. Sidecar-контейнеры считывают логи из файла, сокета или journald. Затем каждый из них пишет логи в собственный поток stdout или stderr .
Такой подход позволяет разграничить потоки логов от разных частей приложения, некоторые из которых могут не поддерживать запись в stdout или stderr . Логика, управляющая перенаправлением логов, проста и не требует значительных ресурсов. Кроме того, поскольку stdout и stderr обрабатываются kubelet’ом, можно использовать встроенные инструменты вроде kubectl logs .
Предположим, к примеру, что в Pod’е работает один контейнер, который пишет логи в два разных файла в двух разных форматах. Вот пример конфигурации такого Pod’а:
apiVersion: v1 kind: Pod metadata: name: counter spec: containers: - name: count image: busybox:1.28 args: - /bin/sh - -c - > i=0; while true; do echo "$i: $(date)" >> /var/log/1.log; echo "$(date) INFO $i" >> /var/log/2.log; i=$((i+1)); sleep 1; done volumeMounts: - name: varlog mountPath: /var/log volumes: - name: varlog emptyDir: <>
Не рекомендуется писать логи разных форматов в один и тот же поток, даже если удалось перенаправить оба компонента в stdout контейнера. Вместо этого можно создать два sidecar-контейнера. Каждый из них будет забирать определенный лог-файл с общего тома и перенаправлять логи в свой stdout .
Вот пример конфигурации Pod’а с двумя sidecar-контейнерами:
apiVersion: v1 kind: Pod metadata: name: counter spec: containers: - name: count image: busybox:1.28 args: - /bin/sh - -c - > i=0; while true; do echo "$i: $(date)" >> /var/log/1.log; echo "$(date) INFO $i" >> /var/log/2.log; i=$((i+1)); sleep 1; done volumeMounts: - name: varlog mountPath: /var/log - name: count-log-1 image: busybox:1.28 args: [/bin/sh, -c, 'tail -n+1 -F /var/log/1.log'] volumeMounts: - name: varlog mountPath: /var/log - name: count-log-2 image: busybox:1.28 args: [/bin/sh, -c, 'tail -n+1 -F /var/log/2.log'] volumeMounts: - name: varlog mountPath: /var/log volumes: - name: varlog emptyDir: <>
Доступ к каждому потоку логов такого Pod’а можно получить отдельно, выполнив следующие команды:
kubectl logs counter count-log-1
Результат будет таким:
0: Mon Jan 1 00:00:00 UTC 2001 1: Mon Jan 1 00:00:01 UTC 2001 2: Mon Jan 1 00:00:02 UTC 2001 .
kubectl logs counter count-log-2
Результат будет таким:
Mon Jan 1 00:00:00 UTC 2001 INFO 0 Mon Jan 1 00:00:01 UTC 2001 INFO 1 Mon Jan 1 00:00:02 UTC 2001 INFO 2 .
Агент на уровне узла, установленный в кластере, подхватывает эти потоки логов автоматически без дополнительной настройки. При желании можно настроить агент на парсинг логов в зависимости от контейнера-источника.
Обратите внимание: несмотря на низкое использование процессора и памяти (порядка нескольких milliCPU для процессора и пары мегабайт памяти), запись логов в файл и их последующая потоковая передача в stdout может вдвое увеличить нагрузку на диск. Если приложение пишет в один файл, рекомендуется установить /dev/stdout в качестве адресата, нежели использовать подход с транслирующим контейнером.
Sidecar-контейнеры также можно использовать для ротации файлов логов, которые не могут быть ротированы самим приложением. В качестве примера можно привести небольшой контейнер, периодически запускающий logrotate . Однако рекомендуется использовать stdout и stderr напрямую, а управление политиками ротации и хранения оставить kubelet’у.
Sidecar-контейнер с лог-агентом

Если лог-агент на уровне узла недостаточно гибок для ваших потребностей, можно создать sidecar-контейнер с отдельным лог-агентом, специально настроенным на работу с приложением.
Примечание: Работа лог-агента в sidecar-контейнере может привести к значительному потреблению ресурсов. Более того, доступ к этим журналам с помощью kubectl logs будет невозможен, поскольку они не контролируются kubelet’ом.
Ниже приведены два файла конфигурации sidecar-контейнера с лог-агентом. Первый содержит ConfigMap для настройки fluentd.
apiVersion: v1 kind: ConfigMap metadata: name: fluentd-config data: fluentd.conf: | type tail format none path /var/log/1.log pos_file /var/log/1.log.pos tag count.format1 type tail format none path /var/log/2.log pos_file /var/log/2.log.pos tag count.format2 type google_cloud
Примечание: За информацией о настройке fluentd обратитесь к его документации.
Второй файл описывает Pod с sidecar-контейнером, в котором работает fluentd. Pod монтирует том с конфигурацией fluentd.
apiVersion: v1 kind: Pod metadata: name: counter spec: containers: - name: count image: busybox:1.28 args: - /bin/sh - -c - > i=0; while true; do echo "$i: $(date)" >> /var/log/1.log; echo "$(date) INFO $i" >> /var/log/2.log; i=$((i+1)); sleep 1; done volumeMounts: - name: varlog mountPath: /var/log - name: count-agent image: registry.k8s.io/fluentd-gcp:1.30 env: - name: FLUENTD_ARGS value: -c /etc/fluentd-config/fluentd.conf volumeMounts: - name: varlog mountPath: /var/log - name: config-volume mountPath: /etc/fluentd-config volumes: - name: varlog emptyDir: <> - name: config-volume configMap: name: fluentd-config
В приведенных выше примерах fluentd можно заменить на другой лог-агент, считывающий данные из любого источника в контейнере приложения.
Прямой доступ к логам из приложения

Сбор логов приложения на уровне кластера, при котором доступ к ним осуществляется напрямую, выходит за рамки Kubernetes.
Обратная связь
Эта страница была полезна?
Спасибо за обратную связь! Если у вас есть конкретный вопрос об использовании Kubernetes, спросите на Stack Overflow. Создайте issue в репозитории GitHub, если вы хотите сообщить о проблеме или предложить улучшение.
Kubernetes: большой обзор технологии, установка и настройка
Что такое Kubernetes (K8s): архитектура и основные компоненты, работа с кластерами в контейнерах.

Kubernetes за несколько лет прошел большой путь от проекта небольшой команды из Google до первого выпускника CNCF и надежды всего сообщества разработчиков облачно-ориентированных приложений. Так получилось не за один день, а по сумме накопившихся предпосылок и решений.
С развитием технологий все больше ожиданий стали ложиться на бизнес. Появлялись стриминги, крупные EdTech и FinTech проекты со своей спецификой. Пользователи ждали, что сервисы будут не только быстро загружать контент и проводить транзакции, но также будут обладать высокой доступностью. В это же время нужно было оптимизировать те решения, что уже были на рынке, например, контейнеры.
Что представляет собой контейнеризация
Контейнеризация — это процесс развертывания программного обеспечения, который собирает в одну сущность код приложения, среды разработки, все файлы и библиотеки, необходимые для запуска в любой инфраструктуре.
До изобретения контейнеров, чтобы запустить на локальной машине приложение, нужно было найти определенную версию под конкретную операционную систему, а также потратить время на отладку окружения. Контейнеризация приложений создала более универсальный подход, который организовал гибкую работу на всех устройствах.
Контейнеризацию можно рассматривать как усовершенствованный вариант виртуальной машины. Только с максимальной изоляцией в рамках одной ОС. В отличие от обычной ВМ, контейнер не связан с базовой аппаратной инфраструктурой и может легко переноситься между облаками и несколькими ОС.
Преимущества контейнеризации
- Простота и гибкость развертывания приложений относительно работы с ВМ.
- CI/CD с возможностью моментально откатить апдейты.
- Разделение приложений на изолированные микросервисы с гибким развертыванием и управлением.
- Создание контейнеров приложений в процессе сборки/релиза и отделение приложения от конкретного железа.
- Среды разработки и тестирования на сервере и в локальных машинах не отличаются.
С одной стороны, еще в конце нулевых многие понимали, что за контейнеризацией приложений будущее. С другой — работа с контейнерами имела высокий порог входа, поэтому не могла использоваться повсеместно. Кому-то не хватало команды, кому-то ресурсов. Контейнеры было сложно масштабировать, были вопросы к управлению и безопасности. Конечно, для определенного процента компаний контейнеризация была просто излишней из-за простой архитектуры приложений.
Решением для оптимизации работы с контейнерами стали оркестраторы. Одним из первых таких решений был Apache Mesos, выпущенный еще в 2009 году. Kubernetes появится только в 2014, но обо всем по порядку.
Что такое Kubernetes и как он работает
Kubernetes (K8s) — это программная платформа для автоматического управления контейнеризованными приложениями. 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 (узлы). Это физические или виртуальные машины, на которых развертываются и запускаются контейнеры с приложениями. Каждый узел содержит сервисы, необходимые для запуска подов.
Обычно в кластере есть несколько узлов, но в среде обучения или среде с ограниченными ресурсами можно использовать один.
Готовые кластеры Kubernetes с GPU
Создайте за несколько кликов.
Типы нод
- 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 Взрывной рост не мог пройти без последствий: 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
Есть один деплоймент, в котором запущен единственный экземпляр приложения. Этот экземпляр работает в контейнере на узле кластера.
Запуск сервиса вручную через Replication Controller
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 как бекенд.
conf% /opt/bin/kubectl expose rc nginx —port=80 —target-port=80 —service-name=nginx-http -s «http://192.168.0.10:8080»
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.
Сначала почистим кластер:
Можем приступать к написанию конфигов.
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.
Можно заметить, что при использовании конфига за одним сервисом могут быть закреплены несколько портов.
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
Установка сетевого дополнения 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
На один кластер можно установить только одну 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 --token --discovery-token-ca-cert-hash sha256:
Теперь переключитесь на ваш хост и выполните команду присоединения рабочей (Worker) ноды к кластеру Kubernetes:
sudo kubeadm join
Выведите на control plane ноде список текущих нод кластера. Проверим, чтобы новый хост был добавлен в кластер Kubernetes:
kubectl get node
Дополнительные настройки
О том, как создать кластер в Managed Kubernetes, читайте в нашей инструкции.
Получение токена авторизации кластера ()
Порядок действий лучше соблюдать такой.
- Подключиться к серверу через SSH.
- Запустить команду, которая присутствовала на выводе команды «kubeadm init». Например:
kubeadm join --token : --discovery-token-ca-cert-hash sha256:
- Если токен отсутствует, его можно получить, выполнив команду на мастер-ноде:
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-адреса в параметр «:», адрес должен быть заключен в квадратные скобки. Например:
[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 каждый год презентует роадмэп продуктов и решений, рекомендованных и активно развивающихся в соответствии с философией облачных сервисов. Подробнее о трендах на 2023 год читайте в этом материале.
Экосистема и сообщество 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-инженерам провайдера, которые каждый день сталкиваются с подобными задачами, поэтому знают, как выиграть здесь время и предоставить отказоустойчивую платформу.
Резервное копирование в Kubernetes с помощью K8up и Kasten K10 by Veeam
Рассказываем, как настроить бэкапирование Kubernetes с помощью K8up и Kasten K10 by Veeam в объектное хранилище Selectel.

Сегодня обеспечение надежности и доступности данных в Kubernetes — ключевая задача для разработчиков и системных администраторов. Несмотря на высокую степень автоматизации и управления контейнерами, сбои и человеческие ошибки непредсказуемы. Поэтому резервное копирование становится неотъемлемой частью любого приложения.
Меня зовут Филипп, я системный администратор в отделе Data- и ML-продуктов Selectel. В этой статье постараюсь раскрыть, зачем настраивать резервное копирование в Kubernetes, и на простом примере покажу, как это сделать.
Резервное копирование в Kubernetes
Динамичная и распределенная архитектура Kubernetes обязывает использовать резервные копии. Необходимо учитывать состояние каждого контейнера, конфигурации, секрета и блока данных, которые находятся в постоянном хранилище.

Важно отметить, что в Kubernetes управление постоянным хранилищем осуществляется через основные компоненты.
- PVC (Persistent Volume Claim) — это запрос на использование хранилища со стороны приложения или пользователя.
- PV (Persistent Volume) — физическое или логическое хранилище в кластере, которое может быть связано с внешними хранилищами.
- Storage Class — структура, которая определяет, как PV создается.
- CSI(Container Storage Interface) — плагин, который позволяет взаимодействовать с различными внешними хранилищами.
- Внешнее хранилище — облачное или локальное хранилище, где фактически хранятся данные.

Также Kubernetes поддерживает парадигму Infrastructure as code, IaC. Она позволяет автоматизировать и стандартизировать развертывание и управление ресурсами с помощью GitOps. Однако даже в таком случае есть важная деталь, которую нельзя игнорировать: сохранность данных.
Пока ресурсы типа config-map, secret, deployment, service, ingress и другие могут быть воссозданы из кода по IaC, данные в PV восстановить в случае сбоя, удаления или взлома не получится.
Какие есть варианты

Можно придумать разные способы резервного копирования постоянных данных. Это могут быть, например, кастомные скрипты, которые запускаются по расписанию (cron) и создают снапшоты (снимки) самих PV.
При создании снимков PV могут возникнуть проблемы, если во время процесса в базу данных активно записываются данные. Например, снапшот может получиться неполным или поврежденным. Тогда при попытке восстановиться есть риск, что база данных запустится некорректно.
Однако есть сложные системы, которые обеспечивают непрерывное резервное копирование и автоматическое восстановление в случае сбоя. Среди них — Velero.io, Kasten K10, Cohesity, Portworx и другие.
Выбор стратегии резервного копирования будет зависеть от текущей реализации. Например, если ваше высоконагруженное приложение запущено в Managed Kubernetes, а стремительно растущие базы данных — на сетевых дисках, необходимо подумать о том, чтобы резервное копирование не влияло на работоспособность IT-систем.
Например, если основная база данных — PostgreSQL, необходимо подумать о бэкапировании с помощью streaming replication и настроить резервное копирование на secondary-реплике через pg_dump, pg_basebackup, Barman или WAL-E. А также — определиться с периодичностью бэкапирования, его шифрованием, способом хранения, мониторингом и проверкой восстановления из резервных копий.
Далее мы рассмотрим два инструмента K8UP и Kasten K10 от Veeam, которые предоставляют различный функционал для резервного копирования. Но прежде подготовим тестовый стенд в облаке Selectel.
ML-платформа Selectel
Используйте настроенную инфраструктуру для развертывания и обучения ML-моделей.
Подготовка рабочего окружения
Подготовим тестовый стенд, в который установим простейшее приложение с постоянным хранилищем данных. За основу возьмем Managed Kubernetes, а в качестве хранилища резервных копий — объектное хранилище S3, к которому настроим доступ через сервисного пользователя и S3-ключ.
Подготовка кластера Managed Kubernetes
1. В панели управления нужно перейти в раздел Kubernetes:

2. Далее нужно создать и настроить кластер: ввести его имя, выбрать версию Kubernetes, регион, тип и подсеть для нод.

3. После настройки кластера необходимо добавить группы нод:

4. Далее дождитесь статуса ACTIVE и скачайте kubeconfig для дальнейшей работы с кластером:

5. Для работы с кластером можно использовать Lens или Kubectl. Для kubectl необходимо указать переменную KUBECONFIG:
#: export KUBECONFIG=
6. В качестве проверки можно получить пространство имен кластера:
#: kubectl get namespace
Подготовка объектного хранилища
1. В панели управления нужно перейти в раздел Объектное хранилище → Контейнеры:

2. Далее нужно создать и настроить контейнер: ввести его название, выбрать Приватный тип, класс хранения Стандартное хранение и нажать кнопку Создать контейнер.

Создание сервисного пользователя и ключа S3
1. В панели управления нужно перейти в меню Управление пользователями:

2. Далее откройте раздел Сервисные пользователи:

3. Создайте пользователя и настройте данные для доступа к объектному хранилищу в вашем проекте облачной платформы:

4. Последним этапом нужно добавить S3-ключ для доступа к хранилищу:

Важно: S3 access и secret keys необходимо сохранить в надежном месте.
Установка тестового приложения в кластере
Теперь осталось установить в кластер простейшее тестовое приложение. Для этого подготовим манифест создания Storage Class, Deployment и Persistent Volume Claim и применим его:
# nginx-pvc.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: default annotations: storageclass.kubernetes.io/is-default-class: 'true' provisioner: cinder.csi.openstack.org parameters: availability: ru-9a fsType: ext4 type: fast.ru-9a reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: Immediate --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-container image: nginx:latest ports: - containerPort: 80 volumeMounts: - name: nginx-volume mountPath: /usr/share/nginx/html volumes: - name: nginx-volume persistentVolumeClaim: claimName: nginx-pvc
#: kubectl apply -f nginx-pvc.yaml
Готово — теперь можем начать работу с инструментами резервного копирования в Kubernetes.
Резервное копирование на базе K8up
Возможности инструмента
- Автоматическое копирование данных из PVC и БД.
- Запуск резервного копирования по требованию и расписанию.
- Сохранение копий в разных местах, включая Amazon S3 и Minio.
- Восстановление данных через командную строку.
- Возможность создавать резервные копии, которые учитывают особенности приложений и включают результаты работы любого инструмента, способного выдавать данные в стандартный поток вывода.
Установка
Рассмотрим процесс установки и настройки K8up в подготовленном рабочем окружении. Для наглядности представим схему работы инструмента.

1. Устанавливаем Custom Resource Definition:
#: kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.4.1/k8up-crd.yaml
2. Для удобства устанавливаем K8up в отдельное пространство имен:
#: kubectl create namespace k8up #: helm repo add k8up-io https://k8up-io.github.io/k8up #: helm install -n k8up k8up k8up-io/k8up
Настройка хранилища для резервных копий
Перед созданием резервных копий необходимо указать хранилище, в котором они будут храниться. Подробнее о вариантах хранения можно можно почитать в документации restic.
Секреты для доступа по S3
Ранее мы подготовили объектное хранилище. Теперь создадим секреты, чтобы у K8up был к нему доступ. Укажем токен доступа к S3 и пароль для restic-репозитория:
# secrets.yaml apiVersion: v1 kind: Secret metadata: name: "s3-secrets" namespace: k8up stringData: bucket: "" password: ”” username: ”” --- apiVersion: v1 kind: Secret metadata: name: "restic-repository-password" namespace: k8up stringData: password: "secret_pass" # Это пароль для restic repository, создается при инициализации; его можно поменять на любой, желательно надежный и состоящий из более чем 16 символов
Применим описанный манифест в кластер:
#: kubectl apply -f secrets.yaml
Подготовительные работы выполнены, теперь можем приступить к созданию резервных копий.
Создание снимка из PVC
Теперь попробуем сделать бэкап данных приложения, которое мы задеплоили на этапе подготовки рабочего окружения. Для этого необходимо создать Custom Resource для K8up, тем самым объяснить, что и как мы хотим копировать.
Создадим CR-Backup, который сделает резервное копирование всех PVC в пространстве имен, где будет создан данный ресурс, а после — применим манифест:
# backup.yaml apiVersion: k8up.io/v1 kind: Backup metadata: name: k8up-test-swift namespace: k8up spec: failedJobsHistoryLimit: 4 successfulJobsHistoryLimit: 0 backend: repoPasswordSecretRef: name: "restic-repository-password" key: "password" s3: accessKeyIDSecretRef: key: username name: s3-secrets bucket: test endpoint: s3.ru-1.storage.selcloud.ru secretAccessKeySecretRef: key: password name: s3-secrets
#: kubectl apply -f backup.yaml
После создания ресурса K8up автоматически начнет поиск и создание снимков всех PVC с режимами доступа к хранилищу типа RMX (ReadMany, Execute) и RWO (ReadWriteOnce). Если все было выполнено правильно, мы должны увидеть успешно завершенный под с именем, в котором есть приставка backup-k8up.
Приставка означает, что под подмонтировал к себе нужный PVC (в нашем случае — nginx-pvc) и создал снимок файловой системы с помощью restic:
В S3-контейнере можно увидеть, что снимок файловой системы успешно создан с помощью restic. Также появилась папка, которую мы указали в манифесте:


То же самое можно проверить через CLI с помощью команд:
#: kubectl get -A backups.k8up.io #: kubectl get -A snapshots.k8up.io
В K8up также можно настроить резервное копирование по расписанию и добавить проверку целостности с помощью custom-resource — Schedule.
Восстановление из снимка PVC
Локальное восстановление
Можно установить утилиту restic и подмонтировать снимок локально, указав чувствительные данные для доступа к объектному хранилищу. Но прежде необходимо узнать SNAPSHOT ID:
RESTIC_REPOSITORY="s3://s3.ru-1.storage.selcloud.ru//" \ AWS_ACCESS_KEY_ID="" \ AWS_SECRET_ACCESS_KEY="" \ RESTIC_PASSWORD="" \ restic snapshots
Теперь мы можем скопировать к себе резервную копию командой:
RESTIC_REPOSITORY="s3://s3.ru-1.storage.selcloud.ru//" \ AWS_ACCESS_KEY_ID="" \ AWS_SECRET_ACCESS_KEY="" \ RESTIC_PASSWORD="" \ restic restore --target ~/Desktop/mnt/
В папке ~/Desktop/mnt/ можно увидеть все файлы, находящиеся в снимке.
Восстановление в кластере Custom Resource
Для демонстрации восстановления внесем правки в index.html, добавив текст:

Теперь восстановим предыдущее состояние файла в кластере.
- Создадим customResource Restore и новый PVC, в который будем восстанавливать данные:
# restore.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: restore-test-mfw namespace: k8up annotations: # set to "true" to include in future backups k8up.io/backup: "false" spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi --- apiVersion: k8up.io/v1 kind: Restore metadata: name: restore-test-mfw namespace: k8up spec: podSecurityContext: fsGroup: 65532 fsGroupChangePolicy: OnRootMismatch restoreMethod: folder: claimName: restore-test-mfw backend: envFrom: - secretRef: name: "open-stack-secret" repoPasswordSecretRef: name: "restic-repository-password" key: "password" swift: path: "/container-path" container: "cmlp-testing-rpd-5921-ff-research-k8up"
2. В качестве восстановленной PVC можем указать новую, в которую восстановили бэкап:
kubectl patch -n k8up deployment nginx-deployment -p '<"spec":<"template":<"spec":<"volumes":[<"name":"nginx-volume","persistentVolumeClaim":<"claimName":"restore-test-mfw">>]>>>>'
Далее можем открыть index.html и убедиться, что нам удалось откатить изменения.
Создание бэкапа баз данных
Проблема при создании бэкапов баз данных в том, что необходимо остановить запись в базу, чтобы на момент создания снимка не было никаких активных и открытых ячеек. Иначе в резервной копии будут незавершенные операции.
В результате мы пришли к выводу, что делать бэкап базы данных лучше встроенными утилитами — например, pg_dump, mongodump и другими. K8up позволяет нам использовать механизм запуска команд в поде, к которому будут добавлены аннотации.
Добавление аннотаций
Процесс создания аннотаций и их описание есть в документации K8up. Ниже — основные конфигурации для них.
annotations: k8up.io/backupcommand: sh -c 'mongodump --username=$MONGODB_ROOT_USER --password=$MONGODB_ROOT_PASSWORD --archive' k8up.io/file-extension: .archive
Конфигурация аннотации MongoDB.
annotations: k8up.io/backupcommand: sh -c 'PGDATABASE="$POSTGRES_DB" PGUSER="$POSTGRES_USER" PGPASSWORD="$POSTGRES_PASSWORD" pg_dump --clean' k8up.io/file-extension: .sql
Конфигурация аннотации PostgreSQL.
template: metadata: labels: app: my-db annotations: k8up.io/backupcommand: sh -c 'PGDATABASE="$POSTGRES_DB" PGUSER="$POSTGRES_USER" PGPASSWORD="$POSTGRES_PASSWORD" pg_dump --clean' k8up.io/file-extension: .sql k8up.io/backupcommand-container: postgres spec: containers: - name: pgbouncer - name: postgres - name: prometheus-exporter .
Сборка аннотации на определенный контейнер.
Резервное копирование на базе Kasten K10 by Veeam
Kasten K10 создан специально для Kubernetes и представляет собой платформу управления данными Cloud Native для операций «второго дня».
Возможности инструмента
Инструмент предоставляет DevOps-командам простую, масштабируемую и безопасную систему для резервного копирования и восстановления приложений Kubernetes. Kasten K10 можно интегрировать с реляционными и NoSQL-базами данных и основными дистрибутивами Kubernetes.
Важно: бесплатная версия Kasten K10 ограничена пятью нодами.
Установка
PRE-FLIGHT проверки
Проверим наличие всех необходимых компонентов для Kasten K10:
#: curl https://docs.kasten.io/tools/k10_primer.sh | bash
В выводе команды мы увидим, чего не хватает для корректной работы K10. В нашем случае отсутствует CRD для создания снапшотов. Решим эту проблему.
1. Выведем имеющиеся для Volume CRD:
#: kubectl api-resources | grep volume
2. Теперь мы можем установить недостающие CRD и проверить, что они появились в списке api-resources:
#: kubectl apply -f https://raw.githubusercontent.com/selectel/mks-csi-snapshotter/master/deploy/setup-snapshot-controller.yaml
#: kubectl api-resources | grep volume persistentvolumeclaims pvc v1 true PersistentVolumeClaim persistentvolumes pv v1 false PersistentVolume volumesnapshotclasses vsclass,vsclasses snapshot.storage.k8s.io/v1 false VolumeSnapshotClass volumesnapshotcontents vsc,vscs snapshot.storage.k8s.io/v1 false VolumeSnapshotContent volumesnapshots vs snapshot.storage.k8s.io/v1 true VolumeSnapshot volumeattachments storage.k8s.io/v1 false VolumeAttachment
3. Повторно прогоняем проверки PRE-FLIGHT:
#: curl https://docs.kasten.io/tools/k10_primer.sh | bash
Ошибка по CRD-Base пропала, но появилась новая: CSI Provisioner doesn’t have VolumeSnapshotClass — Error. Все верно: CRD есть, а VolumeSnapshotClass отсутствует. Попробуем решить эту проблему.
1. Рабочий вариант — вручную подготовить манифест. Приведу пример для Cinder OpenStack. Подробнее о драйверах можно почитать на сайте.
apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass driver: cinder.csi.openstack.org metadata: annotations: k10.kasten.io/is-snapshot-class: "true" name: csi-hostpath-snapclass-v1 deletionPolicy: Delete
2. Применим манифест и проверим наличие ресурса VolumeSnapshotClass:
#: kubectl apply -f VolumeSnapshotClass.yaml volumesnapshotclass.snapshot.storage.k8s.io/cinder-csi-openstack-org created #: kubectl get -f VolumeSnapshotClass.yaml NAME DRIVER DELETIONPOLICY AGE csi-hostpath-snapclass-v1 cinder.csi.openstack.org Delete 20s
3. Теперь можем снова запустить проверку PRE-FLIGHT:
#: curl https://docs.kasten.io/tools/k10_primer.sh | bash
Все пункты должны быть в статусе ОК.
4. Дополнительно необходимо добавить аннотацию k10.kasten.io/volume-snapshot-class в default storage-class:
#: kubectl annotate storageclass default \ k10.kasten.io/volume-snapshot-class=csi-hostpath-snapclass-v1
На этом предварительные настройки для работы Kasten K10 закончены. Теперь можем перейти к установке самого инструмента.
Установка Kasten K10
1. Добавляем репозиторий Kasten:
#: helm repo add kasten https://charts.kasten.io/
2. Создаем отдельное пространство имен:
#: kubectl create namespace kasten-io
3. Устанавливаем Helm-чарт с включением sidecar kanister, который необходим для создания снапшотов. С версии Kasten K10 6.5.0 он по умолчанию выключен.
#: helm install k10 kasten/k10 --namespace=kasten-io --set injectKanisterSidecar.enabled=true --set-string injectKanisterSidecar.namespaceSelector.matchLabels.k10/injectKanisterSidecar=true
4. Дожидаемся полной установки компонентов и пробрасываем порт на локальный хост:
#: kubectl get pods --namespace kasten-io --watch
#: kubectl --namespace kasten-io port-forward service/gateway 8080:8000
Супер — все загружено, теперь мы можем открыть веб-интерфейс инструмента по адресу http://127.0.0.1:8080/k10/#/dashboard.
Настройка хранилища для резервных копий
Для создания резервных копий из снимков, перемещения приложений и их данных между кластерами и разными облаками, а также — последующего импорта/экспорта этих резервных копий в другой кластер используются профили хранилища.
Инициализация профиля S3
Как и в случае с K8up, настроим объектное хранилище в качестве основного для всех резервных копий. Это можно сделать как через веб-интерфейс, так и с помощью YAML-манифестов.
1. Создадим и настроим S3-профиль хранения резервных копий в объектном хранилище Selectel. Для этого перейдем на страницу профилей (http://127.0.0.1:8080/k10/#/profiles/location). Нас встретит такая страница:

2. Чтобы создать профиль местоположения, нужно нажать New Profile на странице профилей и заполнить поля:

3. Далее необходимо сохранить профиль. Если все сделали правильно, в списке увидите профиль со статусом VALID:

Настройка резервного копирования
Приступим к настройке периодических резервных копий нашего приложения.
1. Укажем label для пространства имен, в которое установлено приложение. В нашем случае namespace=default:
#: kubectl label namespace default k10/injectKanisterSidecar=true
2. Создадим Policy. Это можно сделать из веб-панели Kasten K10, но мы воспользуемся манифестом:
#sample-backup-action.yam apiVersion: config.kio.kasten.io/v1alpha1 kind: Policy metadata: name: test namespace: kasten-io spec: frequency: "@hourly" paused: false actions: - action: backup backupParameters: profile: name: selectel-s3 namespace: kasten-io - action: export exportParameters: frequency: "@hourly" migrationToken: name: test-migration-token namespace: kasten-io exportData: enabled: true retention: <> retention: hourly: 24 daily: 7 weekly: 4 monthly: 12 yearly: 7 selector: matchExpressions: - key: k10.kasten.io/appNamespace operator: In values: - default
2. Применим манифест в кластере:
#: kubectl create -f sample-backup-action.yaml
3. Если все сделано правильно, должен создаться backupaction. Его можно вывести с помощью специальной команды:
#: kubectl get backupactions.actions.kio.kasten.io NAME CREATED AT STATE PCT scheduled-pwbvk 2023-11-02T09:08:00Z Complete 100
4. Во вкладке Action веб-интерфейса можно проверить статус резервного копирования:

Копируем файл в приложение
Для проверки восстановления из резервной копии скопируем файл, например, Snapshot-class.yaml и вручную запустим резервное копирование. После удалим файл и восстановимся из резервной копии.
1. Копируем файл Snapshot-class.yaml:
#: kubectl cp Snapshot-class.yaml default/nginx-deployment-5dcc6d978b-lc96j:/usr/share/nginx/html/
2. Вручную запускаем резервное копирование. Это можно сделать на странице Policies:

3. Дожидаемся завершения резервного копирования (статус можно отслеживать на странице Dashboard), а после — удаляем файл из примонтированной папки в контейнере:
#: kubectl --namespace default exec -it nginx-deployment-5dcc6d978b-ps6rs -- /bin/sh Defaulted container "nginx-container" out of: nginx-container, kanister-sidecar # rm /usr/share/nginx/html/Snapshot-class.yaml
Восстановление
Теперь можем проверить, восстанавливается ли система из резервной копии.
1. Перейдем во вкладку Application → Item-Menu → Restore:

2. Выберем нужную точку восстановления:

3. В появившемся окне Restore Point выберем приложение, поставим галочку рядом с Data-Only Restore и нажмем кнопку Restore:

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

Готово — резервное копирование на базе Kasten K10 работает!
Подводим итоги
Организация резервного копирования — сложный и комплексный процесс. Необходимо подумать о надежном хранении бэкапов, мониторинге их состояния, а также проверке на восстановление из них.
В своей ML-платформе мы используем инструмент K8up для резервного копирования важной информации — например, служебных данных ClearML. В качестве хранилища используем объектное хранилище. K8up создает файловые копии один раз в день, а также проверяет их на целостность.
Если вам интересно посмотреть, как это работает на практике, протестируйте нашу ML-платформу. Мы разворачиваем ее индивидуально для каждого клиента и можем включить в сборку такие open source-инструменты, как ClearML или Kubeflow. В общем, все для того, чтобы вы смогли организовать полный цикл обучения и тестирования ML-моделей.