Перейти до вмісту

Модуль 1.7: Основи kubeadm — Початкове налаштування кластера

Складність: [MEDIUM] — основи управління кластером

Час на проходження: 60–75 хвилин

Передумови: Модуль 1.1 (Площина управління), Модуль 1.2 (Інтерфейси розширення)


Що ви зможете зробити

Розділ «Що ви зможете зробити»

Після цього модуля ви зможете:

  • Спроєктувати послідовність початкового налаштування kubeadm, яка охоплює попередні перевірки (preflight checks), kubeadm init, встановлення CNI та токени приєднання робочих вузлів.
  • Діагностувати збої статичних Подів і kubelet за допомогою локальних логів, маніфестів та інструментів середовища виконання контейнерів, коли API-сервер недоступний.
  • Оцінити ризики обслуговування сертифікатів і etcd, перевіряючи строк дії, плануючи поновлення та захищаючи знімки перед руйнівними операціями.
  • Впровадити безпечне обслуговування вузлів за допомогою робочих процесів cordon, drain, uncordon та kubeadm reset.

Чому цей модуль важливий

Розділ «Чому цей модуль важливий»

Гіпотетичний сценарій: ви успадковуєте невеликий kubeadm-кластер, на якому працює внутрішній сервіс платформної команди, і площина управління залишається справною, доки рутинне перезавантаження вузла не оголює забутий нюанс початкового налаштування. Нові Поди перестають отримувати IP-адреси, заміна робочого вузла не може приєднатися, а kubectl працює з ноутбука одного адміністратора, але не з іншого. Жоден аспект цього інциденту не вимагає екзотичних знань Kubernetes, проте кластер залишається заблокованим, бо команда знає лише абстракції керованих кластерів і ніколи не зазирала в /etc/kubernetes, маніфести статичних Подів kubelet, токени початкового налаштування чи сертифікати, які kubeadm створює під час ініціалізації.

kubeadm важливий, тому що він навмисно близький до самої механіки. Керовані сервіси приховують більшість цієї механіки, доки щось під ними не дасть тріщину, але іспит CKA очікує від вас міркувань із перших принципів, коли вузол не приєднується, статичний Под знову й знову повертається після видалення, сертифікат наближається до завершення строку дії або осушений вузол лишається непридатним для планування після обслуговування. Мета цього модуля — не запам’ятати кожну підкоманду kubeadm. Мета — пов’язати кожен файл, сертифікат, токен і операцію над вузлом із поведінкою площини управління, яку ви вже вивчали в попередніх модулях.

Уявіть kubeadm як прораба на будівництві з кресленнями. Коли ви запускаєте kubeadm init, він не стає будівлею і не продовжує керувати кожною цеглиною після того, як кластер вже існує. Він закладає фундамент, генеруючи сертифікати та kubeconfig-файли, розміщує площину управління в маніфести статичних Подів, просить kubelet підтримувати ці Поди в робочому стані й виводить інструкцію приєднання для майбутніх робочих вузлів. Щойно цей фундамент закладено, ваша операційна робота змінюється з «запустити інсталятор» на «захищати файли та процеси, які цей інсталятор створив».

Цей модуль переписує стару коротку довідку в робочу ментальну модель. Спершу ви відобразите послідовність початкового налаштування, а потім потренуєте команди, які ініціалізують площину управління, встановлюють мережу, приєднують вузли, перевіряють статичні Поди, захищають сертифікати й дані etcd та виконують обслуговування вузлів. Наприкінці kubeadm-кластер має сприйматися менше як магічний скрипт і більше як набір придатних для огляду контрактів між kubeadm, kubelet, середовищем виконання контейнерів, API-сервером і файлами на диску.


Анатомія початкового налаштування: що будує kubeadm

Розділ «Анатомія початкового налаштування: що будує kubeadm»

kubeadm найкраще розуміти як координатора початкового налаштування, а не як повноцінну платформу управління життєвим циклом кластера. Він перевіряє хост, записує матеріал сертифікатів, створює kubeconfig-файли, формує маніфести статичних Подів і налаштовує достатньо додатків кластера, щоб API-сервер став придатним до використання. Він не встановлює ваше середовище виконання контейнерів, не вирішує дизайн вашого хмарного балансувальника навантаження, не обирає ваш CNI-плагін і не продовжує редагувати вашу операційну систему після ініціалізації кластера. Ця межа корисна, бо робить kubeadm передбачуваним, але вона ж означає, що зламана передумова лишається вашою відповідальністю.

Перший практичний урок полягає в тому, що kubeadm створює площину управління Kubernetes, просячи kubelet запускати статичні Поди. Спочатку такий дизайн здається непрямим: замість запуску kube-apiserver через systemd, kubeadm записує YAML-файл у каталог, за яким ведеться спостереження, і kubelet запускає контейнер із цього маніфесту. Саме тому площина управління kubeadm може відновити контейнер свого API-сервера навіть тоді, коли сам API-сервер тимчасово недоступний. Локальний kubelet є наглядачем для контейнерів площини управління, тож діагностика на рівні файлів лишається можливою, коли діагностика на рівні API — ні.

┌────────────────────────────────────────────────────────────────┐
│ kubeadm init Process │
│ │
│ 1. Pre-flight Checks │
│ └── Verify system requirements (CPU, memory, ports) │
│ │
│ 2. Generate Certificates │
│ └── CA, API server, kubelet, etcd certificates │
│ └── Stored in /etc/kubernetes/pki/ │
│ │
│ 3. Generate kubeconfig Files │
│ └── admin.conf, kubelet.conf, controller-manager.conf │
│ └── Stored in /etc/kubernetes/ │
│ │
│ 4. Generate Static Pod Manifests │
│ └── API server, controller-manager, scheduler, etcd │
│ └── Stored in /etc/kubernetes/manifests/ │
│ │
│ 5. Start kubelet │
│ └── kubelet reads manifests and starts control plane │
│ │
│ 6. Apply Cluster Configuration │
│ └── CoreDNS, kube-proxy DaemonSet │
│ │
│ 7. Generate Join Token │
│ └── For worker nodes to join │
│ │
└────────────────────────────────────────────────────────────────┘

Наведена послідовність дає вам надійний порядок усунення несправностей. Якщо kubeadm init зазнає невдачі ще до запису сертифікатів, ви дивитеся на попередні перевірки, swap, ідентичність хоста, порти та середовище виконання контейнерів. Якщо сертифікати й kubeconfig-файли існують, але API-сервер недоступний, ви перевіряєте логи kubelet і контейнери статичних Подів. Якщо API-сервер доступний, але CoreDNS у стані pending, ви перевіряєте, чи був встановлений CNI-плагін і чи збігається його pod CIDR із конфігурацією кластера. Кожна точка збою звужує простір пошуку, бо kubeadm лишає по собі видимі артефакти.

kubeadm також має навмисні незавдання (non-goals), і ці незавдання важливі для іспиту. Він не встановлює для вас containerd, kubelet, kubeadm чи kubectl. Він не встановлює CNI-плагін під час init, бо вибір CNI залежить від мережевої моделі, яку ви хочете. Він не будує зовнішній балансувальник навантаження для HA-площини управління, бо це належить вашому інфраструктурному рівню. Він може допомогти додати додаткові вузли площини управління, але продакшн-дизайн HA все одно потребує стабільної кінцевої точки перед API-серверами.

Перш ніж запускати kubeadm на свіжому хості, ставтеся до передумов як до частини плану початкового налаштування, а не як до примітки. Відсутній сокет середовища виконання контейнерів, увімкнений swap, дубльована ідентичність хоста або заблокований порт API-сервера спричиняють збої, які виглядають як «Kubernetes зламався», тоді як справжня проблема — у контракті підготовки вузла. Зупиніться й передбачте: якщо kubelet встановлено, але середовище виконання контейнерів зупинене, який крок на діаграмі все ще може завершитися, а який крок мусить зазнати невдачі, коли kubelet спробує запустити контейнери статичних Подів?

Terminal window
# Required on ALL nodes:
# 1. Container runtime (containerd)
# 2. kubelet
# 3. kubeadm
# 4. kubectl (at least on control plane)
# 5. Swap disabled
# 6. Required ports open
# 7. Unique hostname, MAC, product_uuid

Фазова модель kubeadm корисна, коли збій трапляється посеред ініціалізації. kubeadm init — це не одна непрозора дія; це послідовність фаз, які досвідчені оператори можуть переглядати, пропускати або повторно запускати в контрольований спосіб. Для роботи з CKA вам рідко потрібне власне виконання фаз, але знання про те, що фази існують, допомагає читати вивід помилок. Збій під час генерації сертифікатів, генерації kubeconfig, формування статичних Подів або встановлення додатків має інший шлях виправлення, ніж збій під час попередніх перевірок хоста.

Ви можете побачити цей дизайн у виводі команди, коли kubeadm повідомляє про кожен великий крок. Цей вивід є доказом, тож зберігайте його, коли лабораторна робота чи реальний кластер зазнає збою. Якщо фаза попередніх перевірок скаржиться на swap, виправте swap. Якщо формування маніфесту статичного Пода вдалося, але API-сервер так і не став доступним, спускайтеся стеком до kubelet і середовища виконання. Ця дисципліна схожа на читання помилки компілятора: перший значущий збій зазвичай дає кращу зачіпку, ніж каскад пізніших симптомів.

На іспиті CKA питання про kubeadm зазвичай менше стосуються побудови продакшн-кластера з порожньої віртуальної машини й більше — розпізнавання того, де kubeadm розмістив рухомі частини. Проте модель початкового налаштування окупається й поза іспитом. Якщо ви знаєте, що сертифікати лежать у /etc/kubernetes/pki, що маніфести Подів площини управління лежать у /etc/kubernetes/manifests, а kubelet є локальним наглядачем, ви можете діагностувати збої навіть тоді, коли API кластера тимчасово недоступний.


Ініціалізація площини управління та встановлення мережі

Розділ «Ініціалізація площини управління та встановлення мережі»

Команда kubeadm init запускає площину управління, але прапорці, які ви обираєте, кодують припущення, що й далі впливатимуть на кластер. Pod network CIDR має збігатися з CNI-плагіном, який ви плануєте встановити. Адреса оголошення (advertise address) API-сервера має бути досяжною для вузлів, що приєднуватимуться. Закріплення версії Kubernetes контролює версії образів площини управління і має узгоджуватися з пакетами, які ви встановили на хості. Це не декоративні прапорці; це перші тривкі рішення в кластері.

Terminal window
# Initialize control plane
sudo kubeadm init
# With specific pod network CIDR (required by some CNIs)
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
# With specific API server address (for HA or custom networking)
sudo kubeadm init --apiserver-advertise-address=192.168.1.10
# With specific Kubernetes version
sudo kubeadm init --kubernetes-version=v1.35.0

Найпростіша команда корисна в лабораторії, але реальне усунення несправностей часто починається з більш явних варіантів. Якщо вузол приєднується, але Поди не можуть спілкуватися, pod CIDR і конфігурація CNI — перші підозрювані. Якщо робочий вузол отримує команду приєднання, що містить адресу, до якої він не може маршрутизувати, підозрюваним є вибір адреси оголошення або кінцевої точки площини управління. Якщо пакети й образи площини управління походять із різних мінорних версій, правила розбіжності версій (version skew) мають значення ще до того, як ви припустите, що винна мережа.

Для відтворюваних кластерів конфігураційний файл kubeadm безпечніший за довгий командний рядок, скопійований зі сторінки нотаток. Файл фіксує налаштування кластера, як-от версія Kubernetes, pod subnet, service subnet, репозиторій образів, кінцева точка API-сервера та альтернативні імена суб’єкта сертифіката (SAN), в одному придатному для огляду артефакті. Це важливо в командах, бо інший оператор може перевірити заплановані значення початкового налаштування до запуску команди. Це також важливо під час перебудов, бо другу площину управління не варто ініціалізувати з чиєїсь пам’яті про першу.

Terminal window
# Generate a starting point for a reviewed kubeadm configuration
kubeadm config print init-defaults
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.35.0
controlPlaneEndpoint: "192.168.1.10:6443"
networking:
podSubnet: 10.244.0.0/16

Коли ви використовуєте конфігураційний файл, команда стає простішою, а огляд — чіткішим. Ви можете порівняти обраний pod subnet із документацією CNI, підтвердити кінцеву точку площини управління перед приєднанням робочих вузлів і зберігати файл у внутрішньому runbook без зберігання токенів початкового налаштування. Файл не усуває потреби готувати хости, але зменшує ймовірність того, що критичний вибір початкового налаштування буде прихований в історії команд оболонки.

Terminal window
# Initialize from a reviewed configuration file
sudo kubeadm init --config kubeadm-config.yaml

Після ініціалізації kubeadm записує адміністративний kubeconfig, але не копіює цей файл у домашній каталог кожного користувача. Саме тому свіжоініціалізований кластер може існувати, тоді як kubectl get nodes зазнає невдачі для звичайного користувача оболонки. API-сервер може працювати, але kubectl все одно потребує облікових даних і даних підключення до кластера. Перед тим як це запускати: який вивід ви очікуєте від kubectl get nodes до копіювання kubeconfig і що зміниться після того, як $HOME/.kube/config вказуватиме на admin.conf?

Terminal window
# For regular user (recommended)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# For root user
export KUBECONFIG=/etc/kubernetes/admin.conf

Наступний крок — встановлення CNI. Без CNI-плагіна kubelet може запускати статичні Поди площини управління, але звичайні Поди не можуть отримати маршрутизовані pod-IP, а CoreDNS зазвичай лишається в стані pending або not ready. Ця відмінність важлива: kubeadm-кластер може виглядати частково живим до встановлення мережі. API-сервер може відповідати на запити, проте робочі навантаження лишаються нездатними спілкуватися, бо мережевий рівень ще не виконав свою частину контракту кластера.

Перед запуском будь-якої команди встановлення CNI оберіть рівно один CNI і спершу перевірте актуальну документацію постачальника. Версія Kubernetes, передумови ядра, режим kube-proxy, pod CIDR і метод встановлення можуть змінюватися від випуску до випуску плагіна, тож застарілі однорядкові маніфести — поганий навчальний патерн для кластера Kubernetes 1.35. Використовуйте команди з актуальної документації для того плагіна, який ви насправді обрали, і записуйте версію чи канал випуску в нотатках лабораторної роботи, щоб подальше усунення несправностей мало фактичну відправну точку.

Terminal window
# Without CNI, pods won't get IPs and CoreDNS won't start
# Calico: read current Kubernetes support and install steps first.
# https://docs.tigera.io/calico/latest/getting-started/kubernetes/requirements
# https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart
#
# Flannel: use the current release or Helm path from the upstream project.
# https://github.com/flannel-io/flannel
#
# Cilium: install the Cilium CLI first, then follow the current install docs.
# https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/

Ці вказівники на CNI — лабораторні запобіжники, а не рекомендація копіювати команду без читання актуального посібника зі встановлення обраного постачальника. Захищений урок — це послідовність: ініціалізуйте площину управління, налаштуйте kubectl, встановіть один CNI, який відповідає вибору pod-мережі, а потім перевірте системні Поди. Змішування кількох CNI за логікою «більше мережі має допомогти» створює конфліктні агенти, які борються за мережу Подів і ускладнюють діагностику.

Terminal window
# Check nodes
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# control-plane Ready control-plane 5m v1.35.0
# Check system pods
kubectl get pods -n kube-system
# Should see: coredns, etcd, kube-apiserver, kube-controller-manager,
# kube-proxy, kube-scheduler, CNI pods

Перевірку слід тлумачити, а не сприймати як ритуал «пройдено чи ні». Один вузол площини управління може повідомляти Ready, тоді як CoreDNS усе ще запускається, а свіжовстановленому CNI може знадобитися короткий проміжок, щоб створити Поди свого DaemonSet. Патерн, якого ви прагнете, — це сходження до робочого стану: вузол стає готовим, Поди kube-system перестають циклічно падати, CoreDNS отримує робочі репліки, а Поди CNI потрапляють на вузли, що потребують мережі Подів. Якщо кластер застряг, зіставте симптом із послідовністю початкового налаштування, а не запускайте kubeadm init наосліп.

Корисний практичний приклад — хост площини управління, де kubeadm init --pod-network-cidr=10.244.0.0/16 вдається, kubectl get nodes працює після копіювання kubeconfig, але CoreDNS лишається в стані pending. Наступна команда — не kubeadm reset; це kubectl get pods -n kube-system -o wide, щоб побачити, чи існує DaemonSet CNI і де заплановані Поди. Якщо Подів CNI немає, встановіть призначений CNI. Якщо Поди CNI існують, але циклічно падають, перевірте їхні логи й переконайтеся, що pod CIDR і передумови ядра/мережі відповідають плагіну.

kubeadm також зберігає конфігурацію кластера в кластері після ініціалізації, що дає вам ще один спосіб перевірити, що було задумано. ConfigMap kubeadm-config у kube-system записує налаштування, до яких можуть звертатися майбутні операції kubeadm, особливо оновлення. Це не замінює ваш runbook, бо зламаний API-сервер може зробити ConfigMap недосяжним, але це цінно, коли кластер достатньо справний для перевірки через API. Якщо збережена конфігурація й ваші припущення розходяться, довіряйте доказам і оновіть runbook.

Terminal window
# Inspect kubeadm's stored cluster configuration
kubectl -n kube-system get configmap kubeadm-config -o yaml

Приєднання вузлів і захист довіри початкового налаштування

Розділ «Приєднання вузлів і захист довіри початкового налаштування»

Приєднання робочих вузлів легко скопіювати й легко зрозуміти неправильно. Команда приєднання містить токен початкового налаштування, який автентифікує новий вузол для його початкової реєстрації, і містить хеш CA-сертифіката, що дозволяє вузлу переконатися, що він спілкується з призначеною площиною управління. Токен відповідає на питання «чи дозволено мені починати приєднання?», а хеш CA — на «чи приєднуюся я до правильного кластера?». Обидві частини мають значення, бо початкове налаштування вузла відбувається до того, як вузол отримає свій довготривалий клієнтський сертифікат kubelet.

Terminal window
# Example output from kubeadm init
kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:abc123...

Запускайте команду приєднання на робочому вузлі після того, як там встановлено середовище виконання, kubelet і kubeadm. Робочий вузол потребує мережевої досяжності кінцевої точки API-сервера, достатньо узгодженого часу для перевірки сертифіката, справного середовища виконання контейнерів і токена, строк дії якого не завершився. Невдале приєднання часто є локальною проблемою підготовки вузла, а не проблемою площини управління, тож перші логи для читання зазвичай — на робочому вузлі, що приєднується.

Terminal window
# On worker node (as root)
sudo kubeadm join 192.168.1.10:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:abc123...

Токени початкового налаштування за замовчуванням мають обмежений строк дії, і це радше функція, ніж незручність. Команда приєднання, вставлена в тикет, чат або історію команд оболонки, не повинна авторизувати нові вузли вічно. Операційна звичка — генерувати свіжу команду за потреби, використовувати її під час контрольованого вікна обслуговування й видаляти старі токени або дозволяти їм завершити строк дії. Який підхід ви б тут обрали й чому: довготривалий токен для зручності чи короткотривалі токени, що генеруються як частина runbook кожного додавання вузла?

Terminal window
# On control plane - create new token
kubeadm token create --print-join-command
# Or manually:
# 1. Create token
kubeadm token create
# 2. Get CA cert hash
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
openssl rsa -pubin -outform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
# 3. Construct join command
kubeadm join <control-plane-ip>:6443 --token <new-token> \
--discovery-token-ca-cert-hash sha256:<hash>

Ручний процес варто вивчити, навіть якщо --print-join-command швидший, бо він оголює модель довіри. Хеш походить від публічного ключа CA кластера, а не від короткотривалого токена. Якщо строк дії токена завершився, ви створюєте новий токен; якщо хеш CA неправильний, вузол має відмовитися довіряти кінцевій точці. Коли робочий вузол не може приєднатися, читання точної помилки має значення, бо «token invalid», «x509», «connection refused» і «timed out» вказують на різні рівні.

Terminal window
# List existing tokens
kubeadm token list
# Delete a token
kubeadm token delete <token>
# Create token with custom TTL
kubeadm token create --ttl 2h

Ставтеся до управління токенами як до частини гігієни кластера. У крихітному лабораторному кластері токени з вичерпаним строком дії — переважно лише невелика затримка. У спільному середовищі забуті токени початкового налаштування стають заплутаним операційним станом і можуть розширити вікно, протягом якого небажаний хост зможе спробувати зареєструватися. Виправлення нескладне: переглядайте токени перед приєднанням, створюйте токен із розумним TTL, документуйте, який вузол його використав, і прибирайте токени, які вже не потрібні.

Сценарій вправи: робочий вузол було підготовлено з того самого образу, що й наявний вузол, але kubeadm join зазнає невдачі з помилкою про те, що вузол уже існує. Це сигнал перевірити ідентичність хоста й старий стан kubelet, перш ніж винуватити токен. Клонована віртуальна машина може нести застарілі дані /var/lib/kubelet, дубльовану машинну ідентичність або ім’я хоста, що конфліктує з наявним об’єктом вузла. Скиньте й очистіть вузол, виправте ім’я хоста й повторно запустіть приєднання зі свіжою командою, замість того щоб змушувати API-сервер приймати неоднозначну ідентичність.


Статичні Поди, файли, сертифікати та etcd

Розділ «Статичні Поди, файли, сертифікати та etcd»

Статичні Поди — це ключ до діагностики площини управління kubeadm. Звичайний Деплоймент узгоджується контролерами через API-сервер; статичний Под читається kubelet безпосередньо з файлу. kubeadm використовує статичні Поди для kube-apiserver, kube-controller-manager, kube-scheduler і локального etcd, бо ці компоненти мусять існувати раніше, ніж контролери вищого рівня зможуть будь-чим керувати. Це і є цикл початкового налаштування: kubelet запускає API-сервер, і лише потім API-сервер може показати дзеркальні Поди (mirror pods), які роблять статичні Поди видимими через kubectl.

Terminal window
# Static pod manifests location
ls /etc/kubernetes/manifests/
# etcd.yaml
# kube-apiserver.yaml
# kube-controller-manager.yaml
# kube-scheduler.yaml

API-сервер показує дзеркальні Поди для видимості, але він не володіє джерелом істини для статичних Подів. Якщо ви видалите дзеркальний Под за допомогою kubectl, kubelet помітить, що файл маніфесту все ще існує, і відтворить об’єкт дзеркального Пода в API. Базовий контейнер при цьому НЕ перезапускається — kubelet не видаляє маніфест, тож процес статичного Пода продовжує працювати без переривання. Це класична пастка CKA: видалення дзеркального Пода за допомогою kubectl не перезапускає застряглий компонент площини управління, бо операція API ніколи не досягає середовища виконання. Така поведінка дивує лише тоді, коли ви припускаєте, що кожен Под, видимий через API, керується через API. Зупиніться й передбачте: якщо ви запустите kubectl delete pod kube-apiserver-controlplane -n kube-system, що зміниться (а що — ні) на рівні середовища виконання контейнерів і який файл визначає відповідь?

┌────────────────────────────────────────────────────────────────┐
│ Static Pod Lifecycle │
│ │
│ /etc/kubernetes/manifests/ │
│ │ │
│ │ kubelet watches this directory │
│ ▼ │
│ ┌─────────────┐ │
│ │ kubelet │ │
│ └──────┬──────┘ │
│ │ │
│ │ For each YAML file: │
│ │ 1. Start container │
│ │ 2. Keep it running │
│ │ 3. Restart if it crashes │
│ │ 4. Create mirror pod in API server │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Control Plane Containers │ │
│ │ • kube-apiserver │ │
│ │ • kube-controller-manager │ │
│ │ • kube-scheduler │ │
│ │ • etcd │ │
│ └─────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘

Редагування маніфестів статичних Подів є потужним і ризикованим, бо kubelet застосовує результат автоматично. Дійсне редагування перезапускає компонент із новими прапорцями; недійсне редагування може зупинити API-сервер, scheduler, controller manager або etcd. Найбезпечніша звичка — зробити копію з часовою міткою поза /etc/kubernetes/manifests/, змінити одну річ, тримати відкритою root-оболонку на вузлі площини управління й використовувати локальні логи, якщо API зникне. Не залишайте kube-apiserver.yaml.bak чи будь-який інший резервний файл усередині каталогу маніфестів, за яким ведеться спостереження, бо kubelet ставиться до файлів без крапки на початку як до кандидатів на маніфести статичних Подів, а не як до нешкідливих нотаток. Для практики до іспиту ключова відмінність проста: kubectl може показати статичний Под, але файл маніфесту керує ним.

Terminal window
# Make a safe backup OUTSIDE the watched manifest directory
sudo mkdir -p /etc/kubernetes/backup
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml \
/etc/kubernetes/backup/kube-apiserver.yaml.$(date -u +%Y%m%dT%H%M%SZ)
# View static pod manifests
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
# Modify a static pod (edit the manifest)
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
# kubelet automatically restarts the pod
# "Delete" a static pod (remove the manifest)
sudo mv /etc/kubernetes/manifests/kube-scheduler.yaml /tmp/
# kubelet stops the pod
# Restore it
sudo mv /tmp/kube-scheduler.yaml /etc/kubernetes/manifests/
# kubelet starts the pod again

Розкладка каталогів — це карта, якою ви користуєтеся, коли інструменти рівня API перестають працювати. /etc/kubernetes/admin.conf — це адміністративний kubeconfig. /etc/kubernetes/manifests містить визначення статичних Подів. /etc/kubernetes/pki містить CA кластера, сертифікати API-сервера, ключі підписання сервісних акаунтів, матеріал front-proxy і сертифікати etcd. Коли ви знаєте ці шляхи, «площина управління лежить» перестає бути розпливчастою панікою й стає розслідуванням на рівні файлів і процесів.

/etc/kubernetes/
├── admin.conf # kubectl config for admin
├── controller-manager.conf # kubeconfig for controller-manager
├── kubelet.conf # kubeconfig for kubelet
├── scheduler.conf # kubeconfig for scheduler
├── manifests/ # Static pod definitions
│ ├── etcd.yaml
│ ├── kube-apiserver.yaml
│ ├── kube-controller-manager.yaml
│ └── kube-scheduler.yaml
└── pki/ # Certificates
├── ca.crt # Cluster CA
├── ca.key
├── apiserver.crt # API server cert
├── apiserver.key
├── apiserver-kubelet-client.crt
├── front-proxy-ca.crt
├── sa.key # ServiceAccount signing key
├── sa.pub
└── etcd/ # etcd certificates
├── ca.crt
└── ...

kubeconfig-файли в цьому каталозі теж варто називати уважно. admin.conf призначений для адміністрування кластера, тоді як kubelet.conf, controller-manager.conf і scheduler.conf — це клієнтські облікові дані для компонентів, що спілкуються з API-сервером. Якщо адміністратор скопіює не той файл у $HOME/.kube/config, поведінка авторизації, що виникне, може заплутати. Якщо kubeconfig компонента застарілий або нечитабельний, компонент може запуститися, але не пройти автентифікацію на API-сервері, тож діагностика сертифікатів і kubeconfig часто відбувається разом.

Права доступу до файлів — це частина моделі безпеки, а не лише дрібниця адміністрування Linux. Приватний ключ CA, ключ підписання сервісних акаунтів і приватні ключі etcd можуть авторизувати або підписувати надзвичайно чутливу поведінку кластера. Хороша резервна копія захоплює те, що потрібне для відновлення, але необачне копіювання в спільний каталог створює інший інцидент. Коли ви перевіряєте ці файли, використовуйте мінімально необхідний доступ, тримайте копії захищеними й видаляйте тимчасові діагностичні копії після вікна обслуговування.

Управління сертифікатами — це місце, де зустрічаються зручність kubeadm і ваша відповідальність. kubeadm може перевіряти завершення строку дії сертифікатів і поновлювати сертифікати, якими він керує, але поновлені файли не мають значення, доки уражені компоненти не перезавантажать їх. Компоненти на статичних Подах зазвичай перезавантажуються через перезапуск, який можна здійснити, перемістивши маніфести назовні й назад, дозволивши kubelet відтворити контейнери, або перезапустивши kubelet у запланованому вікні обслуговування. Вам також варто знати, які kubeconfig-файли потрібно повторно скопіювати після поновлення адміністративних облікових даних.

Terminal window
# Cluster CA
/etc/kubernetes/pki/ca.crt
/etc/kubernetes/pki/ca.key
# API Server
/etc/kubernetes/pki/apiserver.crt
/etc/kubernetes/pki/apiserver.key
# etcd CA (separate CA)
/etc/kubernetes/pki/etcd/ca.crt
/etc/kubernetes/pki/etcd/ca.key
# Check certificate expiration
kubeadm certs check-expiration

etcd заслуговує на окрему увагу, бо він зберігає стан кластера. Резервне копіювання etcd перед руйнівним обслуговуванням площини управління не є необов’язковим у серйозному середовищі, навіть коли іспит лише просить продемонструвати механіку. Команда знімка має використовувати кінцеву точку etcd і правильні клієнтські сертифікати, а відновлення слід планувати ретельно, бо воно замінює стан, який читатиме API-сервер. Резервна копія, яку ви ніколи не перевіряли, ближча до надії, ніж до плану відновлення.

Terminal window
# Save an etcd snapshot on a stacked-control-plane kubeadm node
sudo ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /var/backups/etcd-snapshot.db
# Inspect the snapshot before trusting it
sudo ETCDCTL_API=3 etcdctl snapshot status /var/backups/etcd-snapshot.db --write-out=table

Відновлення etcd — це руйнівна дія відновлення, а не буденна команда обслуговування. У лабораторії з одновузловим вбудованим (stacked) etcd патерн відновлення такий: зупинити площину управління, відновити знімок у новий каталог даних за допомогою etcdutl, оновити маніфест статичного Пода etcd, щоб він вказував на цей каталог, якщо потрібно, а потім дозволити kubelet перезапустити etcd і API-сервер. Старіша форма etcdctl snapshot restore — це застаріла настанова; актуальна документація з відновлення Kubernetes і etcd використовує etcdutl для відновлення, тоді як etcdctl лишається поширеним для збереження живих знімків. У топології з кількома членами etcd процедура має враховувати кворум та ідентичність членів, тож не узагальнюйте рецепт одновузлової лабораторії в продакшн-runbook.

Terminal window
# Example lab restore target; plan production restores from the official etcd guidance
sudo etcdutl snapshot restore /var/backups/etcd-snapshot.db \
--data-dir=/var/lib/etcd-from-backup

Оновлення вписуються в ту саму модель ризику. kubeadm може спланувати й застосувати оновлення площини управління, але ви все одно осушуєте вузли, дотримуєтеся розбіжності версій, оновлюєте пакети kubelet і kubectl та перевіряєте кожен крок перед тим, як рухатися далі. Безпечний порядок — спершу площина управління, потім робочі вузли по одному, з планом відкату й резервного копіювання, що існує до того, як ви торкнетеся першого компонента. Для цілей CKA знайте форму робочого процесу й команди, якими ви перевіряєте план.

Terminal window
# Step 1: upgrade the kubeadm binary itself to the target version FIRST.
# `kubeadm upgrade apply` validates that the running kubeadm matches the
# target version, so skipping this step fails immediately. Exact package
# string varies by distro and repo (apt example shown).
sudo apt-get update && sudo apt-get install -y --allow-change-held-packages kubeadm=1.35.1-1.1
# Step 2: control-plane planning step (read-only, safe to re-run)
sudo kubeadm upgrade plan
# Step 3: control-plane apply for a patch release in the same minor line
sudo kubeadm upgrade apply v1.35.1
# Step 4: upgrade kubelet and kubectl packages, then restart kubelet
sudo apt-get install -y --allow-change-held-packages kubelet=1.35.1-1.1 kubectl=1.35.1-1.1
sudo systemctl daemon-reload
sudo systemctl restart kubelet

Важливий зв’язок полягає в тому, що сертифікати, знімки etcd, маніфести статичних Подів та оновлення — не окремі теми. Усі вони є операціями обслуговування навколо одного набору активів, створених kubeadm. Якщо ви можете прочитати розкладку файлів і пояснити, який локальний процес споживає кожен файл, ви можете міркувати про поведінку поновлення, відновлення, перезапуску й оновлення, не покладаючись на завчений скрипт.


Обслуговування вузлів, скидання та відновлення

Розділ «Обслуговування вузлів, скидання та відновлення»

Обслуговування вузлів починається з наміру щодо планування. Cordon каже «не розміщуй тут нові Поди»; drain каже «виселити Поди, які можуть безпечно переміститися». Ця відмінність важлива, бо вузол із cordon усе ще може виконувати наявні робочі навантаження, а перезавантаження все одно може їх перервати. Drain використовує API виселення (eviction API) для керованих Подів, дотримується багатьох засобів контролю доступності й лишає Поди DaemonSet недоторканими, якщо ви не використаєте додаткові прапорці. Правильна команда залежить від того, запобігаєте ви майбутньому розміщенню чи готуєтеся до руйнівної роботи.

Terminal window
# List nodes
kubectl get nodes
# Detailed info
kubectl get nodes -o wide
# Node details
kubectl describe node <node-name>

Хороша діагностика вузла починається з розділення бажаного стану планування й стану справності. Вузол може бути в стані Ready,SchedulingDisabled, що означає, що kubelet справний, але scheduler не має дозволу розміщувати там нові Поди. Вузол може бути в стані NotReady, що означає, що площина управління не отримала справного статусу від kubelet чи пов’язаних компонентів. Ці стани передбачають різні наступні кроки. Зупиніться й подумайте: якщо ви лише виконаєте cordon вузла перед обслуговуванням ядра, який ризик лишається, з яким би впорався drain?

Terminal window
# Drain node (evict pods, mark unschedulable)
kubectl drain <node-name> --ignore-daemonsets
# If there are pods with local storage:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
# Force (for pods without controllers):
kubectl drain <node-name> --ignore-daemonsets --force

Прапорці drain мають змусити вас зробити паузу, бо кожен із них кодує компроміс. --ignore-daemonsets є нормою, бо Поди DaemonSet очікувано живуть на вузлі й не можуть бути осушені так само, як Поди Деплойменту. --delete-emptydir-data визнає, що дані в томах emptyDir є локальними для вузла й будуть видалені разом із Подом. --force — це сильніше твердження: ви готові видалити Поди, які не мають контролера для повторного створення. Використовуйте його свідомо, а не на автоматизмі.

Terminal window
# Mark node unschedulable (no new pods)
kubectl cordon <node-name>
# Mark node schedulable again
kubectl uncordon <node-name>
# Check node status
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# node1 Ready worker 10d v1.35.0
# node2 Ready,SchedulingDisabled worker 10d v1.35.0 # cordoned

Відновлення після обслуговування не завершується, коли вузол перезавантажується. Ви перевіряєте, що kubelet працює, що вузол повертається в стан Ready, що критичні DaemonSet справні, і що з вузла знято cordon, якщо він має отримувати робочі навантаження. Поширений операційний недогляд — правильно виконати обслуговування й потім залишити вузол із cordon на кілька днів. Кластер продовжує працювати, але ємність нижча, сигнали автомасштабування заплутуються, а майбутні drain мають менше місця для переміщення Подів.

Terminal window
# 1. Drain the node first
kubectl drain <node-name> --ignore-daemonsets --force
# 2. Delete from cluster
kubectl delete node <node-name>
# 3. On the node itself, reset kubeadm
sudo kubeadm reset
# 4. Optional post-reset cleanup after preserving evidence
sudo rm -rf /etc/cni/net.d/
rm -rf $HOME/.kube
# Clean kube-proxy rules with the documented kube-proxy --cleanup method.

Видалення вузла остаточніше за його осушення. Видалення об’єкта Node каже кластеру припинити відстеження цього хоста, тоді як kubeadm reset виконує локальне очищення на хості за принципом «найкраще зусилля» (best-effort). Команди очищення навмисно руйнівні, тож їхнє місце — у лабораторії, runbook виведення з експлуатації чи контрольованій перебудові, а не в буденному циклі усунення несправностей. Якщо вам потрібно лише перезапустити kubelet чи виправити файл конфігурації CNI, скидання вузла викидає корисні докази й створює зайву роботу.

Terminal window
# On the node to reset
sudo kubeadm reset
# kubeadm reset is best-effort LOCAL cleanup:
# 1. Removes kubeadm-managed local files and certificates.
# 2. Removes this node's local stacked etcd member data when applicable.
# 3. Does not remove generic cluster state from a surviving etcd cluster.
# 4. Does not clean CNI config, $HOME/.kube, or kube-proxy rules.
# Additional cleanup kubeadm reset does NOT do automatically:
sudo rm -rf /etc/cni/net.d/
rm -rf $HOME/.kube
# For kube-proxy network rules, follow the kubeadm reset reference:
# run kube-proxy --cleanup from the same kube-proxy image version/runtime
# your cluster used. Do not assume an iptables flush is complete, because
# kube-proxy may have programmed iptables, IPVS, or nftables state.

Скидання також має іспитову пастку: воно не стирає магічним чином кожен можливий мережевий, обліковий чи runtime-артефакт у кожному середовищі. Файли конфігурації CNI, $HOME/.kube, правила трафіку kube-proxy, стан IPVS чи nftables, образи контейнерів і дані середовища виконання можуть потребувати окремого очищення залежно від того, як був підготовлений вузол. Саме тому вивід kubeadm reset і довідкова сторінка кажуть вам, що воно зробило і що вам, можливо, ще потрібно очистити. Читайте вивід, а не припускайте, що скидання означає «як новий з заводу».


Усунення несправностей без робочого API-сервера

Розділ «Усунення несправностей без робочого API-сервера»

Найшвидша звичка усунення несправностей kubeadm — обирати інструмент, який усе ще працює на рівні, де стався збій. Якщо API-сервер справний, kubectl зручний і виразний. Якщо API-сервер лежить, kubectl може зависати, але логи kubelet, статус systemd, інструменти середовища виконання контейнерів і маніфести статичних Подів усе ще доступні на вузлі. Якщо сам kubelet зупинено, навіть відновлення статичних Подів залежить від спершу виправлення локального сервісу. Цей пошаровий підхід запобігає поширеній помилці — раз за разом запускати API-клієнт проти мертвого API.

Terminal window
# Check kubelet status
systemctl status kubelet
# Check kubelet logs
journalctl -u kubelet -f
# Common issues:
# - Swap not disabled
# - Container runtime not running
# - Wrong container runtime socket

Коли ви збираєте докази, фіксуйте і команду, і вузол, на якому ви її запускали. Лог kubelet з робочого вузла, який не може приєднатися, розповідає іншу історію, ніж лог kubelet з вузла площини управління, який не може запустити API-сервер. Так само результат crictl ps з неправильного хоста може відправити вас у погоню за відсутніми контейнерами, які ніколи й не мали там працювати. Маркування доказів за іменем вузла, роллю й часом утримує невеликий інцидент від перетворення на купу розрізнених фрагментів.

Коли kubelet не запускається, розслідування є локальним і механічним. Перевірте, чи увімкнено й чи працює сервіс, чи посилається його конфігураційний файл на дійсну кінцеву точку середовища виконання контейнерів і чи може саме середовище виконання запускати контейнери. Повідомлення в логах kubelet зазвичай називають відсутній сокет, недійсний прапорець, невідповідність cgroup чи проблему з сертифікатом. Не починайте з видалення об’єктів кластера; агент вузла має бути справним, перш ніж площина управління зможе отримувати корисний статус.

Terminal window
# Check container runtime
crictl ps
# Check static pod containers
crictl logs <container-id>
# Look for API server errors
sudo cat /var/log/pods/kube-system_kube-apiserver-*/kube-apiserver/*.log

Коли площина управління не запускається, локальне середовище виконання контейнерів стає вашим вікном у збій. crictl ps каже вам, чи існують контейнери статичних Подів, чи перезапускаються вони і який ідентифікатор контейнера перевіряти. Логи контейнерів можуть розкрити недійсний прапорець API-сервера, нечитабельний сертифікат, збій підключення до etcd чи синтаксичну помилку YAML у маніфесті. Якщо API-сервер недоступний, виправлення часто відбувається в /etc/kubernetes/manifests, а не через kubectl.

Terminal window
# On the node, check logs
journalctl -u kubelet | tail -50
# Common issues:
# - Token expired
# - Wrong CA hash
# - Network connectivity to control plane
# - Firewall blocking port 6443

Збої приєднання вузла вимагають від вас вирішити, чи робочий вузол не може досягти API-сервера, не може йому довіряти, чи не може завершити локальне початкове налаштування. Таймаут вказує на маршрутизацію, фаєрвол, кінцеву точку чи доступність API-сервера. Помилка хешу CA чи x509 вказує на матеріал довіри. Помилка kubelet чи середовища виконання вказує назад на підготовку вузла. Ці категорії корисніші за завчання одного виправлення для «вузол не приєднується», бо той самий симптом на рівні дашборда може походити з кількох різних рівнів.

Terminal window
# Check expiration
kubeadm certs check-expiration
# Renew all certificates
kubeadm certs renew all
# Restart control plane components
# (just move manifests and wait)

Збої сертифікатів особливо легко прочитати неправильно, бо вони часто проявляються як загальні помилки підключення. Команда поновлення записує нові файли сертифікатів, але її запуск — це не те саме, що доказ того, що площина управління їх перезавантажила. Перевіряйте строк дії до й після, перезапускайте або перезавантажуйте відповідні статичні Поди й перевіряйте клієнтські kubeconfig, де потрібно. Якщо задіяні сертифікати etcd, будьте уважні, щоб відрізнити серверні (serving) сертифікати API-сервера від однорангових (peer) і клієнтських сертифікатів etcd, бо їх споживають різні процеси.

Релевантний для іспиту набір команд достатньо короткий, щоб тренувати його до плавності, але плавність має включати контекст. kubeadm token create --print-join-command призначений для довіри початкового налаштування, а не для виправлення зламаного CNI. kubectl drain призначений для переміщення робочих навантажень перед обслуговуванням, а не для видалення локального стану kubeadm вузла. kubeadm reset призначений для демонтажу чи перебудови, а не для кожного попередження kubelet. Використовуйте команду, яка відповідає зламаному контракту.

Terminal window
# Initialize cluster
kubeadm init --pod-network-cidr=10.244.0.0/16
# Get join command
kubeadm token create --print-join-command
# Join worker
kubeadm join <control-plane>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
# Check certificates
kubeadm certs check-expiration
# Drain node for maintenance
kubectl drain <node> --ignore-daemonsets
# Make node schedulable again
kubectl uncordon <node>
# Reset node
kubeadm reset

Практичний приклад: адміністратор редагує /etc/kubernetes/manifests/kube-apiserver.yaml, щоб додати прапорець допуску (admission flag), але лишає помилку відступу YAML. Тепер kubectl get nodes повертає connection refused, що очікувано, бо контейнер API-сервера не може запуститися. Шлях відновлення — підключитися по SSH до вузла площини управління, переглянути journalctl -u kubelet, переглянути логи збійного контейнера API-сервера через crictl, виправити маніфест локальним редактором і дочекатися, поки kubelet відтворить статичний Под. Урок конкретний: коли API-сервер є зламаним компонентом, локальні інструменти вузла замінюють інструменти API, доки статичний Под знову не стане справним.

Інший корисний сценарій — робочий вузол, що повідомляє NotReady після перезавантаження, навіть коли площина управління справна. Почніть з kubectl describe node, якщо API досяжний, потім перейдіть до робочого вузла й перевірте kubelet, середовище виконання контейнерів, конфігурацію CNI та свіжі логи. Якщо kubelet не може автентифікуватися, порівняйте /etc/kubernetes/kubelet.conf і сертифікати; якщо Поди не можуть створити пісочниці (sandboxes), перевірте файли CNI й помилки середовища виконання. Об’єкт вузла дає вам симптом, але локальні докази робочого вузла зазвичай дають причину.


Патерни й антипатерни

Розділ «Патерни й антипатерни»

Наведені нижче патерни — не загальні «найкращі практики»; це звички прийняття рішень, які утримують операції kubeadm оборотними й придатними для діагностики. kubeadm-кластер достатньо прозорий, щоб ви могли перевірити майже кожен важливий артефакт, але ця прозорість допомагає лише тоді, коли ви робите одну зміну за раз і зберігаєте докази перед руйнівними діями. У невеликих лабораторіях нехтування цією дисципліною коштує хвилин. У спільному кластері воно може перетворити звичайне завдання обслуговування на вправу з відновлення.

ПатернКоли його застосовуватиЧому він працюєМіркування щодо масштабування
Початкове налаштування з явними вхідними данимиВикористовуйте під час ініціалізації чи перебудови площини управлінняPod CIDR, адреса оголошення й закріплення версії роблять пізніші симптоми легшими для поясненняЗберігайте обрані значення в runbook чи конфігураційному файлі kubeadm для відтворюваності
Діагностика з рівня, що вцілівВикористовуйте, коли kubectl зависає чи API-сервер недоступнийkubelet, systemd, crictl і файли маніфестів лишаються доступними локальноНавчіть операторів підключатися по SSH до правильного вузла й збирати локальні логи перед скиданням
Захист стану перед руйнуваннямВикористовуйте перед оновленнями, ротацією сертифікатів чи редагуванням статичних ПодівЗнімки etcd і скопійовані маніфести надають докази для відкатуАвтоматизуйте перевірку резервних копій і тримайте процедури відновлення окремими для одновузлового й HA etcd
Drain перед обслуговуванням хостаВикористовуйте перед перезавантаженням, оновленням пакетів чи видаленням вузлаРобочі навантаження переміщуються шляхом виселення Kubernetes замість раптової загибеліЄмність і PodDisruptionBudget визначають, чи може drain завершитися швидко

Відповідні антипатерни спокусливі, бо здаються швидшими в моменті. Повторний запуск kubeadm init здається рішучим, примусовий drain ніби розчищає затор, а видалення статичного Пода через kubectl виглядає природним, бо Под видимий через API. Кожне з цих скорочень ігнорує право власності. kubeadm володіє артефактами початкового налаштування, kubelet володіє виконанням статичних Подів, scheduler володіє новим розміщенням, контролери володіють заміною Подів, а etcd володіє станом кластера.

АнтипатернЩо йде не такКраща альтернатива
Повторний запуск kubeadm init на напівробочій площині управлінняВи ризикуєте перезаписати докази й створити конфліктний локальний станЧитайте логи kubelet, логи статичних Подів і вивід kubeadm, щоб визначити збійну фазу
Сприйняття kubectl delete pod як видалення статичного Подаkubelet відтворює дзеркальний Под, бо маніфест усе ще існуєПеремістіть, відредагуйте чи відновіть маніфест у /etc/kubernetes/manifests/
Збереження довготривалих токенів приєднання заради зручностіСтарі токени ускладнюють міркування про стан допуску вузлівГенеруйте короткотривалі токени й видаляйте невикористані після вікна приєднання
Використання kubeadm reset як першого кроку усунення несправностейВи видаляєте локальний стан до розуміння збоюСкидайте лише для демонтажу, перебудови чи задокументованої процедури повторного приєднання

Суть масштабування в тому, що kubeadm не усуває потреби в операційному дизайні. Одновузлова лабораторія може терпіти ручні команди й короткі простої, тоді як подібний до продакшну кластер потребує зовнішніх кінцевих точок API, перевірених резервних копій, запланованих хвиль оновлень і достатнього запасу ємності для drain. Назви команд лишаються тими самими, але ризик навколо кожної команди змінюється з розміром кластера, критичністю робочого навантаження й вимогами до відновлення.


Каркас прийняття рішень

Розділ «Каркас прийняття рішень»

Використовуйте наведений нижче каркас, коли ви стикаєтеся із симптомом kubeadm-кластера й маєте обрати наступну дію. Мета — уникнути стрибка прямо до найдраматичнішої команди. Почніть із визначення того, який рівень усе ще заслуговує на довіру, а потім оберіть найменш руйнівну дію, що може довести чи відновити підозрюваний контракт. Це той самий ментальний хід, який ви тренували в попередніх модулях з архітектури: знайдіть право власності, перш ніж застосовувати виправлення.

Symptom observed
|
v
Can kubectl reach the API server?
|
+-- yes --> Is this a scheduling or workload-placement issue?
| |
| +-- yes --> inspect nodes, cordon/drain/uncordon, events
| |
| +-- no --> inspect kube-system pods, CNI, certificates, joins
|
+-- no --> Can you SSH to the affected control-plane node?
|
+-- yes --> inspect kubelet, crictl, static pod manifests, local logs
|
+-- no --> fix host/network access before Kubernetes diagnosis
СитуаціяПерша перевіркаІмовірне сімейство командУникайте, доки не дізнаєтеся більше
Свіжий кластер має вузол NotReady і CoreDNS у стані pendingПоди CNI й pod CIDRkubectl get pods -n kube-system, команда встановлення CNIkubeadm reset
Приєднання робочого вузла відразу зазнає невдачіТокен, хеш CA, досяжність API, логи kubeletkubeadm token create --print-join-command, journalctl -u kubeletПовторна ініціалізація площини управління
API-сервер недоступний після редагування маніфестуЛоги kubelet і статичних Подівjournalctl, crictl logs, редагування маніфестуkubectl delete pod
Заплановане перезавантаження вузлаКонтролери робочих навантажень і політика порушеньkubectl cordon, kubectl drain, kubectl uncordonПерезавантаження живленням без drain
Сертифікати близькі до завершення строку діїВивід kubeadm certs check-expirationkubeadm certs renew, перезапуск статичного ПодаПрипущення, що поновлення автоматично перезавантажує кожен процес
Руйнівне обслуговування площини управлінняСвіжий знімок etcd і план відновленняetcdctl snapshot save, kubeadm upgrade planОновлення без захисту стану

Два правила утримують цей каркас практичним. По-перше, не використовуйте команду рівня кластера для виправлення локальної передумови вузла, доки локальні докази вузла не скажуть, що Kubernetes готовий до цієї команди. По-друге, не використовуйте руйнівну локальну команду для виправлення умови планування рівня кластера, доки ви не перевірили вигляд з боку API. Це розділення — те, що запобігає перетворенню простого недогляду з cordon на скидання, і воно ж не дає мертвому API-серверу марнувати ваш час повторними викликами kubectl.


  • Токени початкового налаштування, створені kubeadm, за замовчуванням завершують строк дії через 24 години, і саме тому kubeadm token create --print-join-command є звичайною операційною командою, а не рідкісним трюком відновлення.
  • Компоненти площини управління kubeadm працюють як статичні Поди, тож kubelet спостерігає за /etc/kubernetes/manifests/ і може перезапустити контейнер API-сервера навіть тоді, коли API-сервер не може відповісти kubectl.
  • Типовий захищений порт API-сервера Kubernetes — 6443, і робочий вузол, який не може досягти цієї кінцевої точки, не може завершити kubeadm join, скільки б разів ви не перегенеровували токен.
  • Сертифікати, керовані kubeadm, можна перевірити за допомогою kubeadm certs check-expiration, але поновлені файли сертифікатів усе одно мають бути завантажені відповідними компонентами площини управління, перш ніж клієнти побачать зміну.

ПомилкаЧому вона трапляєтьсяЯк її виправити
Запуск init з увімкненим swapПопередні перевірки kubeadm відхиляють хост, що порушує вимоги kubeletВимкніть swap за допомогою swapoff -a, видаліть постійні записи swap з /etc/fstab і повторно запустіть попередні перевірки
Забування CNI після initAPI-сервер працює, тож кластер виглядає «встановленим», хоча мережа Подів відсутняВстановіть рівно один призначений CNI-плагін і перевірте Поди CNI плюс CoreDNS у kube-system
Токен із вичерпаним строком діїПочаткову команду приєднання скопіювали зі старого виводу init чи застарілих нотатокЗапустіть kubeadm token create --print-join-command і використайте свіжу команду під час вікна приєднання
Використання kubectl delete на статичних ПодахДзеркальні Поди з’являються в API, тож вони виглядають як звичайні Поди, керовані через APIРедагуйте, переміщуйте чи відновлюйте файли в /etc/kubernetes/manifests/, бо kubelet володіє життєвим циклом статичних Подів
Відсутність drain перед обслуговуваннямCordon і drain сприймають як взаємозамінні команди для вузлаCordon — щоб зупинити нове розміщення, drain — щоб виселити рухомі робочі навантаження, потім uncordon після обслуговування
Поновлення сертифікатів без перезапуску компонентівКоманда записує файли, але запущені процеси можуть усе ще тримати старі дані сертифікатівПерезапустіть чи перезавантажте уражені статичні Поди й перевірте строк дії знову після перезавантаження
Скидання перед збором локальних доказівСкидання здається чистим виправленням, коли поведінка kubelet чи приєднання заплутуєЗафіксуйте логи kubelet, вивід crictl, маніфести й помилки kubeadm перед використанням kubeadm reset

Питання 1: Ваша команда ініціалізує площину управління за допомогою `kubeadm init`, копіює `admin.conf` і бачить вузол, але CoreDNS лишається в стані pending. Що ви перевіряєте перед повторним запуском kubeadm?

Перевірте, чи був встановлений CNI-плагін і чи відповідає його конфігурація pod CIDR, який використовувався під час kubeadm init. API-сервер може бути досяжним до того, як мережа Подів стане готовою, тож CoreDNS у стані pending часто є симптомом початкового налаштування мережі, а не невдалого встановлення площини управління. Перевірте kubectl get pods -n kube-system -o wide, пошукайте Поди DaemonSet CNI й прочитайте їхні логи, якщо вони існують. Повторний запуск kubeadm був би неправильним першим кроком, бо він ігнорує відсутній чи несправний мережевий рівень.

Питання 2: Вчорашня команда приєднання робочого вузла зазнає невдачі, а помилка згадує перевірку токена початкового налаштування. Що вам слід зробити і чому хеш CA все ще є частиною команди?

Згенеруйте свіжу команду приєднання на площині управління за допомогою kubeadm token create --print-join-command, а потім запустіть цю команду на підготовленому робочому вузлі. Токен — це короткотривалий матеріал автентифікації, тож стара команда може завершити строк дії, навіть коли кластер справний. Хеш CA лишається необхідним, бо робочий вузол має переконатися, що кінцева точка API-сервера належить призначеному кластеру, перш ніж довіряти їй. Якщо новий токен усе одно зазнає невдачі, відокремте помилки токена від помилок мережевої досяжності й підготовки kubelet.

Питання 3: Ви видаляєте `kube-apiserver-controlplane` за допомогою `kubectl`, і він повертається майже миттєво. Що це каже вам про право власності?

Це каже вам, що видимий Под — це дзеркало статичного Пода, а не звичайний Под, яким володіє Деплоймент чи ReplicaSet. kubelet спостерігає за /etc/kubernetes/manifests/kube-apiserver.yaml, тож коли ви видаляєте дзеркальний Под через API, kubelet відтворює об’єкт дзеркального Пода — але базовий контейнер ніколи не перезапускається, бо kubelet не отримав інструкції видалити маніфест. Процес статичного Пода продовжує працювати протягом операції kubectl delete. Щоб навмисно зупинити чи змінити цей статичний Под, ви маєте відредагувати чи перемістити маніфест на вузлі площини управління. Саме тому локальний доступ до вузла має значення, коли API-сервер є компонентом, який ви усуваєте.

Питання 4: Під час запланованого обслуговування ядра молодший адміністратор пропонує `kubectl cordon` і негайне перезавантаження. Який безпечніший робочий процес ви впроваджуєте?

Спершу виконайте cordon вузла, щоб запобігти потраплянню туди нових Подів, потім осушіть його з відповідними прапорцями, щоб керовані Поди були виселені перед перезавантаженням. Після обслуговування перевірте справність kubelet, підтвердіть, що вузол повертається в стан Ready, і зніміть з нього cordon, щоб планування могло відновитися. Сам по собі cordon не переміщує наявні Поди, тож негайне перезавантаження може перервати робочі навантаження, які можна було б граціозно перепланувати. Точні прапорці drain залежать від DaemonSet, локальних даних emptyDir і некерованих Подів.

Питання 5: Ви поновлюєте сертифікати kubeadm, бо сертифікат API-сервера близький до завершення строку дії, але клієнти все ще повідомляють стару дату. Що ви, найімовірніше, пропустили?

Ви, найімовірніше, записали нові файли сертифікатів, але не перезапустили чи не перезавантажили компонент, який їх завантажує. Поновлення kubeadm змінює файли в /etc/kubernetes/pki, тоді як процеси статичних Подів мають перезавантажити ці файли, перш ніж клієнти побачать новий сертифікат. Перевірте строк дії за допомогою kubeadm certs check-expiration, перезапустіть чи перезавантажте відповідний статичний Под і перевірте через openssl-перевірку серверного (serving) сертифіката. Якщо адміністративні клієнтські облікові дані були поновлені, також оновіть kubeconfig, який використовує адміністративна оболонка.

Питання 6: Після редагування `kube-apiserver.yaml` кожна команда `kubectl` зависає. Які інструменти ви використаєте далі?

Переключіться на локальні інструменти вузла, бо API-сервер може бути зламаним компонентом. Підключіться по SSH до вузла площини управління, перевірте journalctl -u kubelet, перелічіть контейнери за допомогою crictl ps і перевірте логи контейнера API-сервера за допомогою crictl logs чи файлів у /var/log/pods. Потім виправте маніфест безпосередньо в /etc/kubernetes/manifests/ і дозвольте kubelet перезапустити статичний Под. Повторні спроби kubectl не допомагають, коли API-сервер не може запуститися.

Питання 7: Перед оновленням площини управління kubeadm який захист стану ви хочете мати на місці і як він змінює ваш ризик?

Ви хочете свіжий знімок etcd, який було перевірено, плюс скопійовані маніфести статичних Подів і чіткий план відновлення, що відповідає топології кластера. Знімок захищає стан кластера, а копії маніфестів допомагають скасувати випадкові зміни прапорців чи шляхів. Це не робить оновлення безризиковим, але змінює обробку збоїв з імпровізації на відпрацьований шлях відновлення. Ви все одно маєте запустити kubeadm upgrade plan, дотримуватися розбіжності версій і оновлювати по одному вузлу за раз.


Ця вправа розрахована на лабораторний kubeadm-кластер щонайменше з одним робочим вузлом. Якщо ви використовуєте kind чи minikube, деякі шляхи статичних Подів і поведінка обслуговування вузлів можуть відрізнятися, бо «вузли» є контейнерами чи локальними абстракціями ВМ, а не звичайними хостами Linux. Навчальна мета однакова: пов’яжіть кожну команду з рівнем, який вона змінює, а потім перевірте результат перед переходом до наступного кроку.

Сценарій вправи: ви готуєте kubeadm-кластер до рутинного обслуговування й маєте довести, що можете перевірити артефакти початкового налаштування, згенерувати команду приєднання, захистити стан, осушити вузол і відновити планування після цього. Не запускайте руйнівні команди скидання проти кластера, який вам важливий, якщо лабораторія явно не надає вам одноразові вузли. Коли завдання каже «на площині управління», запускайте його з оболонки на хості площини управління, а не з випадкової робочої станції.

Завдання 1: Перегляд і класифікація вузлів

Розділ «Завдання 1: Перегляд і класифікація вузлів»

Запустіть команди перевірки вузлів, потім запишіть, який вузол є площиною управління, який вузол є робочим і чи якийсь вузол уже має cordon. Вивід має дозволити вам відрізнити справність від стану планування перед виконанням обслуговування.

Terminal window
kubectl get nodes -o wide
Terminal window
kubectl describe node <node-name> | head -50
Нотатки до розв'язання

Перша команда дає компактний вигляд ролей, версій, внутрішніх IP і готовності. Друга команда дає умови, адреси, ємність, доступні (allocatable) ресурси, taint-и й свіжі події вузла. Вузол, що показує SchedulingDisabled, має cordon, тоді як вузол, що показує NotReady, має проблему справності чи зв’язку, яку слід діагностувати перед обслуговуванням.

Завдання 2: Перевірка файлів статичних Подів площини управління

Розділ «Завдання 2: Перевірка файлів статичних Подів площини управління»

На вузлі площини управління перевірте каталог маніфестів і прочитайте початок маніфесту API-сервера. Поки що нічого не редагуйте; суть у тому, щоб знайти джерельні файли, за якими спостерігає kubelet.

Terminal window
# If you have SSH access to control plane
ls /etc/kubernetes/manifests/
cat /etc/kubernetes/manifests/kube-apiserver.yaml | head -30
Нотатки до розв'язання

Ви маєте побачити маніфести, як-от kube-apiserver.yaml, kube-controller-manager.yaml, kube-scheduler.yaml і часто etcd.yaml на вузлі площини управління зі stacked-топологією. Якщо ці файли присутні, kubelet є локальним наглядачем для цих компонентів. Якщо kubectl пізніше зазнає невдачі, бо API-сервер лежить, цей каталог лишається одним із ваших основних місць відновлення.

Завдання 3: Практика cordon і uncordon

Розділ «Завдання 3: Практика cordon і uncordon»

Виконайте cordon робочого вузла, переконайтеся, що планування вимкнено, створіть тестовий Под і перевірте, де він опиниться. Потім зніміть cordon з робочого вузла й переконайтеся, що стан планування повертається до норми.

Terminal window
# Cordon a worker node
kubectl cordon <worker-node>
kubectl get nodes
# Should show SchedulingDisabled
# Try to schedule a pod
kubectl run test-pod --image=nginx
# Check where it landed
kubectl get pods -o wide
# Won't be on cordoned node
# Uncordon
kubectl uncordon <worker-node>
kubectl get nodes
Нотатки до розв'язання

Вузол із cordon має показувати SchedulingDisabled, а тестовий Под має опинитися на іншому придатному для планування вузлі, якщо є ємність. Якщо у вас лише один робочий вузол, Под може лишитися в стані pending, доки з вузла не знято cordon. Цей результат усе одно корисний, бо він доводить, що cordon змінює розміщення scheduler-ом, нічого не доводячи про справність kubelet.

Завдання 4: Практика drain з одноразовим деплойментом

Розділ «Завдання 4: Практика drain з одноразовим деплойментом»

Створіть невеликий деплоймент, поспостерігайте за розміщенням Подів, осушіть вузол, що хостить одну з реплік, і переконайтеся, що Поди-заміни переміщуються в інше місце. Використовуйте лабораторний кластер із достатньою ємністю й не форсуйте продакшн-навантаження, якщо ваш runbook це явно не дозволяє.

Terminal window
# Create a deployment first
kubectl create deployment drain-test --image=nginx --replicas=2
# Check pod locations
kubectl get pods -o wide
# Drain a node with pods
kubectl drain <node-with-pods> --ignore-daemonsets
# Check pods moved
kubectl get pods -o wide
# Uncordon the node
kubectl uncordon <node-name>
Нотатки до розв'язання

Контролер деплойменту має створити Поди-заміни на придатних для планування вузлах після того, як drain виселить оригінали. Якщо drain блокується, прочитайте повідомлення замість того, щоб наосліп додавати прапорці; воно може попереджати вас про некеровані Поди чи локальні дані. Після тесту зніміть cordon з вузла, щоб він знову міг отримувати робочі навантаження.

Завдання 5: Перевірка сертифікатів і генерація команди приєднання

Розділ «Завдання 5: Перевірка сертифікатів і генерація команди приєднання»

На вузлі площини управління перевірте строк дії сертифікатів і згенеруйте свіжу команду приєднання. Не запускайте команду приєднання, якщо у вас немає підготовленого робочого вузла, який має приєднатися до кластера.

Terminal window
# If you have access to control plane
kubeadm certs check-expiration
Terminal window
# On control plane
kubeadm token create --print-join-command
Нотатки до розв'язання

Команда сертифікатів має показати дати завершення строку дії для керованих kubeadm сертифікатів, що допомагає спланувати поновлення до простою. Команда токена має вивести повну команду kubeadm join, що містить токен і хеш CA. Ставтеся до цього виводу як до тимчасового матеріалу початкового налаштування й уникайте зберігання його в довготривалих спільних нотатках.

Завдання 6: Прибирання лабораторних ресурсів

Розділ «Завдання 6: Прибирання лабораторних ресурсів»

Видаліть одноразовий деплоймент і Под, створені під час вправи. Потім повторно перевірте вузли, щоб підтвердити, що жоден лабораторний вузол не лишився з cordon помилково.

Terminal window
kubectl delete deployment drain-test
kubectl delete pod test-pod
Нотатки до розв'язання

Прибирання має видалити об’єкти робочих навантажень, які ви створили, і лишити вузли в очікуваному стані планування. Запустіть kubectl get nodes після цього й пошукайте випадковий статус SchedulingDisabled. Якщо ви практикували drain, також підтвердіть, що з осушеного вузла знято cordon, перш ніж завершувати лабораторну роботу.

Тренувальні вправи

Розділ «Тренувальні вправи»

Використовуйте ці хронометровані вправи після керованих завдань. Вони зберігають оригінальну практику команд із цього модуля, але сприймайте цільові показники як приблизний лабораторний темп, а не як привід поспіхом проскочити вивід, якого ви не розумієте.

Вправа 1: Команди управління вузлами (Ціль: 3 хвилини)

Розділ «Вправа 1: Команди управління вузлами (Ціль: 3 хвилини)»
Terminal window
# List nodes with details
kubectl get nodes -o wide
# Get node labels
kubectl get nodes --show-labels
# Describe a node
kubectl describe node <node-name> | head -50
# Check node conditions
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
# Check node resources
kubectl describe node <node-name> | grep -A10 "Allocated resources"

Вправа 2: Cordon і Uncordon (Ціль: 5 хвилин)

Розділ «Вправа 2: Cordon і Uncordon (Ціль: 5 хвилин)»
Terminal window
# Cordon a node (prevent new pods)
kubectl cordon <worker-node>
# Verify
kubectl get nodes # Shows SchedulingDisabled
# Try to schedule a pod
kubectl run cordon-test --image=nginx
kubectl get pods -o wide # Won't be on cordoned node
# Uncordon
kubectl uncordon <worker-node>
kubectl get nodes # Back to Ready
# Cleanup
kubectl delete pod cordon-test

Вправа 3: Drain і відновлення (Ціль: 5 хвилин)

Розділ «Вправа 3: Drain і відновлення (Ціль: 5 хвилин)»
Terminal window
# Create test deployment
kubectl create deployment drain-test --image=nginx --replicas=3
# Wait for pods
kubectl wait --for=condition=available deployment/drain-test --timeout=60s
kubectl get pods -o wide
# Drain a worker node
kubectl drain <worker-node> --ignore-daemonsets --delete-emptydir-data
# Watch pods move to other nodes
kubectl get pods -o wide
# Uncordon the node
kubectl uncordon <worker-node>
# Cleanup
kubectl delete deployment drain-test

Вправа 4: Управління токенами kubeadm (Ціль: 3 хвилини)

Розділ «Вправа 4: Управління токенами kubeadm (Ціль: 3 хвилини)»
Terminal window
# List existing tokens
kubeadm token list
# Create a new token
kubeadm token create
# Create token with specific TTL
kubeadm token create --ttl 2h
# Generate full join command
kubeadm token create --print-join-command
# Delete a token
kubeadm token delete <token-id>

Вправа 5: Дослідження статичних Подів (Ціль: 5 хвилин)

Розділ «Вправа 5: Дослідження статичних Подів (Ціль: 5 хвилин)»
/etc/kubernetes/manifests
# Find static pod manifest directory
cat /var/lib/kubelet/config.yaml | grep staticPodPath
# List static pod manifests
ls -la /etc/kubernetes/manifests/
# View one manifest
cat /etc/kubernetes/manifests/kube-apiserver.yaml | head -30
# Create your own static pod
cat << 'EOF' | sudo tee /etc/kubernetes/manifests/my-static-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-static-pod
namespace: default
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
EOF
# Wait and verify (will have node name suffix)
sleep 10
kubectl get pods | grep my-static-pod
# Remove static pod
sudo rm /etc/kubernetes/manifests/my-static-pod.yaml

Вправа 6: Перевірка сертифікатів (Ціль: 5 хвилин)

Розділ «Вправа 6: Перевірка сертифікатів (Ціль: 5 хвилин)»
Terminal window
# Check certificate expiration (on control plane)
kubeadm certs check-expiration
# View certificate details
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | head -30
# Check all certificates
ls -la /etc/kubernetes/pki/
# Check CA certificate
openssl x509 -in /etc/kubernetes/pki/ca.crt -text -noout | grep -E "Subject:|Issuer:|Not"

Вправа 7: Усунення несправностей — вузол NotReady (Ціль: 5 хвилин)

Розділ «Вправа 7: Усунення несправностей — вузол NotReady (Ціль: 5 хвилин)»
Terminal window
# Simulate: Stop kubelet on a worker
# (Run on worker node)
sudo systemctl stop kubelet
# On control plane, diagnose
kubectl get nodes # Shows NotReady
kubectl describe node <worker> | grep -A10 Conditions
# Check what's happening
kubectl get events --field-selector involvedObject.kind=Node
# Fix: Restart kubelet (on worker)
sudo systemctl start kubelet
# Verify recovery
kubectl get nodes -w

Вправа 8: Виклик — робочий процес обслуговування вузла

Розділ «Вправа 8: Виклик — робочий процес обслуговування вузла»

Виконайте повний робочий процес обслуговування:

  1. Виконайте cordon вузла
  2. Осушіть усі робочі навантаження
  3. Зімітуйте обслуговування, зачекавши 30 секунд
  4. Зніміть cordon з вузла
  5. Переконайтеся, що Поди знову можна планувати
Terminal window
# YOUR TASK: Complete this without looking at solution
NODE_NAME=<your-worker-node>
kubectl create deployment maint-test --image=nginx --replicas=2
# Start timer - Target: 3 minutes total
Розв'язання
Terminal window
NODE_NAME=worker-01 # Replace with your node
# 1. Cordon
kubectl cordon $NODE_NAME
# 2. Drain
kubectl drain $NODE_NAME --ignore-daemonsets --delete-emptydir-data
# 3. Verify pods moved
kubectl get pods -o wide
# 4. Simulate maintenance
echo "Performing maintenance..."
sleep 30
# 5. Uncordon
kubectl uncordon $NODE_NAME
# 6. Verify scheduling works
kubectl scale deployment maint-test --replicas=4
kubectl get pods -o wide # Some should land on $NODE_NAME
# Cleanup
kubectl delete deployment maint-test
  • Спроєктувати послідовність початкового налаштування kubeadm, що включає попередні перевірки, kubeadm init, налаштування kubeconfig, встановлення CNI та токени приєднання робочих вузлів.
  • Діагностувати збої статичних Подів і kubelet за допомогою /etc/kubernetes/manifests/, journalctl, crictl і локальних логів площини управління.
  • Оцінити ризики обслуговування сертифікатів і etcd, перевіряючи строк дії, пояснюючи, коли і як зберегти знімок etcd, та плануючи перезапуски компонентів.
  • Впровадити безпечне обслуговування вузлів за допомогою kubectl cordon, kubectl drain, kubectl uncordon і чіткого кроку прибирання.
  • Пояснити, коли kubeadm reset доречний і чому він не повинен бути першою реакцією на кожну проблему kubeadm.


Перейдіть до Частини 2: Робочі навантаження та планування, щоб дізнатися, як Kubernetes розміщує й запускає прикладні робочі навантаження після того, як фундамент кластера вже існує.

Покажчик модулів Частини 1

Розділ «Покажчик модулів Частини 1»

Швидкі посилання для повторення:

МодульТемаКлючові навички
1.1Глибоке занурення в площину управлінняРолі компонентів, усунення несправностей, статичні Поди
1.2Інтерфейси розширенняCNI/CSI/CRI, crictl, усунення несправностей плагінів
1.3HelmВстановлення, оновлення, відкат, values
1.4KustomizeBase/overlay, патчі, kubectl -k
1.5CRD та операториСтворення CRD, управління кастомними ресурсами
1.6RBACРолі, прив’язки, ServiceAccount, can-i
1.7Основи kubeadmInit, join, cordon, drain, токени