Материалы к экзамену · Урок 7

Как это вообще работает

Желаемое состояние, операторы и GitOps — четыре идеи, на которых держится всё остальное.

Последний урок — про идеи, а не про компоненты. Они лежат в основании всего, о чём шла речь раньше, и вопросы по ним формулируются просто: «почему это работает именно так».

Вы описываете результат, а не действия

Привычный подход к администрированию — последовательность шагов: поставь, настрой, запусти, проверь. Здесь иначе: вы описываете, как должно быть — желаемое состояние, desired state, а система сама решает, что для этого сделать.

Разница проявляется, когда что-то ломается. Скрипт, отработавший вчера, сегодня не поможет: он уже выполнен. А описание желаемого состояния действует постоянно — если реальность от него отклонилась, её вернут обратно.

1. Прочитать, как должно быть2. Посмотреть, как есть3. Устранить разницу4. Повторять всегда
Этот цикл крутится непрерывно — и в контроллерах Kubernetes, и в операторах платформы.

Отсюда самолечение: удалённая копия приложения возвращается не потому, что кто-то заметил пропажу, а потому, что реальность разошлась с описанием.

Из чего состоит манифест

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

ПолеЧто в нём
apiVersionк какой версии API относится тип, например apps.cozystack.io/v1alpha1
kindсам тип: Tenant, Bucket, VMInstance
metadataпаспортные данные: имя, пространство имён, метки, аннотации
specжелаемое состояние — всё, чем объект должен стать

Пятое поле, status, вы не пишете никогда: его заполняет контроллер, и в нём написано, как дела обстоят на самом деле. Отсюда простое правило чтения любого объекта: spec — это ваше требование, status — ответ платформы на него. Цикл сверки выше — это и есть непрерывное сведение одного к другому.

apiVersion: apps.cozystack.io/v1alpha1
kind: Bucket
metadata:
  name: images          # как объект зовут
  namespace: tenant-lab # где он живёт
spec:                   # каким он должен стать
  replicas: 2

Новые типы объектов и операторы

kubectl get tenants работает, хотя в самом Kubernetes никаких тенантов нет. Работает потому, что Cozystack расширяет API Kubernetes, и API-серверу тип Tenant известен.

Расширяют API двумя разными способами, и экзамен различает их.

Определение своего типа — CRD (custom resource definition). Вы регистрируете новый тип, и дальше его объекты хранит и отдаёт обычный API-сервер вместе со встроенными. Так в платформе устроены, например, резервные копии (backups.cozystack.io) и шлюзы (gateway.cozystack.io).

Агрегированный API-сервер. Отдельная программа берёт на себя целую группу API, а основной API-сервер переадресует ей запросы. В Cozystack это cozystack-api в пространстве имён cozy-system, и именно он отвечает за самые заметные группы — apps.cozystack.io (тенанты, бакеты, базы, кластеры), core.cozystack.io, sdn.cozystack.io. CRD с именем tenants.apps.cozystack.io в кластере вы не найдёте: этот тип не зарегистрирован, он отдаётся агрегированным сервером.

Кто за какую группу отвечает, видно одной командой — в колонке SERVICE либо адрес программы, либо слово Local, означающее «обычный API-сервер, тип из CRD»:

kubectl get apiservices | grep cozystack

Но тип сам по себе ничего не делает: это запись, которую кластер согласен хранить. Работу выполняет оператор (operator) — программа, которая следит за объектами своего типа и приводит мир в соответствие.

Отсюда практический вывод: если объект создан, а ничего не произошло, вопрос не к объекту, а к оператору. Он либо не запущен, либо не смог.

GitOps

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

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

Одна оговорка, чтобы не сказать лишнего. Желаемое состояние самой платформы задаёт не ваш репозиторий, а Platform Package — YAML-конфигурация установки; чарты FluxCD тянет из OCI-регистри. Агент внутри кластера непрерывно приводит кластер к описанному состоянию, поэтому изменение, сделанное мимо описания, живёт недолго.

У FluxCD два объекта, которые нужно знать по именам. HelmRepository — источник, откуда берутся чарты. HelmRelease (короткое имя hr) — заявление «этот чарт такой-то версии с такими значениями должен быть установлен и оставаться установленным».

Как временно отключить сверку

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

На такой случай у HelmRelease есть выключатель spec.suspend. Переведённый в suspend релиз контроллер перестаёт сверять: он не переустанавливает чарт, не откатывает изменения и вообще не трогает объект. При этом нагрузка продолжает работать — поды не удаляются, приложение отвечает, — а ваши ручные правки сохраняются до тех пор, пока сверку не включат обратно.

kubectl patch hr <имя> -n <пространство> --type merge -p '{"spec":{"suspend":true}}'

Обратная операция — "suspend": false. В момент возврата контроллер сверяет объект заново и всё, что вы поправили руками мимо описания, откатывается. Поэтому suspend — инструмент диагностики на время расследования, а не способ жить с ручными правками.

Helm

Один объект — это один объект. Приложение — это обычно десяток: развёртывание, сервис, настройки, секреты, правила доступа.

Helm упаковывает такой набор в чарт — шаблоны плюс значения. Меняя значения, вы получаете разные установки из одной упаковки.

В платформе Helm — не рекомендация, а несущая конструкция: каждая позиция каталога это чарт, и заказ сервиса разворачивает именно его. Сама платформа тоже ставится Helm-чартом — одной командой helm upgrade --install с чартом cozy-installer в пространство имён cozy-system.

Складывается такая цепочка, и она стоит того, чтобы её запомнить целиком:

объект → HelmRelease → чарт → оператор → работающие поды

Всё, что делает платформа, проходит по ней. Заказали базу — прошло по ней. Создали тенант — прошло по ней. Установилась сама платформа — тоже.

Словарь Kubernetes, который спросят здесь же

Этот раздел экзамена описан как «седьмая тема плюс базовая терминология», поэтому шесть слов стоит проговорить. Английские названия — ровно те, что будут в вопросах.

ОбъектЧто это и зачем
Namespaceименованное пространство, группирует ресурсы; у каждого тенанта своё
Podнаименьшая единица нагрузки — один контейнер или несколько вместе
Deploymentописывает желаемое: какой образ, сколько реплик, как обновлять
ReplicaSetего исполнитель: держит нужное число подов; руками его почти не трогают
Serviceстабильное имя и адрес перед меняющимся набором подов
PVCзаявка на постоянное хранилище, которое переживает перезапуск пода
Secretхранит чувствительное: пароли, токены, ключи

У Service три типа: ClusterIP — адрес виден только внутри кластера, это тип по умолчанию; NodePort — открывает порт на каждом узле, годится для проб; LoadBalancer — просит внешний адрес у платформы, на своём железе его даёт MetalLB из пятого урока.

И пять команд, которые экзамен спрашивает по написанию:

  • kubectl get pods -A — все поды во всех пространствах имён сразу
  • kubectl describe pod <имя> — подробности пода и, главное, его события
  • kubectl api-resources — какие типы ресурсов кластер вообще знает, включая добавленные платформой
  • kubectl apply -f manifest.yaml --dry-run=server — отдать манифест на проверку серверу, ничего не сохраняя
  • helm upgrade --install — идемпотентно: поставит, если релиза нет, обновит, если есть

Что спросят на экзамене

  • Что описывается желаемое состояние, а не последовательность действий.
  • Что контроллер непрерывно сверяет желаемое с фактическим и устраняет разницу.
  • Что желаемое состояние объекта лежит в spec, фактическое — в status, а apiVersion, kind и metadata отвечают за версию API, тип и имя.
  • Что CRD добавляет тип, а работу выполняет оператор.
  • Что kubectl get tenants работает потому, что Cozystack расширяет API Kubernetes: тип Tenant отдаёт агрегированный сервер cozystack-api, а не CRD.
  • Что suspend у HelmRelease останавливает сверку, но не удаляет нагрузку: поды продолжают работать, ручные правки сохраняются до возврата сверки.
  • Что платформа применяет GitOps к самой себе через FluxCD.
  • Что желаемое состояние платформы задаёт Platform Package, а чарты FluxCD берёт из OCI-регистри.
  • Два объекта FluxCD: HelmRepository — источник чартов, HelmRelease — заявление об установленном чарте.
  • Что чарт — единица упаковки, и каждая позиция каталога это чарт.
  • Что сам Cozystack ставится Helm-чартом cozy-installer.
  • Цепочку: объект → HelmRelease → чарт → оператор → поды.
  • Что такое Namespace, Pod, Deployment, ReplicaSet, Service, PVC и Secret — по одной фразе на каждый.
  • Три типа Service: ClusterIP, NodePort, LoadBalancer.
  • Команды: kubectl get pods -A, kubectl describe pod для событий, kubectl api-resources, --dry-run=server, helm upgrade --install.