Managed Kubernetes в облаке: то, чего не показать на kind
Lesson from the course “Курс подготовки DevOps-инженеров”
Хронометраж: занятие 60 минут — теория 30 минут, практика 30 минут. Домашняя работа: 1–2 часа.
Краток о чём урок: Управляемый кластер Yandex Cloud под Terraform, три вещи, которых нет на kind (LoadBalancer с настоящим адресом, облачный StorageClass/CSI, GitOps на реальный кластер), доступ к API и уборка облачных ресурсов, созданных вне Terraform.
1. Что изучаем
После урока вы сможете:
- поднимать управляемый кластер Yandex Cloud под Terraform и понимать, что берёт на себя сервис;
- получать доступ к API управляемого кластера, в том числе когда прямой путь закрыт;
- показывать Service
LoadBalancerс настоящим внешним адресом (на kind это невозможно); - заказывать динамический том на облачном StorageClass/CSI и понимать отличие от local-path;
- запускать GitOps (Argo CD) на управляемый кластер и убирать облачные ресурсы, созданные вне Terraform.
2. Зачем это нужно и где применяется
Весь блок 14 (и блок 13) шёл на kind — локальном кластере в контейнере. kind честно показывает
почти всё, но три вещи он показать не может по устройству: у него нет облачного контроллера, нет
облачного диска и нет настоящего внешнего адреса. Ровно в этих точках управляемый кластер в облаке
ведёт себя иначе, и именно их стоит увидеть перед тем, как эксплуатировать прод. Урок собирает вместе
блок 12 (Terraform) и блок 14 (эксплуатация, GitOps) на настоящем облаке.
Ситуации, из-за которых существует этот урок:
- «На kind сервис LoadBalancer вечно
<pending>» — в облаке он получает настоящий адрес; - «PVC на kind не соблюдает размер» — облачный CSI даёт настоящий диск;
- «Кто отвечает за мастер?» — управляемый control plane против самосбора (13.13);
- «kubectl не достучался до кластера» — доступ к API и обходной путь;
- «Снёс кластер, а в счёте остались адрес и диск» — ресурсы, созданные вне Terraform.
3. Теория (30 минут)
Файлы для работы: blocks/15-kubernetes-cloud/examples/15.01-managed-k8s-cloud/
Стенд: настоящее облако Yandex Cloud (каталог
course), Terraform 1.5.7, провайдерyandexчерез зеркало (terraformrc, рецепт из 12.09). Кластер поднят и сразу снесён по F30. Конфигурация —infra/main.tfи модульinfra/modules/k8s/main.tf(variables.tf,outputs.tf); управляющая ВМ —infra/control.tfс драйверомcontrol-driver.sh; проверяемые манифесты —manifests/app-lb.yamlиmanifests/pvc.yaml.
3.1. Что берёт на себя сервис, а что остаётся вам
Управляемый кластер делит ответственность по границе «control plane / узлы» (та же граница, что в 13.13, только теперь мастер держит облако). Проверено на созданном кластере:
- control plane (мастер) — забота сервиса. Вы выбираете версию и релизный канал (STABLE — версии
1.32–1.35 на момент урока), зональность и доступность; сам мастер, его
etcd, обновления и починку ведёт облако. Вkubectl get nodesмастера не видно (11.08); - группа узлов — ваша забота: тип ВМ, число, версия, прерываемость. Это обычные ВМ (11.03), и платите вы за них;
- сеть, сервисный аккаунт, роли — тоже ваши, и в этом уроке они описаны кодом.
Всё это поднимается одним Terraform (модуль
infra/modules/k8s/main.tf):
yandex_vpc_network + yandex_vpc_subnet, сервисный аккаунт yandex_iam_service_account с ролями
(k8s.clusters.agent, vpc.publicAdmin, load-balancer.admin, container-registry.images.puller),
yandex_kubernetes_cluster (зональный, публичный эндпоинт) и yandex_kubernetes_node_group
(одна прерываемая нода). Замер: terraform apply создал 9 ресурсов, кластер поднялся в
RUNNING/HEALTHY, группа узлов RUNNING; создание заняло около 10–15 минут (мастер — основная
часть). Роли обязательны и выдаются до кластера (depends_on): без vpc.publicAdmin и
load-balancer.admin облачный контроллер не сможет создать LoadBalancer (§3.3).
Про версии и обновления. Версию k8s задаёт релизный канал: RAPID получает новые версии первым,
STABLE — последним, но проверенными; на момент урока во всех трёх каналах доступны 1.32–1.35
(yc managed-kubernetes list-versions). В коде версия зафиксирована (1.35), потому что версия вне
канала уронит apply. Обновление здесь — это не пересоздание, как на kind (14.09): у управляемого
кластера сначала обновляется мастер (это делает сервис по вашей команде), затем — группа узлов,
и порядок именно такой (13.13, документация Yandex). Группа узлов в примере — одна прерываемая нода
(дешевле в разы, 11.03) с диском 30 ГБ; в проде число узлов и тип задаёте вы, а прерываемость убираете.
То есть «управляемый» снимает с вас мастер и починку, но выбор мощности, версии и момента обновления
остаётся решением, которое принимаете вы.
3.2. Доступ к API: когда прямой путь закрыт
Кластер поднят с публичным эндпоинтом (external_v4_endpoint), и первое, что хочется, — получить
доступ: yc managed-kubernetes cluster get-credentials <имя> --external. Но здесь всплыло
ограничение среды, которое стоит знать: с рабочей машины автора TCP до внешнего адреса API
(порт 443) не проходит — путь идёт через VPN, и соединение до части адресов облака рвётся (та же
находка, что в 11.08). Проверка однозначна: bash -c 'echo > /dev/tcp/<ip>/443' → отказ, kubectl
виснет. То есть kubectl с машины владельца к этому кластеру не работает вовсе.
Это не «поломка курса», а реальный операционный случай: сеть между вами и кластером может быть закрыта
(корпоративный VPN, приватный эндпоинт, отсутствие маршрута). Обход, который работает всегда, — зайти
изнутри облака: небольшая управляющая ВМ в той же подсети
(infra/control.tf) видит внутренний
эндпоинт мастера. На ней сработала связка из 11.08: IAM-токен из metadata сервисного аккаунта ВМ
(curl http://169.254.169.254/.../token) как bearer к API кластера, а RBAC привязывает этот SA к
cluster-admin (роль k8s.cluster-api.cluster-admin). Замер: сервер в kubeconfig стал
https://10.130.0.21 (внутренний адрес), kubectl get nodes ответил.
Здесь стоит различать два разных доступа, которые легко спутать (и на этом легко потерять время).
Первый — доступ к облачному API (yc, Terraform): он идёт на *.api.cloud.yandex.net и у ВМ
работает через её сервисный аккаунт из metadata, без ключей. Второй — доступ к API самого кластера
(kubectl): он идёт на эндпоинт мастера, и вот он-то и был закрыт с рабочей машины. Роль
k8s.cluster-api.cluster-admin даёт именно второй доступ (не первый), а k8s.clusters.agent из §3.1 —
это про право управлять кластером как облачным объектом, а не про вход в его API. Разные роли для
разных дверей — частая путаница при выдаче прав. Всё, что дальше в уроке, выполнено с управляющей ВМ
одним прогоном (control-driver.sh): kubectl там
настроен на внутренний эндпоинт со встроенным IAM-токеном (без exec-плагина yc, иначе под
cloud-init он не находит нужный контекст), а результат снят с серийной консоли
(yc compute instance get-serial-port-output) — тот же приём, что для сетевых опытов в блоке 11, потому
что и ssh к ВМ по тому же VPN-пути ненадёжен.
3.3. LoadBalancer с настоящим адресом (на kind нельзя)
На kind Service типа LoadBalancer навсегда остаётся EXTERNAL-IP: <pending> — некому выдать адрес
(13.01, 13.06). В облаке за это отвечает облачный контроллер: он видит такой Service и создаёт
сетевой балансировщик (NLB) с настоящим внешним адресом.
Проверено манифестом app-lb.yaml
(nginx + Service type: LoadBalancer): через минуту у сервиса появился
EXTERNAL-IP 130.193.44.58, в облаке возник NLB в статусе ACTIVE со слушателем на этом адресе
и порте 80, а curl http://130.193.44.58/ из публичного интернета вернул 200. То есть это
не внутрикластерная фикция, а настоящий адрес, доступный снаружи. Тонкость, которую стоит помнить:
сразу после создания (первые секунды) балансировщик отвечает 000 — проверки живости целей ещё не
прошли; адрес уже выдан, но трафик пойдёт, когда цели станут здоровыми (та же механика health-check,
что у NLB в 11.05). Отсюда практический вывод: EXTERNAL-IP появился — это ещё не «уже отвечает»,
нужно дождаться здоровья целей.
3.4. Облачный StorageClass и CSI (на kind был local-path)
На kind класс по умолчанию — local-path, и он не соблюдает размер тома: dd записал 300 МБ в
том на 100Mi без ошибки (13.11), а данные привязаны к одному узлу. В облаке класс по умолчанию —
настоящий CSI поверх облачных дисков.
Проверено: kubectl get storageclass показал пять классов, все на провайдере
disk-csi-driver.mks.ycloud.io, класс по умолчанию — yc-network-hdd
(WaitForFirstConsumer, allowVolumeExpansion: true). PVC из
pvc.yaml на 1Gi перешёл в Bound, под него
создался PV, а в облаке появился настоящий диск 1 ГиБ в статусе READY (виден в
yc compute disk list). Отличия от local-path принципиальные: диск существует как облачный ресурс,
переживает переезд пода на другой узел (сетевой диск, а не привязка к узлу), поддерживает расширение и,
в отличие от local-path, соблюдает размер. Классов несколько (hdd, ssd, nvme,
ssd-nonreplicated) — выбор класса это выбор носителя и цены, чего на kind просто нет.
Одно свойство совпадает с kind и стоит того, чтобы его заметить: volumeBindingMode у всех классов —
WaitForFirstConsumer, то есть PVC остаётся Pending, пока не появится под-потребитель (13.11). Это не
дефект, а норма: облако создаёт диск в той зоне, где реально встанет под, и не раньше. Отсюда практический
порядок разбора «PVC висит»: сначала смотрят, есть ли под, и лишь потом — класс и провайдер. А Delete
как reclaimPolicy по умолчанию означает, что при удалении PVC через кластер диск уберётся сам
(в отличие от сценария §3.6, где кластер сносят целиком и диск остаётся сиротой). То есть у облачного
CSI аккуратная уборка встроена — но работает она, только если удалять PVC, а не выдёргивать кластер
из-под него.
3.5. GitOps на управляемый кластер
Механика Argo CD разобрана в 14.10 на kind; здесь важно, что она так же работает на управляемом
кластере, а отличия — в окружении, а не в инструменте. Проверено: на кластер поставлена минимальная
сборка Argo CD (core-install.yaml v3.5.3, как в 14.10), создан проект default (в core-install его
нет — находка 14.10) и Application, указывающий на публичный репозиторий примеров Argo
(argocd-example-apps, приложение guestbook). Приложение дошло до Synced/Healthy за десятки секунд.
Что здесь то же, что на kind: модель синхронизации, Application, AppProject, права через RBAC
(14.03). Что иначе: во-первых, узлы кластера имеют выход в интернет (NAT), поэтому Argo тянет манифесты
из внешнего git без ухищрений (на kind в 14.10 приходилось поднимать git-демон в кластере); во-вторых,
доступ к самому Argo и к API — через реальный эндпоинт и реальный RBAC, то есть все ограничения из
14.03/14.10 действуют буквально. Вывод: GitOps не зависит от того, где кластер, — но окружение
управляемого кластера (сеть, RBAC, эндпоинт) настоящее, и это меняет обвязку вокруг Argo, а не сам Argo.
3.6. Уборка: облако создаёт ресурсы вне Terraform
Самая ценная эксплуатационная находка урока: не всё, что появилось, создано Terraform. NLB для
LoadBalancer и диск для PVC создал облачный контроллер кластера, а не Terraform, — их нет в его
state. Поэтому terraform destroy снёс кластер, узлы, сеть и ВМ (12 ресурсов), но NLB и облачный
диск остались бы сиротами и продолжали тратить деньги: адрес NLB — 0,26 ₽/ч, диск — по часам.
Проверено, поэтому в уборке два шага. Сначала снимаются ресурсы, созданные контроллером: NLB и его
target-group (иначе, пока NLB держит сеть, terraform destroy не удалит сеть), — правильнее всего
удалить их через сам кластер (kubectl delete svc/pvc, тогда контроллер уберёт NLB и диск сам),
а если кластер уже сносится — добить через yc. Затем terraform destroy. После — инвентаризация
каталога (yc ... list по всем видам): в этом уроке после destroy остался один сиротский диск, снят
отдельно, и только тогда каталог стал пуст. Правило F30 в облачном k8s звучит так: инвентаризация
после destroy обязательна, потому что часть ресурсов живёт вне Terraform.
Цена всей проверки: кластер + прерываемая нода + управляющая ВМ + NLB + адрес + два диска за ~40 минут
обошлись меньше чем в несколько рублей; всё снесено сразу (F30). Порядок сноса важен и сам по себе:
сначала — то, что создал контроллер (Service и PVC через кластер, либо NLB и диск через yc), потом —
Terraform, и только в конце — инвентаризация. Пропустишь первый шаг — заплатишь за то, чего в коде нет.
3.7. Сводка: что показали замеры
| Утверждение | Что показал замер |
|---|---|
| «managed = я ничего не делаю» | мастер — сервиса; узлы, сеть, роли — ваши, всё под Terraform (9 ресурсов) |
| «kubectl всегда достучится» | TCP 443 к внешнему API с машины владельца закрыт (VPN, 11.08) — зашёл изнутри |
| «LoadBalancer как на kind» | настоящий NLB ACTIVE, внешний IP 130.193.44.58, curl 200 из интернета |
| «том как local-path» | CSI yc-network-hdd, PVC Bound → настоящий диск 1 ГиБ READY, размер соблюдается |
| «GitOps в облаке — что-то особое» | тот же Argo CD (14.10) → Synced/Healthy; иначе только окружение |
| «destroy убрал всё» | NLB и диск создал контроллер, не Terraform — остались сиротами, добил yc |
3.8. Примеры и варианты реализации
Один управляемый кластер — в трёх средах (здесь среда и есть предмет урока).
| Среда | Как решается | Что нужно иметь |
|---|---|---|
| Локальный стенд (kind) | LoadBalancer/CSI/облачный контроллер недоступны — это и есть граница kind | Docker |
| VPS / bare-metal | кластер самосбором (kubeadm, 13.13); LB и CSI — свои (MetalLB, Ceph/CSI) | серверы, время |
| Yandex Cloud | управляемый кластер под Terraform, облачные LB и CSI из коробки (пример урока) | каталог, ключ/токен |
Локальный стенд. kind показывает всё, кроме облачных интеграций; именно поэтому этот урок — в облаке.
VPS / bare-metal. Кластер и control plane поднимаете и обслуживаете сами (13.13), а LoadBalancer и динамические тома добавляете отдельными компонентами — их в облаке даёт сервис.
Yandex Cloud. Управляемый кластер + облачные LB/CSI из коробки; ценой этого — привязка к облаку и плата за узлы, мастер-вычисления, балансировщик и диски. Дорогое создаётся под замер и сразу сносится (F30), а доступ к API может требовать обхода (§3.2).
4. Практика на занятии (30 минут)
Курс проходят самостоятельно, поэтому каждый шаг говорит, что сделать (или что ввести), зачем, что должно получиться и что делать, если вышло не так.
Опыты — в 15.01-managed-k8s-cloud/. Стенд — настоящий
управляемый кластер Yandex Cloud (каталог course, F30), поднятый Terraform; доступ — через управляющую
ВМ с IAM-токеном из metadata (§3.2). Полный цикл создания и сноса кластера длиннее занятия (создание —
около 10–15 минут) и вынесен в домашнюю работу: там же метка course=lNNNN на всех ресурсах, дорогое —
под замер и с ценой заранее, а после terraform destroy обязательна инвентаризация yc (облачный
контроллер создаёт NLB и диск вне state Terraform, §3.6). На занятии кластер не поднимаем — разбираем
код и уже снятый вывод драйвера (маркеры ===...=== из control-driver.sh),
процитированный в теории.
Шаг 1 (7 минут). Кто за что отвечает: разбор Terraform-кода.
- Что сделать: прочитайте
infra/main.tfи модульinfra/modules/k8s/main.tf; выпишите, какие ресурсы создаёт Terraform, а что после этого держит облако само. - Зачем: без этой границы непонятно, что вообще проверяют следующие два шага — облачные интеграции работают именно там, где заканчивается ваш код и начинается сервис.
- Ожидаемый результат: список из трёх групп — control plane (версия, канал, зональность — решаете вы,
сам мастер и
etcd— сервис), группа узлов (полностью ваша), сеть/SA/роли (ваши, описаны в модуле);yandex_resourcemanager_folder_iam_memberстоит вdepends_onуyandex_kubernetes_cluster. - Если не так: если не нашли
depends_on— он там не для красоты: без ролей, выданных до кластера, облачный контроллер не сможет создать LoadBalancer в шаге 3 (§3.1). - Ответьте: какая из ролей в
locals.rolesнужна именно для публикации LoadBalancer, а не для управления кластером как таковым?
Шаг 2 (7 минут). Доступ к API: почему прямой путь не работает.
- Что сделать: прочитайте §3.2 и начало
control-driver.shдо строкиkubectl config use-context ctx— как ВМ получает IAM-токен из metadata и собирает kubeconfig без exec-плагинаyc. - Зачем: это рабочий обход для любой ситуации, где сеть до API закрыта (VPN, приватный эндпоинт, свой корпоративный фаервол), а не специфика курса.
- Ожидаемый результат: вы можете назвать разницу между ролью
k8s.clusters.agent(управлять кластером как облачным объектом) иk8s.cluster-api.cluster-admin(войти в API самого кластера) и объяснить, зачем токен подставлен в kubeconfig как--token, а не через exec-плагин. - Если не так: если кажется, что достаточно одной роли на всё — перечитайте абзац «Здесь стоит различать два разных доступа» в §3.2: это разные двери, и одна роль другую не заменяет.
- Ответьте: с рабочей машины
bash -c 'echo > /dev/tcp/<ip>/443'даёт отказ. Что именно это доказывает и чего не доказывает?
Шаг 3 (11 минут). Три вещи, которых нет на kind: манифест → вывод драйвера.
- Что сделать: сопоставьте манифесты
app-lb.yamlиpvc.yamlс фрагментами выводаcontrol-driver.sh, процитированными в §3.3–3.5:===LB-IP===,===PVC===/===STORAGECLASS===,===ARGO===. Для каждого из трёх пунктов назовите ОДНО поле или код ответа, которое доказывает результат, а не просто «применилось». - Зачем: «применилось» (код 0) не значит «работает» — это уже встречалось на PSA (14.04, Deployment
применился, а подов ноль) и на GitOps (14.10,
Syncedне гарантирует восстановимость данных) — здесь та же проверка, только доказательства настоящие (внешний IP, статус диска в облаке). - Ожидаемый результат: Service →
EXTERNAL-IP 130.193.44.58иcurlкод200; PVC →phase: Boundплюс дискREADYвyc compute disk list; ArgoApplication→Synced/Healthy. - Если не так:
curlсразу после появления адреса вернул000— это не авария, цели балансировщика ещё не прошли health-check (§3.3), подождите и повторите. PVC осталсяPending— это тоже норма приWaitForFirstConsumer, пока нет пода-потребителя (§3.4), а не признак сломанного CSI. - Ответьте: почему
yc-network-hdd— облачный диск, а не аналогlocal-path— соблюдает заявленный размер тома, аlocal-pathиз 13.11 нет?
Шаг 4 (5 минут). Уборка: что Terraform не видит.
- Что сделать: перечитайте §3.6 и найдите в манифестах, какие два ресурса (LoadBalancer и PVC) порождают объекты, которых нет в коде Terraform.
- Зачем: это самая дорогая ошибка урока — «снёс кластер, а счёт продолжает идти» — и единственный способ её избежать: знать заранее, что облачный контроллер создаёт ресурсы вне state.
- Ожидаемый результат: верный порядок уборки — сначала
kubectl delete svc/pvc(или ресурсы черезyc, если кластер уже сносится), потомterraform destroy, и только в конце — инвентаризацияyc ... listпо всем видам ресурсов. - Если не так: если сделали
terraform destroyпервым и решили, что этого достаточно, — проверьте инвентаризацией: в этом уроке после такого порядка сиротой остался диск. - Ответьте: почему
reclaimPolicy: Deleteу CSI не спасает в сценарии, где кластер сносят целиком, а не удаляют PVC отдельно (§3.4)?
Что обсудить в конце занятия. Вы сносите кластер terraform destroy и видите нулевой счёт за
кластер, но через месяц приходит счёт за диск и адрес. Что случилось и как это предотвратить?
5. Домашняя работа (1–2 часа)
Задание. Если у вас есть каталог в Yandex Cloud, соберите управляемый кластер по заготовке
managed-k8s-plan.md: поднимите кластер
Terraform; получите доступ к API (при закрытом прямом пути — изнутри облака); покажите Service LoadBalancer с настоящим адресом, PVC на облачном StorageClass со связанным диском и Argo CD с
Synced/Healthy; снесите всё и проверьте инвентаризацией, что каталог пуст, приведите оценку цены.
Если облака нет — разберите те же шаги по коду примеров и объясните, почему каждый из трёх пунктов
невозможен на kind.
Критерии приёмки.
- Кластер поднят Terraform (yc/kubectl показывают узлы и
RUNNING/HEALTHY). - Описан доступ к API (в том числе обходной путь, если прямой закрыт).
- Service LoadBalancer получил настоящий внешний адрес; показан ответ по нему.
- PVC на облачном StorageClass связан с настоящим диском (yc показывает диск).
- Показана/описана работа GitOps на управляемом кластере и отличие окружения от kind.
- Всё снесено, инвентаризация каталога пуста, приведена оценка цены (F30).
6. Частые ошибки и подводные камни
Ждать LoadBalancer на kind. Симптом: EXTERNAL-IP <pending> навсегда. Причина: нет облачного
контроллера. Что делать: LoadBalancer — свойство облака; на kind проверяют NodePort/Gateway (13.06).
kubectl виснет к управляемому кластеру. Симптом: таймаут, Unable to connect. Причина: сеть до
API закрыта (VPN, приватный эндпоинт). Что делать: зайти изнутри облака (ВМ в подсети, внутренний
эндпоинт, IAM-токен как bearer), проверить TCP до порта 443 отдельно.
terraform destroy не убрал всё. Симптом: после destroy остались адрес и диск, идёт счёт. Причина:
NLB и CSI-диск создал облачный контроллер, их нет в state Terraform. Что делать: удалять Service/PVC
через кластер до destroy, после — инвентаризация yc (§3.6).
Роли выданы после кластера. Симптом: LoadBalancer не создаётся, PVC висит. Причина: у сервисного
аккаунта нет vpc.publicAdmin/load-balancer.admin в момент работы контроллера. Что делать: выдавать
роли до кластера (depends_on).
Захардкожена версия, которой нет в канале. Симптом: apply падает на версии k8s. Причина: версия
вне релизного канала. Что делать: сверять yc managed-kubernetes list-versions (на момент урока STABLE
— 1.32–1.35).
Оставили кластер «на потом». Симптом: счёт за мастер-вычисления, узлы, адрес, диски. Причина: не
снесли после проверки. Что делать: terraform destroy сразу, дорогое — под замер с ценой заранее (F30).
7. Проверка усвоения
- Что в управляемом кластере берёт на себя сервис, а что остаётся вам?
- Почему kubectl с вашей машины может не достучаться до кластера и как зайти иначе?
- Почему Service LoadBalancer работает в облаке и не работает на kind?
- Чем облачный StorageClass/CSI отличается от local-path из 13.11?
- Что в GitOps на управляемом кластере такое же, как на kind, а что иначе?
- Почему после
terraform destroyнужна инвентаризация каталога? - Как обосновать цену такой проверки и как её минимизировать?
8. Материалы
- Yandex Managed Service for Kubernetes: обзор — устройство управляемого кластера, мастер и группы узлов. На русском.
- Создание кластера Managed Kubernetes через Terraform —
ресурсы
yandex_kubernetes_clusterи группы узлов, роли сервисного аккаунта. На русском. - Kubernetes: Cloud Controller Manager — как облачный контроллер создаёт LoadBalancer и тома. На английском.
- Уроки 13.06, 13.11, 14.10 этого курса — Service/DNS, тома, GitOps на kind; здесь показано, чем от них отличается облако.
← Предыдущий: 14.14. Эксплуатация ambient: политики, наблюдаемость, отладка, цена решения · Блок 15 · Следующий: 15.02. Управляемый кластер под Terraform: узлы, группы узлов, автомасштабирование узлов →
Practice materials
Scripts, cheat sheets and starter files for the lesson tasks. The lesson text is on this page.
-
Lesson materials 15.01 «Managed Kubernetes в облаке то, чего не показать на kind».zip