Раздел 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 берётся за следующий.
Узлы разделены на 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 до пода | Только для внутреннего или тестового |
edge | TLS обрывается на роутере, до пода идёт 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). Сейчас он объявлен устаревшим и в новых проектах не используется, но в существующих кластерах встречается сплошь и рядом, поэтому разницу надо уметь назвать.
| Deployment | DeploymentConfig | |
|---|---|---|
| Что порождает | ReplicaSet | ReplicationController (более старый объект) |
| Кто катит | Контроллер внутри apiserver | Отдельный deployer-под, который запускается на каждую выкатку |
| Триггеры | Только изменение спеки | Плюс триггер на новый образ в ImageStream |
| Хуки | Нет | pre, mid, post — например, миграция БД перед выкаткой |
| Стратегии | RollingUpdate, Recreate | Rolling, 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 |
|---|---|
| Namespace | Project (namespace + автоматика и права) |
| Ingress + ingress-nginx | Route + встроенный роутер на HAProxy (Ingress тоже работает) |
| Pod Security Admission (опционально) | SCC (всегда, обязательно, строже) |
| Deployment | Deployment (DeploymentConfig — устаревшее наследие) |
| Внешний CI собирает образ | Плюс BuildConfig / S2I / ImageStream внутри кластера |
| Внешний реестр | Плюс встроенный registry в кластере |
| Аутентификация — сам придумай | Встроенный OAuth-сервер и identity providers |
| Ставишь kube-prometheus-stack сам | Мониторинг уже есть; для своих приложений включается enableUserWorkload |
| Узлы — обычный Linux, правишь по SSH | RHCOS, неизменяемый; правки только через MachineConfig и с перезагрузкой |
| Обновляешь компоненты по отдельности | oc adm upgrade — кластер целиком, включая узлы |
| Docker / containerd | CRI-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 это обычно не используют.»
Такой ответ закрывает вопрос целиком и честно. А если после него спросят что-то конкретное, чего ты не знаешь, — «не сталкивался, но по логике это должно решаться через…» работает гораздо лучше, чем выдуманный ответ.