Розгортання Kubernetes-кластера на локальному компʼютері: Повне покрокове керівництво
💡 Такої детальної покрокової інструкції немає в офіційній документації Kubernetes! Те, що ви знайдете там, — це окремі рекомендації. Тут же все зібране в одному місці, щоб ви могли швидко та легко створити свій перший кластер.
Що ми будемо робити?
Ми створимо повноцінний Kubernetes-кластер на вашому локальному компʼютері. За наявності у вас окремого обладнання (компʼютерів), можна адаптувати це керівництво для фізичних машин. Для цього ми використаємо:
- Multipass — інструмент для створення віртуальних машин Ubuntu
- kubeadm — основний інструмент для ініціалізації кластера
- Flannel — CNI-втулок для створення мережі між Pod’ами
- MetalLB — балансувальник навантаження для нашого кластера
Наш кластер складатиметься з трьох вузлів:
- 1 вузла панелі управління (control plane)
- 2 робочих worker-вузлів
Передумови
Перед початком встановіть Multipass:
brew install multipass
Крок 1: Створення віртуальних машин
Визначаємо список вузлів
Створимо масив з іменами трьох віртуальних машин. Це як простий список — просто записуємо, які машини нам потрібні.
NODES=(k8s-control k8s-worker-1 k8s-worker-2)
Створюємо ВМ
Тепер за допомогою multipass створимо три віртуальні машини з Ubuntu на борту.
for NODE in "${NODES[@]}"; do
multipass launch --name $NODE --cpus 2 --memory 4G --disk 20G
done
За допомогою циклу for NODE in "${NODES[@]}" проходимо по кожному імені в масиві; multipass launch --name $NODE створює віртуальну машину з відповідним імʼям та наступними параметрами:
--cpus 2— виділяємо 2 процесорних ядра (мінімум для K8s)--memory 4G— виділяємо 4 ГБ оперативної памʼяті--disk 20G— виділяємо 20 ГБ дискового простору
Multipass автоматично завантажить Ubuntu. Це займе кілька хвилин ☕.
Крок 2: Підготовка всіх вузлів
Коли наші віртуальні машини створені, тепер почнемо налаштування. Ці кроки потрібно виконати на всіх трьох машинах.
2.1. Оновлення системи
echo "=== [1/7] Оновлення системи на всіх вузлах ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- bash -c "
sudo apt-get update &&
sudo apt-get upgrade -y
"
done
multipass exec $NODE— виконує команду на віртуальній машиніsudo apt-get update— оновлює список доступних пакетів (як каталог програм)sudo apt-get upgrade -y— встановлює всі оновлення,-yозначає “так, згоден” у відповідях на всі питання
Перед початком роботи важливо мати актуальну систему з останніми виправленнями безпеки та оновленнями пакетів.
Після виконання цієї команди всі пакети в системі будуть оновлені до останніх версій.
2.2. Вимкнення firewall
echo "=== [2/7] Вимкнення firewall на всіх вузлах ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- sudo ufw disable
done
UFW — це вбудований брандмауер Ubuntu. Для навчального кластера ми вимикаємо брандмауер, щоб уникнути проблем з мережевим звʼязком між вузлами.
⚠️ У промисловій експлуатації потрібно правильно налаштувати firewall та відкрити відповідні порти!
2.3. Завантаження модулів ядра
echo "=== [3/7] Налаштування kernel-модулів ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- bash -c "
echo -e 'overlay\nbr_netfilter' | sudo tee /etc/modules-load.d/k8s.conf
sudo modprobe overlay
sudo modprobe br_netfilter
"
done
Для своєї роботи Kubernetes потребує щоб були увімкнені ці два модулі ядра Linux:
overlay— для файлової системи контейнерів (для роботи з шарами образів контейнерів)br_netfilter— для мережевого звʼязку між контейнерами
Перший рядок записує ці модулі у конфігураційний файл, щоб вони завантажувались автоматично при старті. Наступні два рядки завантажують їх зараз.
2.4. Налаштування мережевих параметрів
echo "=== [4/7] Налаштування мережевих параметрів ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- bash -c "
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
"
done
Тут ми налаштовуємо параметри мережі на рівні ядра операційної системи:
- bridge-nf-call-iptables — дозволяє iptables обробляти трафік, що проходить через мережеві мости (для IPv4 та IPv6)
- ip_forward — дозволяє маршрутизацію пакетів між мережевими інтерфейсами (як поштове відділення, що пересилає листи)
Команда sysctl –system застосовує ці параметри негайно.
Це критично важливо для роботи мережі Kubernetes!
2.5. Встановлення containerd
echo "=== [5/7] Встановлення containerd ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- sudo apt-get install -y containerd
done
Containerd — це рушій для запуску та виконання контейнерів, тобто програма, яка фактично запускає та керує контейнерами. Це як двигун для автомобіля — без нього нічого не поїде. Kubernetes підтримує різні рушії, containerd — найпопулярніший та є рекомендованим варіантом.
2.6. Налаштування containerd
echo "=== [6/7] Налаштування containerd і CRI ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- bash -c "
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# Оновлюємо sandbox image
sudo sed -i 's/registry.k8s.io\\/pause:3.8/registry.k8s.io\\/pause:3.10.1/' /etc/containerd/config.toml
# Увімкнення режиму cgroup через systemd
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# Додаємо конфіг для crictl
sudo tee /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
sudo systemctl restart containerd
sudo systemctl enable containerd
"
done
Що відбувається:
- Генеруємо стандартний конфігураційний файл за допомогою
containerd config defaultта записуємо його в/etc/containerd/config.toml - Kubernetes використовує спеціальний (інфраструктурний) “pause” контейнер для кожного Podʼа. Оновимо його до версії 3.10.1 (остання на момент написання)
- Вмикаємо управління cgroups через systemd. Cgroups — це механізм обмеження ресурсів (CPU, памʼять) для контейнерів. Systemd — стандартний спосіб керування цим в Ubuntu
- Налаштовуємо crictl (інструмент для відладки контейнерів). Ми вказуємо йому, як підключатися до containerd
- Перезапускаємо containerd з новими налаштуваннями та додаємо його в автозапуск
2.7. Встановлення Kubernetes компонентів
echo "=== [7/7] Встановлення Kubernetes компонентів ==="
for NODE in "${NODES[@]}"; do
multipass exec $NODE -- bash -c "
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable kubelet
"
done
- Підготовка: Встановлюємо інструменти для безпечного завантаження пакетів (HTTPS, сертифікати, GPG)
- Додавання ключа: Завантажуємо криптографічний ключ від офіційного репозиторію Kubernetes. Це як печатка, що підтверджує автентичність пакетів
- Додавання репозиторію: Додаємо офіційний репозиторій Kubernetes версії 1.34 до списку джерел пакетів
-
Встановлення:
kubelet— агент на кожному вузлі, який запускає контейнериkubeadm— інструмент для ініціалізації кластераkubectl— клієнт командного рядка для управління кластером
‼️ apt-mark hold запобігає автоматичному оновленню зафіксованих пакетів. Версії всіх компонентів у кластері мають збігатися! Додаємо kubelet в автозапуск
2.8. Готово! ✅
Всі ці кроки можна обʼєднати в один скрипт, який виконає їх послідовно на всіх вузлах та підготує їх до створення кластера.
Всі три машини готові стати частиною Kubernetes-кластера!1
Крок 3: Ініціалізація Control Plane
Підключаємось до control plane
multipass shell k8s-control
Ця команда відкриває термінал всередині віртуальної машини k8s-control. Тепер ми працюємо безпосередньо на цій машині, як якби сиділи за нею локально.
Отримання IP-адреси
CONTROL_IP=$(hostname -I | awk '{print $1}')
hostname -I— показує всі IP-адреси цієї машиниawk '{print $1}'— витягує першу адресу зі списку$()— зберігає результат у змінну CONTROL_IP
Нам потрібна IP-адреса, щоб worker-вузли знали, куди підключатися.
Ініціалізуємо кластер 🚀
sudo kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=$CONTROL_IP
Kubeadm — це інструмент для швидкого створення Kubernetes-кластера. Команда kubeadm init ініціалізує панель управління (control plane), налаштовує API server, scheduler, controller manager та інші компоненти. В кінці виводиться команда kubeadm join, яку потрібно виконати на worker-вузлах, щоб приєднати їх до кластера.
Параметри:
--pod-network-cidr=10.244.0.0/16— діапазон IP-адрес для Podʼів (для Flannel)--apiserver-advertise-address— IP для підключення інших вузлів
⏱️ Це займе 1-2 хвилини.
📝 Збережіть команду kubeadm join, яку виведе команда!
Налаштовуємо kubectl
Крім виводу команди kubeadm join, виводиться інструкція для налаштування kubectl на панелі управління для керування кластером від імені поточного користувача.
mkdir -p ~/.kube
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
kubectl потребує конфігураційний файл для підключення до кластера.
mkdir -p ~/.kube— створюємо папку для конфігурації (якщо її ще немає)cp admin.conf ~/.kube/config— копіюємо файл з правами адміністратораchown— змінюємо власника файлу на поточного користувача (щоб не потрібно було використовувати sudo для kubectl)
Крок 4: Встановлення мережевого втулка (CNI) — Flannel
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Flannel — мережевий втулок (Container Network Interface, CNI), що дозволяє Podʼам на різних вузлах спілкуватися між собою.
Kubernetes сам по собі не знає, як організувати мережу. Flannel створює overlay-мережу, де всі Podʼи наче в одній локальній мережі 🌐
Ця команда завантажує та застосовує YAML-маніфест, який створює всі необхідні ресурси (DaemonSet, ConfigMap, ServiceAccount тощо).
Крок 5: Приєднання Worker-вузлів
Під час ініціалізації kubeadm init вивела команду kubeadm join, яку потрібно виконати на кожному worker-вузлі.
for NODE in k8s-worker-1 k8s-worker-2; do
multipass exec $NODE -- sudo kubeadm join 192.168.2.26:6443 \
--token bsw6fd.e7624wl2688fybjx \
--discovery-token-ca-cert-hash sha256:7850aa1c6181277e284a08b81256979db25698a89982f0885540376a5376e0bd
done
⚠️ ВАЖЛИВО: У вашому випадку IP, токен та хеш будуть іншими! Використовуйте команду, яку ви отримали від
kubeadm init.
Що тут:
multipass exec $NODE --— виконуємо команду на кожному worker-вузлі192.168.2.14:6443— адреса API server (порт 6443 — стандартний)--token— тимчасовий токен автентифікації (згенерований під час виконанняkubeadm init)--discovery-token-ca-cert-hash— SHA256-хеш сертифікату CA для перевірки автентичності (захист від атак типу man-in-the-middle)
Крок 6: Перевірка кластера
Повертаємося на вузол панелі управління (control plane) та перевіряємо статус вузлів.
multipass shell k8s-control
kubectl get nodes
Ви повинні побачити три вузли зі статусом Ready:
NAME STATUS ROLES AGE VERSION
k8s-control Ready control-plane 5m v1.34.0
k8s-worker-1 Ready <none> 2m v1.34.0
k8s-worker-2 Ready <none> 2m v1.34.0
Якщо статус NotReady, почекайте хвилину — Flannel ще налаштовується ⏳
Крок 7: Встановлення MetalLB
Що таке MetalLB?
MetalLB — це load balancer для bare-metal кластерів. В керованих (managed) розгортаннях Kubernetes від хмарних провайдерів (AWS, GCP) сервіси типу LoadBalancer створюються автоматично. У нашому локальному кластері MetalLB надає цю функціональність. 🎯
Застосовуємо маніфести
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml
Чекаємо готовності
kubectl wait --namespace metallb-system \
--for=condition=ready pod \
--selector=app=metallb
Ця команда чекає, поки всі Pod’и MetalLB не перейдуть у стан готовності.
Маркування worker-вузлів
Для того щоб призначити мітки всім вузлам, імена яких починаються з k8s-worker-, можна використати команду kubectl get nodes разом із фільтрацією за допомогою grep та подальшим циклом for для застосування мітки до кожного знайденого вузла.
NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}' | tr -s '[[:space:]]' '\n' | grep '^k8s-worker-')
for NODE in $NODES; do
echo "Applying label to node: $NODE"
kubectl label node "$NODE" metallb-role=worker --overwrite
done
Додаємо мітку metallb-role=worker до worker-вузлів. Мітки (labels) — це key-value пари, що допомагають організовувати та вибирати ресурси в Kubernetes. Ми використаємо цю мітку, щоб MetalLB працював тільки на worker-вузлах.
Налаштування IP-пулу та L2Advertisement
CONTROL_IP=$(hostname -I | awk '{print $1}')
BASE_IP=$(echo $CONTROL_IP | cut -d. -f1-3)
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- ${BASE_IP}.200-${BASE_IP}.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: worker-nodes-l2
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
nodeSelectors:
- matchLabels:
metallb-role: worker
EOF
Що відбувається:
- Отримання базової IP: Якщо IP control plane —
192.168.2.14, тоBASE_IPбуде192.168.2 - IPAddressPool — Визначає діапазон IP-адрес, які MetalLB може видавати LoadBalancer-сервісам. У нашому випадку — від .200 до .250 (51 адреса)
- L2Advertisement — Налаштовує L2 (layer 2) режим. MetalLB оголошує IP-адреси через ARP-протокол, щоб мережа знала, де знаходяться ці адреси
- nodeSelectors — Обмежує роботу MetalLB тільки вузлами з міткою
metallb-role=worker
Крок 8: Демонстрація 🎉
Створюємо Deployment
kubectl create deployment hello \
--image=nginxdemos/hello:plain-text \
--replicas=3 \
--port=80
Створюємо 3 репліки простого nginx-застосунку.
deployment— обʼєкт Kubernetes, що керує набором ідентичних Podʼів--image— Docker-образ для контейнерів (простий nginx з текстовим виводом)--replicas=3— запустити 3 копії (для демонстрації балансування)--port=80— відкрити порт 80 у контейнері
Створюємо LoadBalancer Service
kubectl expose deployment hello \
--type=LoadBalancer \
--port=80
Service типу LoadBalancer — MetalLB виділить зовнішню IP-адресу для доступу до нашого застосунку! Service — це абстракція, що надає стабільний спосіб доступу до групи Podʼів:
expose deployment— ця команда створює Service для нашого Deployment--type=LoadBalancer— цей параметр вказує, що потрібно використовувати зовнішній load balancer (MetalLB виділить IP)--port=80— порт, на якому Service буде доступний
Тестуємо балансування
EXTERNAL_IP=$(kubectl get svc hello -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "LB IP: $EXTERNAL_IP"
for i in {1..10}; do
echo "Request $i:"
curl -s http://$EXTERNAL_IP | grep "Server address"
echo "---"
done
Для тестування балансування нашого навантаження в змінну EXTERNAL_IP зберігаємо зовнішню IP-адресу, яку виділив MetalLB для сервісу hello; потім виконуємо 10 запитів до цієї IP-адреси та виводимо рядок з адресою сервера, який обробив кожен запит.
Результат: Ви побачите, що запити розподіляються між трьома різними Podʼами. Це балансування навантаження в дії! 🔄
Request 1:
Server address: 10.244.1.2:80
---
Request 2:
Server address: 10.244.2.3:80
---
Request 3:
Server address: 10.244.1.4:80
---
🚨 Важливо про SWAP
У стандартній конфігурації Multipass на віртуальних машинах swap вимкнений.
Kubelet стандартно відмовляється працювати, якщо swap увімкнений, тому що це може призвести до непередбачуваної поведінки Pod’ів. (контейнери можуть “виштовхуватись” на диск, що сповільнює їх роботу).
У нашому випадку все ок — swap вимкнений автоматично! ✅
Але якщо ви налаштовуєте K8s на інших системах, де swap увімкнений:
Варіант 1: Вимкніть swap
sudo swapoff -a
# І закоментуйте swap у /etc/fstab
Варіант 2: Налаштуйте kubelet для роботи зі swap (експериментально з K8s 1.28+)
Корисні команди
Перевірка статусу
kubectl get nodes
kubectl get pods -A
kubectl get svc
Перегляд логів
kubectl logs -n kube-system -l app=flannel
kubectl logs -n metallb-system -l app=metallb
Видалення ресурсів
kubectl delete svc hello
kubectl delete deployment hello
Зупинка кластера
# Зупинити всі ВМ
for NODE in "${NODES[@]}"; do
multipass stop $NODE
done
# Запустити знову
for NODE in "${NODES[@]}"; do
multipass start $NODE
done
Видалення кластера
for NODE in "${NODES[@]}"; do
multipass delete $NODE
done
multipass purge
Підсумки
Вітаю! 🎉 Ми щойно створили повноцінний Kubernetes-кластер на своєму локальному компʼютері!
Що ми зробили:
- ✅ Створили 3 віртуальні машини
- ✅ Налаштували containerd та kernel-модулі
- ✅ Ініціалізували control plane
- ✅ Приєднали worker-вузли
- ✅ Встановили Flannel для мережі
- ✅ Налаштували MetalLB для LoadBalancer
- ✅ Розгорнули тестовий застосунок з балансуванням
Тепер у вас є локальне середовище для:
- Експериментів з Kubernetes
- Тестування маніфестів
- Ознайомлення з архітектурою кластера
- Підготовки до сертифікацій (CKA, CKAD)
Сподіваюсь, це керівництво було корисним!
Якщо у вас виникли питання або проблеми — пишіть у коментарях. Діліться цим постом з колегами, яким це може бути корисно 🚀
Happy Kubernetes! ☸️
Застереження 🚨
Цей кластер призначений для розробки та тестування.
Для промисловій експлуатації потрібні додаткові налаштування:
- Firewall та Network Policies
- RBAC (Role-Based Access Control)
- Secrets Management
- Моніторинг та логування
- Резервне копіювання etcd
- High Availability control plane
- Сканування на вразливості
-
Скрипт для підготовки вузлів https://gist.github.com/Andygol/2944d08862d58e3c5a12becacd55b620 ↩