Раздел 3 · Kubernetes — глава 3.4

OpenShift с нуля для того, кто знает Kubernetes

Хорошая новость: OpenShift — это Kubernetes. Всё, что ты знаешь про поды, Service, StatefulSet и conntrack, работает там один в один. Плохая новость: сверху навёрнуто десятка полтора собственных сущностей и одна очень строгая политика безопасности, из-за которой обычный kubectl apply с манифестом из интернета там просто не заводится. Эта глава — про дельту. Всё, чего в ванильном Kubernetes нет, и почему оно там появилось.

§1Что это такое и как называть версии

OpenShift — дистрибутив Kubernetes от Red Hat. Ядро то же самое, сверху добавлены: своя операционная система для узлов, свой механизм установки и обновления, встроенная аутентификация, встроенный реестр образов, встроенный мониторинг и логирование, свой контроллер входящего трафика и заметно более жёсткие настройки безопасности по умолчанию.

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

Три названия, которые надо не путать:

  • OCP (OpenShift Container Platform) — коммерческий продукт с подпиской и поддержкой. Обычно, когда говорят «у нас OpenShift», имеют в виду его.
  • OKD — свободная upstream-версия, из которой собирается OCP. Функционально почти то же, без поддержки и с чуть другой ОС узлов.
  • ROSA / ARO — управляемый OpenShift в AWS и Azure соответственно.

Про версии полезно знать простое соответствие: минорная версия Kubernetes = минорная версия OpenShift + 13. OpenShift 4.14 — это Kubernetes 1.27, 4.16 — 1.29, 4.18 — 1.31. Если на собесе спросят «какая у вас была версия», ответ «4.14, то есть куб 1.27» звучит гораздо увереннее голого номера.

И ещё одно различие, которое всплывает постоянно, потому что в интернете полно старых статей: OpenShift 3 и OpenShift 4 — принципиально разные системы. Тройка ставилась Ansible-плейбуками на обычный RHEL и использовала Docker. Четвёрка ставится собственным инсталлятором на неизменяемую ОС, использует CRI-O и целиком построена на операторах. Всё, что написано про 3.x, к 4.x почти не применимо — учитывай при чтении гуглёжа.

§2Главная идея четвёрки: кластер управляет собой сам

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

В обычном кластере ты сам собираешь набор компонентов: поставил CNI, поставил ingress-контроллер, отдельно развернул Prometheus, отдельно настроил cert-manager. Обновляешь каждый своим способом, совместимость версий — твоя забота.

В OpenShift 4 всё иначе. Есть Cluster Version Operator (CVO) — оператор, который управляет другими операторами. Он знает, из чего состоит релиз, и следит, чтобы каждый компонент кластера соответствовал заявленной версии. Под ним — примерно три десятка кластерных операторов, каждый отвечает за свою подсистему: сеть, apiserver, планировщик, реестр образов, мониторинг, аутентификацию, входящий трафик, хранилище.

$ oc get clusteroperators          # или коротко: oc get co
NAME                    VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE
authentication          4.14.15   True        False         False      12d
dns                     4.14.15   True        False         False      40d
etcd                    4.14.15   True        False         False      40d
image-registry          4.14.15   True        False         False      40d
ingress                 4.14.15   True        False         True       2h   ← вот тут проблема
kube-apiserver          4.14.15   True        False         False      40d
machine-config          4.14.15   True        True          False      18m  ← идёт изменение
monitoring              4.14.15   True        False         False      40d
network                 4.14.15   True        False         False      40d

Читать эту таблицу — базовый навык эксплуатации OpenShift, и oc get co — первая команда при любой непонятной проблеме. Три колонки состояния означают: AVAILABLE — подсистема работает; PROGRESSING — прямо сейчас что-то меняется (нормально во время обновления, ненормально сутками); DEGRADED — оператор не может привести систему в нужное состояние, и вот это всегда требует разбирательства. Подробности — в oc describe co/ingress, там будут человекочитаемые сообщения о причине.

Практическое следствие, которое надо проговорить на собесе: компоненты кластера в OpenShift нельзя чинить руками. Отредактировал деплоймент роутера — оператор через полминуты вернёт как было. Это не баг, это дизайн: система постоянно приводит себя к декларированному состоянию. Менять надо конфигурацию оператора, а не то, что он породил.

Спросят

«Чем OpenShift отличается от чистого Kubernetes?» — Не начинай с перечисления сущностей, начни с архитектуры: «Это Kubernetes плюс слой самоуправления. Всё в кластере собрано операторами под управлением Cluster Version Operator, поэтому кластер обновляется одной командой целиком, а компоненты нельзя править руками — их вернёт оператор. Дальше уже частности: своя неизменяемая ОС на узлах, обязательные SCC вместо необязательных Pod Security, Route вместо Ingress, встроенные реестр, мониторинг и OAuth-сервер.»

§3Узлы: неизменяемая ОС и MachineConfig

Второе большое отличие — узлы. В OpenShift 4 они работают под RHCOS (Red Hat Enterprise Linux CoreOS). Это RHEL, урезанный до роли хоста для контейнеров и, главное, неизменяемый: корневая файловая система смонтирована только для чтения, пакетного менеджера в привычном виде нет, поставить что-то через dnf install нельзя.

Для человека с опытом администрирования обычных Linux-узлов это самый непривычный момент. Ты не заходишь на узел, чтобы что-то поправить, — ты декларируешь нужное состояние объектом MachineConfig, а Machine Config Operator раскатывает его на узлы. Причём раскатка означает буквально следующее: узел выводится из-под нагрузки (drain), конфигурация применяется, узел перезагружается, возвращается в строй, и только потом MCO берётся за следующий.

MachineConfig (например, добавить sysctl или файл на узлы) │ ↓ MCO собирает все MachineConfig для пула в один rendered-config MachineConfigPool "worker" │ ├── узел 1: cordon → drain → применить → REBOOT → uncordon ✓ ├── узел 2: то же самое... ← сейчас здесь └── узел 3: ждёт очереди maxUnavailable по умолчанию = 1, поэтому по одному узлу за раз

Узлы разделены на MachineConfigPool — как минимум master и worker, можно заводить свои по меткам (например, отдельный пул для infra-узлов). Конфигурация применяется к пулу целиком.

$ oc get mcp
NAME     CONFIG                    UPDATED   UPDATING   DEGRADED   MACHINECOUNT
master   rendered-master-a1b2c3    True      False      False      3
worker   rendered-worker-d4e5f6    False     True       False      6
                                    ↑ идёт раскатка, узлы перезагружаются по одному

Зайти на узел всё-таки можно, и это важная команда для отладки:

$ oc debug node/worker-2
sh-4.4# chroot /host          # попасть в настоящую файловую систему узла
sh-4.4# journalctl -u kubelet
sh-4.4# crictl ps             # вместо docker ps — здесь CRI-O

Обрати внимание на crictl: в OpenShift 4 движок контейнеров — CRI-O, а не Docker. Docker-команд на узле нет вовсе. Локально образы собирают podman и buildah.

Грабли

Любое изменение MachineConfig — это перезагрузка всех узлов пула по очереди. На кластере из тридцати воркеров это несколько часов, в течение которых поды переезжают туда-сюда. Поэтому: изменения планируются в окно, PodDisruptionBudget должны быть настроены (иначе drain не пройдёт и раскатка встанет), а несколько правок лучше объединять в одну. И зеркальная проблема — если drain где-то не проходит из-за неубиваемого пода, пул подвиснет в состоянии UPDATING навсегда; смотреть oc describe mcp/worker и логи machine-config-daemon на застрявшем узле.

Про установку кратко, потому что спрашивают редко, но знать надо. Есть два способа: IPI (installer-provisioned) — инсталлятор сам создаёт виртуалки в облаке или на vSphere, самый простой путь; и UPI (user-provisioned) — ты сам готовишь машины и сеть, а инсталлятор только раскатывает на них конфигурацию, это вариант для bare-metal и закрытых контуров. Обе схемы используют временный bootstrap-узел, который поднимает первый control-plane и после этого выбрасывается, а конфигурация узлов передаётся через Ignition-файлы. Для закрытых контуров без интернета есть отдельный режим с зеркалированием всех образов релиза во внутренний реестр (oc adm release mirror) — тебе это близко по опыту air-gap.

§4Проект — это namespace с автоматикой

Простое отличие, но встречается в каждом разговоре. Project в OpenShift — это namespace плюс аннотации и набор автоматически создаваемых объектов.

Когда ты делаешь oc new-project team-a, создаётся namespace, а вместе с ним: аннотации с диапазоном UID (о них в §5), сервисные аккаунты default, builder, deployer, права администратора проекта для тебя, и — если администратор кластера настроил шаблон — квоты, лимиты и сетевые политики по умолчанию.

Работать с обоими понятиями можно как угодно: oc get ns и oc get projects покажут по сути одно и то же. Разница в правах: обычный пользователь чаще всего не имеет права смотреть список всех namespace, но видит список своих проектов.

$ oc new-project team-a --display-name="Команда A"
$ oc project team-a            # переключить текущий контекст
$ oc project                   # где я сейчас
Using project "team-a" on server "https://api.ocp.example.com:6443"

Ещё одна деталь, о которой спрашивают: в OpenShift по умолчанию любой аутентифицированный пользователь может создать себе проект — за это отвечает кластерная роль self-provisioner. В корпоративных установках её обычно отбирают, чтобы проекты заводились только через заявку.

§5SCC: то, обо что разбиваются все новички

Если из главы запомнить только один раздел — пусть будет этот. Security Context Constraints — самая частая причина фразы «а в обычном кубе работало, а тут не запускается».

В чём суть

SCC — это политика, которая описывает, что поду разрешено: под каким UID работать, можно ли получить root, можно ли использовать hostPath и сеть узла, какие capabilities доступны, какие типы томов разрешены. Механизм появился в OpenShift задолго до того, как в апстрим-Kubernetes завезли Pod Security Admission, и работает жёстче: SCC применяется всегда, отключить его нельзя, а под, не проходящий ни под одну доступную политику, просто не будет создан.

По умолчанию всем достаётся restricted-v2, и она запрещает почти всё интересное. Главное её свойство, которое и ломает половину готовых образов:

Ключевой момент

Под запускается под случайным UID из диапазона, выделенного проекту (что-нибудь вроде 1000660000), — независимо от того, что написано в образе. Директива USER 1001 в Dockerfile игнорируется. Работать под root запрещено. При этом GID всегда равен 0 (группа root) — и вот на это как раз можно опереться при подготовке образа.

Отсюда типовые симптомы: Permission denied при записи в директорию, которую образ создал под конкретным пользователем; chown: Operation not permitted в entrypoint; попытка слушать порт ниже 1024; падение стандартного nginx-образа с ошибкой доступа к /var/cache/nginx. Всё это — один и тот же корень.

$ oc get scc
NAME                 PRIV    CAPS         RUNASUSER          FSGROUP
anyuid               false   <no value>   RunAsAny           RunAsAny
hostnetwork          false   <no value>   MustRunAsRange     MustRunAs
nonroot-v2           false   <no value>   MustRunAsNonRoot   RunAsAny
privileged           true    [*]          RunAsAny           RunAsAny
restricted-v2        false   <no value>   MustRunAsRange     MustRunAs

# какой UID-диапазон выдан проекту
$ oc get project team-a -o yaml | grep uid-range
    openshift.io/sa.scc.uid-range: 1000660000/10000

# под какой SCC реально запустился под — смотреть в аннотациях
$ oc get pod app-xyz -o jsonpath='{.metadata.annotations.openshift\.io/scc}'
restricted-v2

Как чинить — от правильного к быстрому

Порядок важен, потому что на собесе тебя, скорее всего, спросят именно «а как правильно».

1. Починить образ (правильный путь). Образ должен уметь работать под любым UID. Рецепт стандартный: не полагаться на конкретного пользователя, а выдать нужным каталогам права группе root — chgrp -R 0 /app && chmod -R g=u /app. Поскольку GID пода всегда 0, процесс получит доступ, каким бы ни был его UID. Плюс слушать порт выше 1024. Именно так устроены все образы из каталога Red Hat, и именно поэтому у них есть отдельные варианты вроде nginxinc/nginx-unprivileged.

2. Выдать более мягкий SCC конкретному сервисному аккаунту. Когда образ чужой и переделать нельзя:

$ oc create sa app-sa
$ oc adm policy add-scc-to-user anyuid -z app-sa -n team-a
                                        ↑ -z означает "сервисному аккаунту"
# и в спеке пода прописать serviceAccountName: app-sa

# проверить, кому и что выдано:
$ oc adm policy who-can use scc anyuid
$ oc describe scc anyuid

Обрати внимание: права даются сервисному аккаунту, а не поду напрямую. И anyuid — это всего лишь «разрешить произвольный UID, в том числе root», это далеко не privileged. Разница огромная, и её стоит подчеркнуть в ответе.

3. Написать свой SCC. Если нужна всего одна поблажка (скажем, только capability NET_BIND_SERVICE), правильнее склонировать restricted-v2 и добавить ровно её, чем выдавать anyuid целиком.

Чего делать не надо: выдавать privileged. Это полный доступ к узлу, эквивалент root на хосте. Такое оправдано для системных агентов вроде CNI или драйверов хранилища, но не для приложения.

Спросят

«Задеплоили в OpenShift обычный образ из Docker Hub — под падает с Permission denied. Что происходит и что делать?» — Идеальный ответ: «Это SCC. По умолчанию действует restricted-v2, и под получает случайный UID из диапазона проекта, а USER из Dockerfile игнорируется — образ, который рассчитывает на конкретного пользователя или на root, ломается на правах к своим же каталогам. Правильное решение — пересобрать образ так, чтобы он работал под любым UID: отдать каталоги группе 0 и поставить групповые права, потому что GID у пода всегда 0. Если образ чужой — завести сервисный аккаунт и выдать ему anyuid через oc adm policy add-scc-to-user, но это ослабление, и privileged тут точно не нужен.» Плюс можно добавить, что в ванильном Kubernetes похожую роль сейчас играет Pod Security Admission, только он необязателен и настраивается на уровне namespace.

§6Route: как в OpenShift пускают трафик внутрь

Route — собственный объект OpenShift, появившийся до того, как в Kubernetes стандартизировали Ingress, и оставшийся основным способом опубликовать сервис наружу.

Обслуживает Route Ingress Controller — по сути набор подов с HAProxy, которые живут в отдельном namespace и обычно прибиты к выделенным infra-узлам. Он следит за объектами Route и перестраивает конфигурацию HAProxy.

$ oc expose service myapp                 # создать Route одной командой
route.route.openshift.io/myapp exposed

$ oc get route
NAME    HOST/PORT                                    SERVICES   PORT   TERMINATION
myapp   myapp-team-a.apps.ocp.example.com            myapp      8080   edge/Redirect

Заметь имя хоста: если его не указать явно, OpenShift сгенерирует его сам по схеме <route>-<project>.<wildcard-домен кластера>. У кластера есть wildcard-запись *.apps.домен, указывающая на роутеры, поэтому новый Route работает мгновенно, без правки DNS. Мелочь, а экономит кучу времени по сравнению с обычным ingress-nginx, где домен надо заводить руками.

Четыре режима TLS — про них спрашивают почти всегда

TerminationЧто происходитКогда применяют
нетЧистый HTTP до подаТолько для внутреннего или тестового
edgeTLS обрывается на роутере, до пода идёт HTTPСамый частый вариант. Сертификат хранится в Route
passthroughРоутер не расшифровывает, отдаёт TLS-соединение поду как естьКогда шифрование обязано доходить до приложения или нужна взаимная аутентификация по сертификатам. Балансировка только по TCP, HTTP-маршрутизация по путям недоступна
reencryptРоутер расшифровывает, проверяет, шифрует заново и идёт к поду по HTTPSКогда нужен и разбор HTTP на роутере, и шифрование внутри кластера

Полезно понимать, чем Route богаче обычного Ingress без аннотаций: он умеет разделение трафика по весам между несколькими сервисами (готовый canary или blue-green прямо в объекте), выбор алгоритма балансировки, липкие сессии через cookie, ограничение скорости.

spec:
  to:
    kind: Service
    name: myapp-v1
    weight: 90
  alternateBackends:          # 10% на новую версию — канарейка «из коробки»
    - kind: Service
      name: myapp-v2
      weight: 10

И приятная деталь для переносимости: обычные объекты Ingress в OpenShift тоже работают — контроллер автоматически создаёт под каждый Ingress соответствующий Route. Так что манифесты из ванильного мира не придётся переписывать, хотя тонкие настройки будут доступны только через Route.

§7Сборка образов внутри кластера: BuildConfig, ImageStream, S2I

Ещё один пласт, которого в ванильном Kubernetes нет вовсе. Идея: CI внутри самого кластера.

BuildConfig — объект, описывающий, как из исходников получить образ. Стратегии сборки: Docker (обычный Dockerfile), Source (та самая S2I), Custom. Каждый запуск порождает объект Build и под, который выполняет сборку.

S2I (Source-to-Image) — фирменная штука Red Hat. Берётся готовый базовый образ с рантаймом (Java, Python, Node), в него закачивается твой репозиторий, внутри вызываются скрипты assemble и run, на выходе — готовый образ. Dockerfile писать не нужно вообще: разработчик даёт ссылку на git, платформа сама понимает язык и собирает.

$ oc new-app https://github.com/team/api.git
--> Found image openjdk:17 ... creating S2I builder
--> Creating resources: imagestream, buildconfig, deployment, service
--> Success

$ oc start-build api --follow      # запустить сборку и смотреть лог
$ oc logs -f bc/api                # лог последней сборки

ImageStream — самая своеобразная сущность, и её стоит понять правильно, потому что объясняют её обычно плохо. Это не хранилище образов. Это именованный указатель на образы с историей тегов, живущий внутри кластера.

Зачем он нужен — три причины:

  • Стабильность. Под ссылается на myapp:prod в ImageStream, а ImageStream внутри держит конкретный неизменяемый дайджест. Тег во внешнем реестре перезаписали — на кластере ничего не поехало, пока ты сам не обновишь указатель.
  • Триггеры. В ImageStream появился новый образ по тегу — автоматически запускается перевыкатка деплоймента или следующая сборка. Готовый конвейер без внешнего CI.
  • Развязка окружений. Продвижение из dev в prod — это просто перевешивание тега внутри кластера (oc tag myapp:latest myapp:prod), без пересборки и перезаливки.

Сами образы лежат во внутреннем реестре, доступном изнутри кластера как image-registry.openshift-image-registry.svc:5000. Снаружи он по умолчанию не опубликован — если нужно, роутер для него включается отдельно.

Честная оценка для собеса: в командах со зрелым CI (GitLab CI, Jenkins — твой случай) BuildConfig и S2I обычно не используют, образы собираются снаружи и просто заливаются в реестр. Это нормальная и распространённая практика. Но знать, что они есть и зачем, надо — вопрос «что такое ImageStream» задают часто.

§8DeploymentConfig: наследие, о котором спросят

До того как в Kubernetes появился нормальный Deployment, в OpenShift был свой объект — DeploymentConfig (сокращённо dc). Сейчас он объявлен устаревшим и в новых проектах не используется, но в существующих кластерах встречается сплошь и рядом, поэтому разницу надо уметь назвать.

DeploymentDeploymentConfig
Что порождаетReplicaSetReplicationController (более старый объект)
Кто катитКонтроллер внутри apiserverОтдельный deployer-под, который запускается на каждую выкатку
ТриггерыТолько изменение спекиПлюс триггер на новый образ в ImageStream
ХукиНетpre, mid, post — например, миграция БД перед выкаткой
СтратегииRollingUpdate, RecreateRolling, Recreate, Custom (свой образ-выкатчик)
Поведение при разрывеПродолжает работуМожет застрять, если deployer-под убит

Главная практическая разница — deployer-под: выкатка DeploymentConfig это отдельный процесс в кластере, за которым можно смотреть (oc rollout status dc/app, oc logs dc/app), но который может и подвиснуть. У Deployment всё делает контроллер, и это надёжнее.

Рекомендация Red Hat однозначная: новое писать на Deployment, старое мигрировать. Если на собесе спросят «что выберешь» — отвечай Deployment, а хуки заменяй init-контейнерами и Job.

§9Кто ты такой и что тебе можно

В ванильном Kubernetes аутентификации как таковой нет — apiserver проверяет сертификат или токен, а откуда взялся пользователь, его не касается. OpenShift эту дыру закрывает: в нём есть встроенный OAuth-сервер, и вход по логину-паролю работает из коробки.

$ oc login https://api.ocp.example.com:6443 -u arseny
Password:
Login successful. You have access to 12 projects.

$ oc whoami
arseny
$ oc whoami --show-console      # адрес веб-консоли
$ oc whoami -t                  # текущий токен

Откуда берутся пользователи — определяется identity provider, который настраивается в объекте OAuth/cluster. Поддерживаются htpasswd (простой файл, обычно для старта), LDAP, OpenID Connect (сюда подключают Keycloak — тебе это близко), GitHub/GitLab/Google и другие. При первом входе автоматически создаются объекты User и Identity, связывающие внешнюю учётку с внутренней.

Отдельная деталь, о которой любят спрашивать: kubeadmin — временный аварийный пользователь, который создаётся при установке кластера. Правильная практика — после подключения нормального провайдера и выдачи кому-то прав cluster-admin удалить его секрет, потому что это учётка с полным доступом и паролем в открытом виде в чьей-нибудь истории терминала.

RBAC тот же, что в Kubernetes (Role, ClusterRole, привязки), плюс готовые роли уровня проекта и удобные команды-обёртки:

$ oc adm policy add-role-to-user edit ivan -n team-a
                                  ↑ роли проекта: admin / edit / view
$ oc adm policy add-cluster-role-to-user cluster-admin arseny
$ oc adm policy add-role-to-group view devs -n team-a

$ oc auth can-i delete pods -n team-a        # а мне можно?
$ oc adm policy who-can delete pods -n team-a # а кому вообще можно?

Смысл трёх базовых ролей: view — только чтение (без секретов), edit — менять объекты приложения, но не права, admin — всё в проекте, включая раздачу прав внутри него. В 90% случаев этого хватает, свои роли пишут редко.

§10Сеть

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

Плагин по умолчанию в актуальных версиях — OVN-Kubernetes (построен на Open vSwitch, использует Geneve-туннели). Старый OpenShift SDN объявлен устаревшим и из свежих релизов убран; если увидишь его в кластере — это старая установка, и переезд на OVN будет отдельной задачей. Важное практическое следствие туннелирования: MTU внутри подов меньше 1500, и все проблемы из главы 1.1 здесь актуальны в полный рост.

Что OVN даёт сверх обычных NetworkPolicy:

  • EgressIP — закрепить за проектом фиксированный исходящий адрес. Практическая ценность огромная: внешняя база или партнёрский API пускают по белому списку IP, а без этого весь трафик уходит под адресом того узла, где случайно оказался под (это тот самый masquerade из главы 1.2). С EgressIP адрес предсказуем.
  • EgressFirewall — ограничить, куда поды проекта имеют право ходить наружу. Обычные NetworkPolicy для исходящего трафика тоже работают, но EgressFirewall удобнее описывает правила по доменам и подсетям для всего проекта разом.
  • AdminNetworkPolicy — политики кластерного уровня, которые нельзя переопределить из проекта.

Отдельно стоит знать про Multus: он позволяет подключить поду несколько сетевых интерфейсов сразу. Нужно для телекома, СХД и всего, где под должен смотреть в отдельную физическую сеть, — и в кластерах Red Hat встречается часто.

§11Что идёт в коробке и как этим управлять

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

Мониторинг. Prometheus, Alertmanager, Thanos Querier и Grafana-подобные дашборды в веб-консоли — всё это уже развёрнуто в openshift-monitoring и следит за кластером. Ключевая деталь, которую спрашивают: этот стек по умолчанию не собирает метрики твоих приложений — только платформенные. Чтобы включить пользовательский мониторинг, нужно отдельно поднять флаг:

# ConfigMap cluster-monitoring-config в namespace openshift-monitoring
data:
  config.yaml: |
    enableUserWorkload: true

После этого в проектах начинают работать ServiceMonitor и PrometheusRule — привычные объекты Prometheus Operator. Менять сам платформенный Prometheus нельзя (см. §2 — оператор вернёт как было), настраивается он только через свой ConfigMap.

Логирование. Ставится отдельным оператором (не входит в базовую поставку). Раньше это был стек на Elasticsearch, сейчас — Loki плюс Vector в качестве сборщика. Учитывая твой опыт с ELK и OpenSearch, тут стоит просто знать текущее направление.

OperatorHub и OLM. Всё дополнительное ставится операторами через каталог прямо из веб-консоли. Под капотом — Operator Lifecycle Manager со своими объектами, и их названия стоит выучить, потому что отлаживать установку приходится именно через них:

ОбъектЧто означает
CatalogSourceИсточник каталога операторов (для закрытых контуров — своё зеркало)
Subscription«Хочу вот этот оператор из вот этого канала, обновляй так-то»
InstallPlanКонкретный план установки или обновления. При ручном режиме одобрения ждёт твоего approve
CSV (ClusterServiceVersion)Установленная версия оператора со всеми правами и CRD. oc get csv — первое место, куда смотреть, если оператор «не поставился»
OperatorGroupВ каких namespace оператор имеет право работать

Хранилище. Обычные StorageClass, PV и PVC — без изменений. Дополнительно есть OpenShift Data Foundation (в основе Ceph через Rook) как готовое программно-определяемое хранилище.

Машины. Если кластер поставлен способом IPI, доступен Machine API: объекты MachineSet и Machine позволяют масштабировать узлы как поды — oc scale machineset worker-a --replicas=5, и в облаке появляется новая виртуалка, сама регистрируется в кластере и получает конфигурацию. Сверху работает автомасштабирование узлов.

§12Обновление кластера

Та вещь, ради которой во многом всё и затевалось. Кластер обновляется целиком, одной операцией: CVO по очереди приводит все свои операторы к новой версии, затем MCO перекатывает узлы (drain, применение, перезагрузка — по одному, как в §3).

$ oc adm upgrade
Cluster version is 4.14.15
Updates:
VERSION   IMAGE
4.14.18   quay.io/openshift-release-dev/ocp-release@sha256:...

$ oc adm upgrade --to=4.14.18
$ watch oc get co                 # наблюдать за подсистемами
$ oc get clusterversion           # общий прогресс в процентах

Что надо знать про это на собеседовании:

  • Каналы обновлений. stable-4.14 — проверенные релизы, fast-4.14 — раньше, candidate — кандидаты, eus — расширенная поддержка с возможностью прыгать через мажорную версию. В проде — stable.
  • Через минорные версии перепрыгивать нельзя. С 4.12 на 4.14 — только через 4.13. Исключение — специальный сценарий EUS-to-EUS.
  • Откатиться назад нельзя. Даунгрейд не поддерживается. Единственная страховка — резервная копия etcd, снимаемая скриптом cluster-backup.sh прямо на control-plane узле. Снимать её перед каждым обновлением — обязательная практика.
  • Обновление узлов — это перезагрузки. Часы времени на большом кластере и обязательные корректные PodDisruptionBudget, иначе drain встанет.

В бою

Когда что-то сломалось и непонятно что — есть одна команда, собирающая полный диагностический дамп кластера: oc adm must-gather. Она разворачивает временный под, который выгребает состояние всех операторов, логи, конфигурацию и события в локальную директорию. Именно этот архив требует поддержка Red Hat при обращении, и именно с него разумно начинать собственный разбор серьёзного инцидента. Для конкретной подсистемы можно указать свой образ сбора: oc adm must-gather --image=....

§13Шпаргалка и как отвечать

Перевод с ванильного на OpenShift

В обычном KubernetesВ OpenShift
NamespaceProject (namespace + автоматика и права)
Ingress + ingress-nginxRoute + встроенный роутер на HAProxy (Ingress тоже работает)
Pod Security Admission (опционально)SCC (всегда, обязательно, строже)
DeploymentDeployment (DeploymentConfig — устаревшее наследие)
Внешний CI собирает образПлюс BuildConfig / S2I / ImageStream внутри кластера
Внешний реестрПлюс встроенный registry в кластере
Аутентификация — сам придумайВстроенный OAuth-сервер и identity providers
Ставишь kube-prometheus-stack самМониторинг уже есть; для своих приложений включается enableUserWorkload
Узлы — обычный Linux, правишь по SSHRHCOS, неизменяемый; правки только через MachineConfig и с перезагрузкой
Обновляешь компоненты по отдельностиoc adm upgrade — кластер целиком, включая узлы
Docker / containerdCRI-O, локально podman и buildah

Команды, которых нет в kubectl

oc — это kubectl со всеми его командами плюс свои. Всё, что ты умеешь, работает; ниже — то, что стоит добавить в память.

oc login / oc whoami / oc project        # вход, кто я, где я
oc get co                                # здоровье кластера — команда №1
oc adm top nodes / pods                  # потребление ресурсов
oc rsh pod/app                           # шелл в под (короче, чем kubectl exec)
oc debug node/worker-1                   # шелл на узле (дальше chroot /host)
oc debug deployment/app                  # копия пода без пробы — отладить падающий
oc adm policy add-scc-to-user anyuid -z sa
oc adm policy add-role-to-user edit ivan -n proj
oc expose service myapp                  # создать Route
oc new-app / oc start-build              # S2I-сборка
oc adm must-gather                       # полный дамп для разбора инцидента
oc adm cordon / drain / uncordon         # вывод узла из-под нагрузки
oc explain route.spec.tls                # документация по любому полю
oc status                                # обзор проекта человеческим языком

Как отвечать на собесе, если опыта нет

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

«OpenShift — это Kubernetes с достроенным поверх слоем самоуправления. Кластер целиком собран операторами под управлением Cluster Version Operator, поэтому обновляется одной командой вместе с узлами, но и чинить его компоненты руками бесполезно — оператор вернёт как было. Узлы работают на неизменяемой RHCOS: SSH и пакетный менеджер там не рабочий инструмент, конфигурация задаётся объектом MachineConfig и раскатывается с перезагрузкой каждого узла по очереди.

Из того, обо что спотыкаются на практике, главное — SCC. Это обязательная политика безопасности, аналог Pod Security Admission, только строже и без возможности отключить: под получает случайный UID из диапазона проекта, root запрещён, USER из Dockerfile игнорируется. Поэтому произвольный образ из Docker Hub часто не запускается, и правильное лечение — сделать образ работающим под любым UID через права группе 0, а не раздавать anyuid.

Дальше — Project вместо namespace, это namespace с автоматически заведёнными правами и квотами. Route вместо Ingress, его обслуживает встроенный роутер на HAProxy, режимы TLS — edge, passthrough и reencrypt, плюс встроенное разделение трафика по весам для канареек. Есть встроенные реестр образов, OAuth-сервер с подключением LDAP или OIDC, мониторинг на Prometheus, который по умолчанию собирает только платформенные метрики — для своих приложений включается user workload monitoring. Сеть — OVN-Kubernetes, из полезного сверх обычного: EgressIP, чтобы у проекта был предсказуемый исходящий адрес для белых списков.

Из наследия встречается DeploymentConfig — он устарел, новое надо писать на обычном Deployment, а его хуки заменять init-контейнерами. И ещё есть BuildConfig с S2I для сборки прямо в кластере, но при зрелом внешнем CI это обычно не используют.»

Такой ответ закрывает вопрос целиком и честно. А если после него спросят что-то конкретное, чего ты не знаешь, — «не сталкивался, но по логике это должно решаться через…» работает гораздо лучше, чем выдуманный ответ.