Kubernetes для самых маленьких. Часть 42: Как поднять кластер на ноутбуке: kind, k3s, minikube?
Все части серии «Kubernetes для самых маленьких»Учебный кластер серии мы подняли в части 4: три виртуальные машины, containerd, kubeadm init и join, Calico, kubeconfig на ноутбуке. Так выглядит настоящий кластер, и на нём мы прошли всю серию — до GitOps на Argo CD в предыдущей части. Но для многих задач три машины — слишком много: проверить манифест перед выкаткой, прогнать тесты в CI, показать коллеге, как работает Deployment, поиграть с новой версией Kubernetes, не трогая стенд. Для этого есть кластеры, которые поднимаются на ноутбуке за минуту и удаляются одной командой: kind, k3s и minikube. Это бонусная часть в конце серии, единственная про них: основные примеры серии были на кластерах kubeadm. Поэтому здесь разберём каждый всерьёз — как он устроен изнутри, чем его кластер отличается от того, что мы собрали руками, и где он подведёт.
Все трое запускают Kubernetes: API у них тот же, что описан в части 3, обычные манифесты Deployment и Service работают без правок. Для примеров с Windows-подами, CRD и внешними системами нужны соответствующие узлы и компоненты. Отличаются они тем, что вокруг API: где живут узлы, чем хранится состояние, какой CNI, откуда берутся LoadBalancer и тома.
kind: узлы — это контейнеры
kind (Kubernetes IN Docker) появился как инструмент для тестов самого Kubernetes: проекту нужно было в CI поднимать кластер из только что собранного кода, быстро и много раз в день. Идея — каждый «узел» кластера сделать контейнером в Docker или Podman. Docker — движок контейнеров с демоном dockerd, Podman — совместимый с ним по командам движок без демона: контейнеры запускаются как дочерние процессы пользователя. kind работает с обоими.
Внутри контейнера-узла — почти полноценная машина: systemd первым процессом, под ним containerd и kubelet, те же, что в части 4 мы ставили пакетами. Образ узла kindest/node собирается под конкретную версию Kubernetes и уже содержит kubeadm, kubelet, kubectl и образы компонентов control plane, так что при создании кластера из интернета почти ничего не скачивается. kind запускает контейнеры-узлы, а затем внутри первого выполняет kubeadm init, внутри остальных — kubeadm join. То есть kind — это kubeadm, у которого вместо виртуальных машин контейнеры.
Ноутбук (Linux, или ВМ Docker Desktop на macOS/Windows)
┌────────────────────────────────────────────────────────────────────┐
│ dockerd / podman │
│ │
│ сеть docker «kind» 172.18.0.0/16 │
│ ┌──────────────────────┐ ┌──────────────────────┐ ┌─────────────┐ │
│ │ lab-control-plane │ │ lab-worker │ │ lab-worker2 │ │
│ │ 172.18.0.2 │ │ 172.18.0.3 │ │ 172.18.0.4 │ │
│ │ systemd │ │ systemd │ │ systemd │ │
│ │ ├ containerd │ │ ├ containerd │ │ ├ ... │ │
│ │ │ ├ kube-apiserver │ │ │ ├ kindnet │ │ │ │
│ │ │ ├ etcd │ │ │ ├ kube-proxy │ │ │ │
│ │ │ └ ... │ │ │ └ поды │ │ │ │
│ │ └ kubelet │ │ └ kubelet │ │ │ │
│ └──────────▲───────────┘ └──────────────────────┘ └─────────────┘ │
│ │ порт 6443 опубликован на 127.0.0.1:<случайный> │
└─────────────┼──────────────────────────────────────────────────────┘
│ kubectl на ноутбуке
Контейнер узла запускается привилегированным: kubelet внутри должен создавать cgroups, сетевые namespaces, монтировать тома, а containerd — запускать вложенные контейнеры. Поды кластера kind — это контейнеры внутри контейнера, с общим ядром ноутбука.
Вокруг kubeadm kind ставит свой минимальный набор:
- kindnet — собственный CNI kind. Каждому узлу достаётся подсеть из сети подов (по умолчанию
10.244.0.0/16), а демонkindnetdна каждом узле прописывает маршруты к подсетям соседей через их адреса в сети Docker — без инкапсуляции, потому что все узлы в одном L2-сегменте. Начиная с kind 0.24 в комплекте есть и минимальная реализация NetworkPolicy — контроллер kube-network-policies от авторов kind; он работает внутри того жеkindnetdи пишет правила nftables (в журнале подаkindnet— строкиStarting controller name="kube-network-policies"иSyncing nftables rules). - local-path-provisioner — провижинер томов от Rancher: на запрос тома создаёт каталог на диске узла и отдаёт его поду. В кластере есть StorageClass
standard, помеченный как класс по умолчанию. - kube-proxy в режиме iptables (по умолчанию) или nftables — включается в конфигурации кластера.
- CoreDNS — DNS-сервер кластера, тот же, что ставит kubeadm.
Установка и первый кластер
kind — один статический бинарь на Go. На Linux:
$ curl -Lo kind https://kind.sigs.k8s.io/dl/v0.33.0/kind-linux-amd64
$ curl -Lo kind.sha256 https://github.com/kubernetes-sigs/kind/releases/download/v0.33.0/kind-linux-amd64.sha256sum
$ sed 's/kind-linux-amd64/kind/' kind.sha256 | sha256sum -c
kind: OK
$ chmod +x kind && sudo mv kind /usr/local/bin/
$ kind version
kind v0.33.0 go1.26.7 linux/amd64
На macOS — brew install kind, на Windows — winget install Kubernetes.kind или бинарь с той же страницы. Docker или Podman должны быть уже установлены.
Версия 0.33 по умолчанию поднимает Kubernetes 1.37.0 — ту же минорную версию, что у стенда после части 35 (1.37.2; в списке образов для kind 0.33.0 ветка 1.37 представлена версией 1.37.0). Для другой версии образ узла указывают явно. Список готовых образов с дайджестами есть в описании каждого релиза kind; авторы рекомендуют брать образ с дайджестом @sha256:…, потому что образ под одним и тем же тегом пересобирается с новыми релизами kind и со старой версией kind может не работать. Закрепим так и версию по умолчанию — тогда обновление kind не поменяет кластер незаметно:
$ kind create cluster --name lab \
--image kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
Creating cluster "lab" ...
✓ Ensuring node image (kindest/node:v1.37.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-lab"
You can now use your cluster with:
kubectl cluster-info --context kind-lab
Have a nice day! 👋
На стенде команда работала 33 секунды, из них большую часть — скачивание образа узла.
kind дописал в ~/.kube/config кластер, пользователя и контекст kind-lab и сделал его текущим. Контекст — тройка «кластер, пользователь, неймспейс» из kubeconfig, которую мы разбирали в части 4; переключение между стендом и kind — kubectl config use-context. Адрес API-сервера в kubeconfig — https://127.0.0.1:<порт>: порт 6443 контейнера опубликован только на loopback ноутбука, снаружи кластер недоступен, и так и надо оставить.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
lab-control-plane NotReady control-plane 2s v1.37.0
NotReady сразу после создания — нормально: kind возвращает управление, не дожидаясь, пока kindnet настроит сеть узла, и через несколько секунд узел становится Ready. Один узел — и control plane, и рабочий: в кластере без отдельных рабочих узлов kind снимает с него taint node-role.kubernetes.io/control-plane:NoSchedule, который kubeadm ставит на мастер, чтобы поды пользователя могли туда планироваться. В многоузловом кластере ниже taint на мастере остаётся. О taints подробно — в части 13.
Многоузловой кластер
Состав узлов, сеть и патчи kubeadm задаются файлом конфигурации:
# kind-lab.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: lab
networking:
podSubnet: 172.20.0.0/16 # как на стенде, чтобы не путаться
serviceSubnet: 10.96.0.0/12
kubeProxyMode: nftables # как на стенде
nodes:
- role: control-plane
image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
extraPortMappings: # порт 30080 узла → 127.0.0.1:8080 ноутбука
- containerPort: 30080
hostPort: 8080
listenAddress: 127.0.0.1
- role: worker
image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
- role: worker
image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
labels:
disk: ssd
$ kind delete cluster --name lab
Deleting cluster "lab" ...
Deleted nodes: ["lab-control-plane"]
$ kind create cluster --config kind-lab.yaml
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
lab-control-plane Ready control-plane 29s v1.37.0
lab-worker Ready <none> 20s v1.37.0
lab-worker2 Ready <none> 20s v1.37.0
$ kubectl -n kube-system get cm kube-proxy -o jsonpath='{.data.config\.conf}' | grep '^mode'
mode: nftables
Образ уже в кеше Docker, и три узла создаются за 20 секунд. Поды получили адреса из 172.20.0.0/16, а сами узлы — из сети Docker 172.18.0.0/16.
Если в конфигурации больше одного control-plane, kind добавит ещё один контейнер — балансировщик перед API-серверами (в свежих версиях это Envoy — прокси-сервер уровней L4 и L7), и kubeconfig будет смотреть на него. Так можно потрогать отказоустойчивый control plane, но надёжности это не прибавляет: все «мастера» — контейнеры одного ноутбука. Как такой control plane строится на настоящих машинах, разобрано в серии про Kubernetes на BGP.
Поле extraPortMappings — это обычная публикация порта контейнера (docker run -p). Сервис типа NodePort с портом 30080 будет доступен на 127.0.0.1:8080 ноутбука. Публикация задаётся только при создании кластера: контейнеру Docker нельзя добавить порт на ходу.
Поле kubeadmConfigPatches позволяет передать в kubeadm куски ClusterConfiguration, KubeletConfiguration и других типов, которые мы писали руками в части 4, — например, включить аудит API-сервера или поменять параметры kubelet.
Локальный образ: kind load
Главная радость kind в разработке — образ, собранный на ноутбуке, можно отдать кластеру без реестра. Собственное приложение hello мы собирали в части 5, а здесь возьмём двухстрочный Dockerfile: базовый образ nginx и своя страница. Как устроен Dockerfile и что такое слои образа — тоже в части 5.
$ cat Dockerfile
FROM nginx:1.29
COPY index.html /usr/share/nginx/html/
$ docker build -t demo/web:dev .
$ kind load docker-image demo/web:dev --name lab
Image: "demo/web:dev" with ID "sha256:902178ca06f85d0e937b22447962845b19804f53e648bc93d6f24a355eb5c04b" not yet present on node "lab-worker", loading...
Image: "demo/web:dev" with ID "sha256:902178ca06f85d0e937b22447962845b19804f53e648bc93d6f24a355eb5c04b" not yet present on node "lab-worker2", loading...
Image: "demo/web:dev" with ID "sha256:902178ca06f85d0e937b22447962845b19804f53e648bc93d6f24a355eb5c04b" not yet present on node "lab-control-plane", loading...
kind load docker-image делает docker save — выгружает образ в tar-архив — и импортирует его в containerd каждого узла (ctr images import в пространстве имён k8s.io, где containerd держит образы kubelet). Для Podman и для готовых архивов есть kind load image-archive файл.tar.
Тонкость, на которой спотыкаются почти все: у контейнера в поде есть поле imagePullPolicy — когда kubelet должен скачивать образ из реестра. Если тег образа latest или не указан, по умолчанию стоит Always: kubelet пойдёт в реестр, не найдёт там demo/web:latest и под зависнет в ErrImagePull, хотя образ лежит на узле. С тегом dev по умолчанию IfNotPresent — образ с узла будет использован. Поэтому образы для kind помечают осмысленным тегом, а не latest; подробно политика разобрана в части 5.
$ kubectl create deployment web --image=demo/web:dev --replicas=2
deployment.apps/web created
$ kubectl create service nodeport web --tcp=80:80 --node-port=30080
service/web created
$ kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].imagePullPolicy}{"\n"}'
IfNotPresent
$ curl -s http://127.0.0.1:8080/
<h1>hello from kind</h1>
Запрос пришёл на опубликованный порт контейнера lab-control-plane, kube-proxy внутри него перенаправил его на один из подов — оба пода при этом на рабочих узлах. Если curl сразу после выкатки вернул пустой ответ, kube-proxy ещё не успел записать правила для нового сервиса: через секунду-другую запрос проходит. Deployment и Service здесь — заготовка, они разобраны в части 7 и части 15.
LoadBalancer в kind
Сервис типа LoadBalancer в kind по умолчанию навсегда остаётся с EXTERNAL-IP <pending>: в Kubernetes адреса балансировщикам выдаёт облачный контроллер (cloud-controller-manager), а у kind облака нет. Решение от авторов — cloud-provider-kind: отдельная программа, которая запускается на ноутбуке (ей нужны права на Docker и на открытие портов), следит за сервисами LoadBalancer во всех кластерах kind и на каждый создаёт контейнер-балансировщик в сети kind. Его адрес из сети Docker и становится EXTERNAL-IP.
$ curl -LO https://github.com/kubernetes-sigs/cloud-provider-kind/releases/download/v0.12.0/cloud-provider-kind_0.12.0_linux_amd64.tar.gz
$ curl -LO https://github.com/kubernetes-sigs/cloud-provider-kind/releases/download/v0.12.0/cloud-provider-kind_0.12.0_checksums.txt
$ grep linux_amd64 cloud-provider-kind_0.12.0_checksums.txt | sha256sum -c
cloud-provider-kind_0.12.0_linux_amd64.tar.gz: OK
$ tar xzf cloud-provider-kind_0.12.0_linux_amd64.tar.gz cloud-provider-kind
$ sudo install -m 0755 cloud-provider-kind /usr/local/bin/
$ sudo cloud-provider-kind # оставить работать в отдельном терминале
$ kubectl expose deployment web --name=web-lb --type=LoadBalancer --port=80
service/web-lb exposed
$ kubectl get svc web-lb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-lb LoadBalancer 10.97.254.5 172.18.0.5 80:30933/TCP 20s
$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}' | grep kindccm
kindccm-e1b23e1f7834 envoyproxy/envoy:v1.33.2 0.0.0.0:32768->10000/tcp, [::]:32768->10000/tcp
$ curl -s http://172.18.0.5/
<h1>hello from kind</h1>
Балансировщик — контейнер с прокси-сервером Envoy, адрес 172.18.0.5 выдан ему в сети kind. Обратите внимание на колонку PORTS: Docker публикует порт Envoy на всех адресах ноутбука, так что сервис становится доступен из локальной сети по случайному порту — в общественной сети это стоит иметь в виду. В версии 0.12 cloud-provider-kind заодно реализует Ingress и Gateway API (флаги --enable-default-ingress и --gateway-channel в начале его журнала): kind без отдельного ingress-контроллера понимает объекты из части 18.
На Linux адреса сети kind доступны с ноутбука напрямую. На macOS и Windows Docker живёт внутри виртуальной машины, и до адресов 172.18.0.x с хоста не достучаться без дополнительной переадресации — это главная сетевая грабля kind на этих системах, и она же касается NodePort без extraPortMappings. На стенде LoadBalancer даёт MetalLB из части 17.
k3s: один бинарь вместо кластера пакетов
k3s сделала компания Rancher (теперь SUSE) для узлов с малыми ресурсами: граничные устройства, Raspberry Pi, CI, небольшие серверы. Сейчас это проект CNCF — фонда Cloud Native Computing Foundation, в котором живёт и сам Kubernetes. Это не «Kubernetes в контейнерах», а настоящий дистрибутив для Linux-машин — физических или виртуальных, — только собранный иначе, чем kubeadm.
Один бинарь. API-сервер, планировщик, controller-manager, kubelet, kube-proxy, containerd, runc, CNI-плагины, kubectl, crictl, ctr — всё внутри одного исполняемого файла /usr/local/bin/k3s размером около 80 МБ. Компоненты control plane работают не подами, как у kubeadm, а горутинами одного процесса k3s server; на рабочих узлах работает k3s agent. Одна служба systemd на узел: k3s.service на сервере, k3s-agent.service на агенте.
Хранилище состояния. По умолчанию k3s хранит объекты API не в etcd, а в SQLite — встраиваемой базе данных в одном файле, /var/lib/rancher/k3s/server/db/state.db. Между API-сервером и SQLite стоит прослойка kine («kine is not etcd»): она реализует ту часть протокола etcd, которой пользуется kube-apiserver (get, list, watch, транзакции), поверх SQL-базы. Через ту же kine k3s умеет хранить состояние во внешних PostgreSQL или MySQL. Третий вариант — встроенный etcd: флаг --cluster-init на первом сервере, и k3s запустит etcd внутри своего процесса; тогда к нему можно присоединить ещё серверы и получить отказоустойчивый control plane. Серверов при этом нечётное число — три, пять: etcd держит кворум большинством, и четвёртый сервер не прибавляет устойчивости. Кластер на SQLite можно перевести на встроенный etcd, перезапустив сервер с --cluster-init.
Встроенные компоненты. То, что в кластере kubeadm мы ставим сами, k3s приносит с собой:
| Компонент | Что это | Как отключить |
|---|---|---|
| Flannel | CNI от CoreOS: подсеть на узел, между узлами VXLAN | --flannel-backend=none (и ставить свой CNI) |
| CoreDNS | DNS кластера | --disable=coredns |
| Traefik 3 | ingress-контроллер: обратный прокси, принимающий HTTP(S) снаружи и раскладывающий по сервисам | --disable=traefik |
| ServiceLB (klipper-lb) | реализация сервисов LoadBalancer без облака | --disable=servicelb |
| local-path-provisioner | тома в каталоге на диске узла, StorageClass local-path |
--disable=local-storage |
| metrics-server | сбор CPU и памяти подов для kubectl top и автомасштабирования |
--disable=metrics-server |
| контроллер сетевых политик | кусок kube-router (маршрутизатора для Kubernetes), который превращает NetworkPolicy в правила iptables | --disable-network-policy |
| helm-controller | контроллер ресурса HelmChart: ставит чарты Helm (пакетов приложений для Kubernetes, о них — в части 27) из манифестов |
--disable-helm-controller |
| CRD Gateway API | типы Gateway, HTTPRoute и другие из части 18, их понимает встроенный Traefik |
--disable=gateway-api-crd |
Flannel — один из первых CNI-плагинов: каждому узлу выдаёт подсеть из 10.42.0.0/16 (у k3s по умолчанию), а пакеты между узлами заворачивает в VXLAN — L2-кадры внутри UDP-датаграмм на порт 8472. Сам VXLAN подробно разобран в части 18 сетевой серии. Сеть сервисов у k3s — 10.43.0.0/16, адрес DNS — 10.43.0.10.
ServiceLB (бывший klipper-lb) устроен просто. На каждый сервис типа LoadBalancer он создаёт DaemonSet в kube-system — по поду на каждом подходящем узле со свободным портом. Под объявляет hostPort с портом сервиса, то есть занимает этот порт на адресе узла, и правилами iptables перенаправляет входящее на ClusterIP сервиса. В EXTERNAL-IP сервиса попадают адреса узлов. Отсюда ограничения: на одном узле не может быть двух LoadBalancer с одинаковым портом. Второй сервис останется в Pending, если нужный порт занят на всех подходящих узлах, а «внешний адрес» — это адрес узла, который исчезает вместе с узлом.
Установка
Официальный способ — скрипт с get.k3s.io. Перед тем как запускать скрипт из интернета под sudo, его стоит скачать и прочитать; переменные окружения задают версию и роль:
user@k3s-1:~$ curl -sfL https://get.k3s.io -o install-k3s.sh
user@k3s-1:~$ less install-k3s.sh
user@k3s-1:~$ sudo INSTALL_K3S_CHANNEL=v1.37 sh install-k3s.sh
[INFO] Finding release for channel v1.37
[INFO] Using v1.37.2+k3s1 as release
[INFO] Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.37.2%2Bk3s1/sha256sum-amd64.txt
[INFO] Downloading binary https://github.com/k3s-io/k3s/releases/download/v1.37.2%2Bk3s1/k3s
[INFO] Verifying binary download
[INFO] Installing k3s to /usr/local/bin/k3s
[INFO] Skipping installation of SELinux RPM
[INFO] Creating /usr/local/bin/kubectl symlink to k3s
[INFO] Creating /usr/local/bin/crictl symlink to k3s
[INFO] Creating /usr/local/bin/ctr symlink to k3s
[INFO] Creating killall script /usr/local/bin/k3s-killall.sh
[INFO] Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO] env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO] systemd: Creating service file /etc/systemd/system/k3s.service
[INFO] systemd: Enabling k3s unit
Created symlink '/etc/systemd/system/multi-user.target.wants/k3s.service' → '/etc/systemd/system/k3s.service'.
[INFO] systemd: Starting k3s
Здесь k3s-1 (192.168.122.11) и k3s-2 (192.168.122.12) — две учебные виртуальные машины с Ubuntu Server 26.04 на ноутбуке, в сети libvirt по умолчанию, отдельно от стенда. Канал v1.37 выбирает последний выпуск ветки 1.37. На стенде он дал v1.37.2+k3s1. Для повторения примера с тем же выпуском передайте INSTALL_K3S_VERSION=v1.37.2+k3s1 на обоих узлах. Ссылки kubectl, crictl и ctr скрипт создаёт, только если таких команд ещё нет: на машине, где стоит пакет kubectl, он напишет Skipping /usr/local/bin/kubectl symlink to k3s, command exists in PATH, и kubectl будет смотреть не в k3s.
Через полминуты:
user@k3s-1:~$ sudo k3s kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3s-1 Ready control-plane 29s v1.37.2+k3s1
user@k3s-1:~$ sudo k3s kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-577d995dff-wnd5r 1/1 Running 0 65s
kube-system helm-install-gateway-api-crd-brl9s 0/1 Completed 0 66s
kube-system helm-install-traefik-6pmh2 0/1 Completed 1 (47s ago) 66s
kube-system helm-install-traefik-crd-nfj49 0/1 Completed 0 66s
kube-system local-path-provisioner-56c6584955-g4qvf 1/1 Running 0 65s
kube-system metrics-server-778c4649b4-zj7fw 1/1 Running 0 65s
kube-system svclb-traefik-59103bc3-cp4bx 2/2 Running 0 45s
kube-system traefik-68df944ff7-jlbh2 1/1 Running 0 45s
Ни одного пода control plane: API-сервер, планировщик и controller-manager живут внутри процесса k3s server, поэтому их нет ни в kube-system, ни в /etc/kubernetes/manifests — каталоге, из которого kubelet в кластере kubeadm запускает статические поды control plane (поды, описанные файлами на узле, а не объектами в API). Поды helm-install-* — это helm-controller, который из файлов в /var/lib/rancher/k3s/server/manifests/ поставил чарты Traefik и CRD Gateway API; первая попытка helm-install-traefik падает и перезапускается, пока CRD Traefik не зарегистрированы, — это нормально. Под svclb-traefik-… — ServiceLB, занявший порты 80 и 443 узла для сервиса Traefik. Роль у сервера одна, control-plane: прежняя метка master в 1.37 больше не ставится.
Kubeconfig администратора k3s пишет в /etc/rancher/k3s/k3s.yaml, файл доступен только root. Чтобы работать с ноутбука, файл копируют и меняют в нём server: https://127.0.0.1:6443 на адрес узла:
$ ssh user@k3s-1 sudo cat /etc/rancher/k3s/k3s.yaml | sed 's/127.0.0.1/192.168.122.11/; s/: default/: k3s-lab/' > ~/.kube/k3s-lab.yaml
$ chmod 600 ~/.kube/k3s-lab.yaml
$ KUBECONFIG=~/.kube/k3s-lab.yaml kubectl get nodes
После sed кластер, пользователь и контекст в файле называются k3s-lab, а kubectl с ноутбука видит те же узлы, что k3s kubectl на сервере.
В этом файле — клиентский сертификат с правами cluster-admin, тот же уровень, что admin.conf у kubeadm; обращаться с ним нужно как с паролем root.
Второй узел
Агент присоединяется по токену, который сервер положил в /var/lib/rancher/k3s/server/node-token:
user@k3s-1:~$ sudo cat /var/lib/rancher/k3s/server/node-token
K10276633…::server:63e0…
user@k3s-2:~$ curl -sfL https://get.k3s.io -o install-k3s.sh
user@k3s-2:~$ less install-k3s.sh
user@k3s-2:~$ sudo INSTALL_K3S_CHANNEL=v1.37 K3S_URL=https://192.168.122.11:6443 \
K3S_TOKEN='K10276633…::server:63e0…' sh install-k3s.sh
...
[INFO] Creating uninstall script /usr/local/bin/k3s-agent-uninstall.sh
[INFO] env: Creating environment file /etc/systemd/system/k3s-agent.service.env
[INFO] systemd: Creating service file /etc/systemd/system/k3s-agent.service
[INFO] systemd: Enabling k3s-agent unit
Created symlink '/etc/systemd/system/multi-user.target.wants/k3s-agent.service' → '/etc/systemd/system/k3s-agent.service'.
[INFO] systemd: Starting k3s-agent
user@k3s-1:~$ sudo k3s kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3s-1 Ready control-plane 71s v1.37.2+k3s1
k3s-2 Ready <none> 18s v1.37.2+k3s1
Наличие K3S_URL превращает установку в агента. В полном токене за префиксом K10 идёт хеш CA кластера. Агент проверяет по нему CA при первом подключении и проверяет сертификат сервера до отправки учётных данных, так же, как kubeadm join проверяет --discovery-token-ca-cert-hash. Агент поднимает у себя локальный балансировщик на 127.0.0.1:6444, через который kubelet и kube-proxy ходят к серверам: если серверов несколько, агент сам переключается между ними.
user@k3s-2:~$ sudo ss -lntp | grep 6444
LISTEN 0 4096 127.0.0.1:6444 0.0.0.0:* users:(("k3s-agent",pid=2129,fd=4))
LISTEN 0 4096 [::1]:6444 [::]:* users:(("k3s-agent",pid=2129,fd=7))
user@k3s-2:~$ sudo grep server: /var/lib/rancher/k3s/agent/kubelet.kubeconfig
server: https://127.0.0.1:6444
Чем k3s отличается от кластера kubeadm
- Компоненты control plane — не поды, их не видно через
kubectl; логи — вjournalctl -u k3s, параметры — флагиk3s serverили/etc/rancher/k3s/config.yaml. - containerd встроенный, со своим сокетом
/run/k3s/containerd/containerd.sockи каталогом/var/lib/rancher/k3s/agent/containerd; настройки реестров — в/etc/rancher/k3s/registries.yaml, а не в/etc/containerd/certs.d.crictlиctrиз комплекта k3s уже смотрят в нужный сокет. - Состояние в SQLite, а не в etcd:
etcdctlи снапшоты etcd из части 34 к такому кластеру неприменимы, для резервной копии сохраните весь каталог/var/lib/rancher/k3s/server/db/и файл токена/var/lib/rancher/k3s/server/token. - Сети подов и сервисов —
10.42.0.0/16и10.43.0.0/16, а не наши172.20.0.0/16и10.96.0.0/12; меняются флагами--cluster-cidrи--service-cidr. - Обновление — заменой бинаря (или тем же скриптом с новым каналом), а не
kubeadm upgrade.
Грабли k3s
- Traefik и ServiceLB заняли 80 и 443. Если на узле уже есть веб-сервер или вы хотите MetalLB и свой ingress-контроллер, их нужно отключить при установке:
INSTALL_K3S_EXEC="--disable=traefik --disable=servicelb". У существующего кластера с--disable=traefikk3s удалит встроенное дополнение Traefik. Для отключения ServiceLB задайте--disable=servicelbна всех серверах кластера. - Встроенный Traefik перезаписывается. Править его манифест в
/var/lib/rancher/k3s/server/manifests/traefik.yamlбесполезно: k3s перепишет файл при старте. Настройки — отдельным ресурсомHelmChartConfig. - Порты между узлами. Для Flannel нужен UDP 8472, для kubelet — TCP 10250, для API — TCP 6443. Файрвол хоста, закрывший 8472, даёт кластер, где поды на разных узлах не видят друг друга, а на одном — видят.
- local-path привязывает данные к узлу. Том — каталог
/var/lib/rancher/k3s/storage/…конкретного узла: под с таким томом не переедет на другой узел, а данные пропадут вместе с диском. Для тестов это нормально, для данных — нет; хранилище подробно — в части 21. - Один сервер на SQLite — точка отказа. Для учебного кластера это нормально; для чего-то большего — встроенный etcd на трёх серверах.
Есть ещё k3d — обёртка, которая запускает k3s в контейнерах Docker по образцу kind. Если нужен именно k3s на ноутбуке без виртуальных машин, это он.
minikube: кластер в виртуальной машине или контейнере
minikube — самый старый из троих, проект самого Kubernetes, задуманный как «кластер для разработчика на рабочей станции». Его отличие — драйверы: minikube умеет создать узел как виртуальную машину в гипервизоре или как контейнер.
- Виртуальные машины: KVM (гипервизор ядра Linux, драйвер
kvm2), QEMU (эмулятор и гипервизор, работает на всех ОС), Hyper-V (гипервизор Windows), VFkit (обёртка над Virtualization.framework macOS), VirtualBox, Parallels, VMware. В ВМ загружается собственный образ minikube ISO — минимальный Linux с containerd и kubelet. - Контейнеры:
dockerиpodman— узел, как у kind, контейнер с systemd внутри (образkicbase). noneиssh— поставить кластер прямо на текущую или удалённую Linux-машину; это для особых случаев.
Предпочтительные драйверы: на Linux — docker или kvm2, на macOS — docker или vfkit, на Windows — hyperv или docker. ВМ даёт настоящее ядро, отдельное от ноутбука, — важно, когда нужны модули ядра, свои параметры sysctl или проверка того, как приложение ведёт себя на «чистой» машине. Контейнер — быстрее и легче.
Внутри узла minikube тоже работает kubeadm. Начиная с v1.39 runtime по умолчанию — containerd, как у нас (раньше был Docker Engine с адаптером cri-dockerd); выбрать можно флагом --container-runtime.
Установка и первый кластер
$ curl -LO https://github.com/kubernetes/minikube/releases/download/v1.39.0/minikube-linux-amd64
$ curl -LO https://github.com/kubernetes/minikube/releases/download/v1.39.0/minikube-linux-amd64.sha256
$ echo "$(cat minikube-linux-amd64.sha256) minikube-linux-amd64" | sha256sum -c
minikube-linux-amd64: OK
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube
$ minikube start --driver=docker --kubernetes-version=v1.37.2 \
--container-runtime=containerd --cpus=2 --memory=3g --nodes=2 --cni=calico
* minikube v1.39.0 on Ubuntu 26.04
! Specified Kubernetes version 1.37.2 is newer than the newest supported version: v1.37.0. Use `minikube config defaults kubernetes-version` for details.
! Specified Kubernetes version 1.37.2 not found in Kubernetes version list
* Searching the internet for Kubernetes version...
* Kubernetes version 1.37.2 found in GitHub version list
* Using the docker driver based on user configuration
* Using Docker driver with root privileges
* Starting "minikube" primary control-plane node in "minikube" cluster
* Pulling base image v0.0.51 ...
* Downloading Kubernetes v1.37.2 preload ...
> gcr.io/k8s-minikube/kicbase: 507.60 MiB / 507.61 MiB 100.00% 21.92 MiB
* Preparing Kubernetes v1.37.2 on containerd 2.3.4 ...
* Configuring Calico (Container Networking Interface) ...
* Verifying Kubernetes components...
- Using image gcr.io/k8s-minikube/storage-provisioner:v5
* Enabled addons: default-storageclass, storage-provisioner
* Starting "minikube-m02" worker node in "minikube" cluster
* Pulling base image v0.0.51 ...
* Found network options:
- NO_PROXY=192.168.49.2
* Preparing Kubernetes v1.37.2 on containerd 2.3.4 ...
- env NO_PROXY=192.168.49.2
* Verifying Kubernetes components...
* Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
Стенд серии на 1.37.2, а minikube 1.39 знает версии только до 1.37.0. Он предупредил об этом, нашёл 1.37.2 в выпусках Kubernetes на GitHub и поставил её — с более новой версией, чем проверяли авторы minikube, это работает, но без гарантий. Вместе со скачиванием образа узла kicbase (полгигабайта) старт занял почти три минуты. Узлы — контейнеры с Debian 12 внутри, на ядре ноутбука:
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
minikube Ready control-plane 27s v1.37.2 192.168.49.2 <none> Debian GNU/Linux 12 (bookworm) 7.0.0-42-generic (amd64) containerd://2.3.4
minikube-m02 NotReady <none> 8s v1.37.2 192.168.49.3 <none> Debian GNU/Linux 12 (bookworm) 7.0.0-42-generic (amd64) containerd://2.3.4
--cni=calico ставит тот же CNI, что на стенде (по умолчанию minikube выбирает CNI сам: bridge для одного узла, kindnet для нескольких). --cpus и --memory задаются на каждый узел: на машине с 4 ядрами и 8 ГБ два узла по 3 ГБ — разумный предел. Профили (-p имя) позволяют держать несколько кластеров одновременно; контекст в kubeconfig называется по имени профиля.
Дополнения
Сильная сторона minikube — addons: готовые компоненты, которые включаются одной командой.
$ minikube addons list | grep -E 'dashboard |ingress |metrics|registry |metallb'
│ dashboard │ minikube │ disabled │ Kubernetes │
│ ingress │ minikube │ disabled │ Kubernetes │
│ metallb │ minikube │ disabled │ 3rd party (MetalLB) │
│ metrics-server │ minikube │ disabled │ Kubernetes │
│ registry │ minikube │ disabled │ minikube │
$ minikube addons enable metrics-server
...
- Using image registry.k8s.io/metrics-server/metrics-server:v0.9.0
* The 'metrics-server' addon is enabled
$ minikube addons enable ingress
...
- Using image registry.k8s.io/ingress-nginx/controller:v1.15.1
- Using image registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.9
* Verifying ingress addon...
* The 'ingress' addon is enabled
В minikube 1.39 есть также дополнение traefik, которое включается командой minikube addons enable traefik.
ingress — контроллер ingress-nginx на основе веб-сервера nginx (сам проект ingress-nginx с марта 2026 года больше не сопровождается, для нового лучше Traefik или Gateway API, о них — в части 18), metrics-server — для kubectl top, registry — реестр образов внутри кластера, metallb — тот же MetalLB, что на стенде, dashboard — веб-интерфейс Kubernetes Dashboard (minikube dashboard откроет его в браузере). storage-provisioner — провижинер minikube, создающий тома каталогами на узле (класс standard, аналог local-path).
Таблица addons list не во всём верна: после minikube start --nodes=2 строки default-storageclass и storage-provisioner в ней значатся disabled, хотя minikube start написал Enabled addons: default-storageclass, storage-provisioner, а StorageClass standard и под storage-provisioner в кластере есть и работают. Что на самом деле включено, надёжнее смотреть в самом кластере.
Образы и доступ к сервисам
Свой образ — без реестра, как у kind:
$ minikube image load demo/web:dev
$ minikube image ls | grep demo
docker.io/demo/web:dev
Можно и собрать прямо внутри узла: minikube image build -t demo/web:dev ..
Сервис NodePort открывается командой minikube service web --url: на Linux с драйвером docker она просто печатает адрес узла, а на macOS и Windows, где адрес узла с хоста недоступен, поднимает туннель и печатает http://127.0.0.1:<порт>, работающий, пока команда не остановлена.
$ kubectl create deployment web --image=demo/web:dev --replicas=2
$ kubectl expose deployment web --type=NodePort --port=80
$ minikube service web --url
http://192.168.49.2:30180
Для LoadBalancer — minikube tunnel в отдельном терминале. Она добавляет на ноутбуке маршрут к сети сервисов через адрес узла minikube (поэтому ей нужен sudo) и проставляет сервисам LoadBalancer EXTERNAL-IP, равный их ClusterIP:
$ kubectl expose deployment web --name=web-lb --type=LoadBalancer --port=80
$ minikube tunnel
Status:
machine: minikube
pid: 21867
route: 10.96.0.0/12 -> 192.168.49.2
minikube: Running
services: [web-lb]
errors:
minikube: no errors
router: no errors
loadbalancer emulator: no errors
$ kubectl get svc web-lb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-lb LoadBalancer 10.107.252.59 10.107.252.59 80:32623/TCP 16s
$ curl -s http://10.107.252.59/
<h1>hello from kind</h1>
Страница всё та же — её отдаёт образ demo/web:dev, собранный для kind. Туннель работает, пока запущен. Если его процесс убит, маршрут 10.96.0.0/12 на ноутбуке остаётся, и minikube delete его тоже не убирает — после удаления кластера он висит со статусом linkdown. minikube tunnel --cleanup удаляет записи о прежних туннелях и тут же запускает новый, то есть это не разовая команда очистки. Надёжнее всего после экспериментов проверить ip route и удалить лишнее руками: sudo ip route del 10.96.0.0/12.
Грабли minikube
- Ресурсы по умолчанию скромные: 2 CPU и память, вычисленная от объёма ОЗУ хоста, — обычно несколько гигабайт. Для чего-то тяжелее пары подов задайте
--cpusи--memoryпри первом старте: у существующего кластера они не меняются, только пересозданием. - Драйвер выбирается раз. Сменить драйвер у существующего профиля нельзя —
minikube deleteи заново. - Сеть до узла. С драйвером docker на macOS и Windows адрес узла недоступен с хоста; всё через
minikube serviceиminikube tunnel. - Дополнения определяют, какие манифесты заработают. Для Ingress с аннотациями Traefik включите Traefik. Класс
standardиспользует локальный провижинер minikube. Для томов из серии установите соответствующий CSI-драйвер.
Чем все трое отличаются от кластера kubeadm
Всё, что касается API и объектов, одинаково. Расходится то, что ниже API:
LoadBalancer. В кластере на «железе» сервису типа LoadBalancer адрес выдаёт отдельный компонент: у нас это MetalLB из части 17, отвечающий на ARP-запросы за адреса своего пула. У kind — cloud-provider-kind с контейнерами-балансировщиками, у k3s — ServiceLB с hostPort на адресах узлов, у minikube — туннель с маршрутом на ноутбуке. Манифест одинаковый, а путь пакета и поведение при отказе — нет. Проверять на ноутбуке, как сервис переживает падение узла, бессмысленно.
Хранилище. Все трое по умолчанию дают тома-каталоги на узле. Тома NFS или SMB, с которыми работает стенд, ведут себя иначе: том доступен с любого узла, есть права на стороне сервера, блокировки, задержки сети. Ошибки с fsGroup, root_squash и правами на каталог на ноутбуке не воспроизводятся.
Сеть. kindnet и Flannel не реализуют NetworkPolicy так, как Calico (у k3s политики делает отдельный контроллер kube-router, у kind — свой минимальный); Calico-специфичные ресурсы GlobalNetworkPolicy в них отсутствуют. В kind по умолчанию kube-proxy работает через iptables, у стенда — nftables. Сеть узлов kind — мост Docker, и MTU, маршрутизация между подсетями, VXLAN поверх реальной сети в нём не встречаются.
Ядро и runtime. Поды kind и minikube (с драйвером docker) работают на ядре ноутбука, вложенными в контейнер-узел. Ограничения cgroups, sysctl, seccomp и AppArmor — те, что разрешил Docker. На macOS и Windows это вообще ядро служебной ВМ Docker Desktop.
Устойчивость. Кластер kind переживает перезапуск Docker не всегда: адреса контейнеров в сети kind могут смениться, и сертификаты, выписанные на старые адреса, перестанут подходить. Это одноразовые кластеры — их не лечат, а пересоздают, и это правильный способ работы с ними: конфигурация кластера в файле, создание за минуту.
Сравнение
| kind | k3s | minikube | |
|---|---|---|---|
| Узел | контейнер Docker/Podman | Linux-машина (ВМ, железо) | ВМ или контейнер, по драйверу |
| Установка Kubernetes внутри | kubeadm | свой бинарь, без kubeadm | kubeadm |
| Хранилище состояния | etcd | SQLite (kine), встроенный etcd, PostgreSQL/MySQL | etcd |
| Control plane | статические поды | горутины процесса k3s server |
статические поды |
| CNI по умолчанию | kindnet | Flannel (VXLAN) | bridge / kindnet, выбор --cni |
| LoadBalancer | cloud-provider-kind (отдельно) | ServiceLB, встроен | minikube tunnel |
| Ingress | через cloud-provider-kind | Traefik, встроен | дополнения traefik или ingress |
| Тома | local-path, класс standard |
local-path, класс local-path |
hostpath, класс standard |
| Несколько узлов | да, файлом конфигурации | да, агентами на других машинах | да, --nodes |
| Свой образ без реестра | kind load |
импорт в containerd (k3s ctr images import) |
minikube image load |
| Время создания | ~1 мин | ~30 с на узел | 1–3 мин |
| Годится для постоянной работы | нет | да | нет |
Когда какой
- kind — CI и проверка манифестов. Кластер поднимается в любом раннере, где есть Docker, конфигурация в одном файле, версия Kubernetes выбирается образом. Тесты самого Kubernetes и большинства операторов гоняют на kind. Многоузловой кластер на одном ноутбуке — тоже к нему.
- k3s — когда нужен настоящий, долго живущий кластер на скромном железе: домашний сервер, филиал, граничное устройство, учебный кластер на одной ВМ. Это полноценный дистрибутив, его используют и в эксплуатации. Для ноутбука — через k3d или в ВМ.
- minikube — разработка на рабочей станции, особенно на macOS и Windows: драйверы ВМ, addons, туннели решают большинство проблем «как достучаться до сервиса». Если нужно отдельное ядро — тоже к нему.
Для полноты: есть MicroK8s — дистрибутив Canonical, ставится snap-пакетом и, как minikube, включает компоненты командой microk8s enable; k0s — ещё один дистрибутив «одним бинарём», от Mirantis; и встроенный Kubernetes в Docker Desktop и Rancher Desktop — галочка в настройках, поднимающая одноузловой кластер в служебной ВМ. Устроены они по тем же образцам, что разобраны выше.
Смотрим руками
Узлы kind — это контейнеры:
$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
NAMES IMAGE PORTS
lab-worker kindest/node:v1.37.0
lab-worker2 kindest/node:v1.37.0
lab-control-plane kindest/node:v1.37.0 127.0.0.1:37483->6443/tcp, 127.0.0.1:8080->30080/tcp
$ docker inspect lab-control-plane --format '{{.HostConfig.Privileged}}'
true
$ docker exec lab-worker ps -e -o pid,comm | head -12
PID COMMAND
1 systemd
95 systemd-journal
139 containerd
239 kubelet
290 containerd-shim
321 containerd-shim
333 pause
352 pause
409 kube-proxy
584 kindnetd
788 containerd-shim
PID 1 — systemd, под ним те же процессы, что на k8s-node-1. Внутрь узла можно зайти и пользоваться теми же инструментами, что на стенде:
$ docker exec -it lab-worker bash
root@lab-worker:/# crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD NAMESPACE
f560e14023694 50bfe947daf23 59 seconds ago Running web 0 317fd06885853 web-85c764c6f7-fkfpz default
2be56b80e9552 4626fe10df5b9 About a minute ago Running kindnet-cni 0 0b114641a368f kindnet-skbsr kube-system
39934b0c1394f d6a28daf3e6b0 About a minute ago Running kube-proxy 0 fb7cf17ed540e kube-proxy-lznlh kube-system
root@lab-worker:/# ip route
default via 172.18.0.1 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.3
172.20.0.0/24 via 172.18.0.2 dev eth0
172.20.1.0/24 via 172.18.0.4 dev eth0
172.20.2.2 dev veth25d6c26d scope host
Так работает kindnet: подсети соседних узлов — обычные маршруты через их адреса в сети Docker, у пода — veth с маршрутом /32 на узле. Никакой инкапсуляции.
Образ, загруженный kind load, в containerd узла:
root@lab-worker:/# ctr -n k8s.io images ls -q | grep demo
docker.io/demo/web:dev
Имя дополнилось до docker.io/demo/web:dev: короткое имя без реестра containerd считает образом с Docker Hub. Если бы imagePullPolicy был Always, kubelet пошёл бы именно туда.
k3s — один процесс вместо статических подов:
user@k3s-1:~$ ps -e -o pid,rss,args | grep -E 'k3s (server|agent)|containerd ' | grep -v grep
3650 970152 /usr/local/bin/k3s server
3666 192072 containerd
user@k3s-1:~$ ls /etc/kubernetes/manifests
ls: cannot access '/etc/kubernetes/manifests': No such file or directory
user@k3s-1:~$ sudo ls -la /var/lib/rancher/k3s/server/db/
total 23800
drwx------ 2 root root 4096 Nov 7 15:13 .
drwx------ 8 root root 4096 Nov 7 15:13 ..
-rw-r--r-- 1 root root 12087296 Nov 7 15:13 state.db
-rw-r--r-- 1 root root 32768 Nov 7 15:14 state.db-shm
-rw-r--r-- 1 root root 12236432 Nov 7 15:14 state.db-wal
API-сервер, планировщик, controller-manager и kubelet — в одном процессе k3s server (около 950 МБ памяти на всё через минуту после запуска), containerd — отдельный дочерний процесс, и аргументов у него в ps не видно. На агенте k3s agent занимает около 190 МБ. Состояние кластера — файл SQLite с журналом WAL. Внутрь можно заглянуть обычным sqlite3: kine хранит объекты в таблице kine с ключами вида /registry/pods/kube-system/coredns-… — та же схема ключей, что у etcd в кластере kubeadm.
user@k3s-1:~$ sudo sqlite3 /var/lib/rancher/k3s/server/db/state.db \
"select name from kine where name like '/registry/services/specs/%' group by name;"
/registry/services/specs/default/kubernetes
/registry/services/specs/kube-system/kube-dns
/registry/services/specs/kube-system/metrics-server
/registry/services/specs/kube-system/traefik
ServiceLB на узле:
user@k3s-1:~$ sudo k3s kubectl get svc -n kube-system traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.65.154 192.168.122.12,192.168.122.11 80:31293/TCP,443:30503/TCP 58s
user@k3s-1:~$ sudo iptables -t nat -S | grep 'CNI-DN.*dport 80 .*DNAT'
-A CNI-DN-11cd7dd21d93ed04fed3d -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.42.0.8:80
EXTERNAL-IP — адреса самих узлов. Цепочка CNI-DN-… — работа CNI-плагина portmap, который реализует hostPort пода svclb-traefik: пакет на порт 80 узла уходит в под ServiceLB, а оттуда — на ClusterIP Traefik.
minikube — узел и его маршрут:
$ minikube ssh -- sudo crictl pods --name storage
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
76dbfd8e2ed2f About a minute ago Ready storage-provisioner kube-system 0 (default)
$ ip route | grep -E '10.96|192.168.49'
10.96.0.0/12 via 192.168.49.2 dev br-a52b9036e7e3
192.168.49.0/24 dev br-a52b9036e7e3 proto kernel scope link src 192.168.49.1
minikube tunnel добавил маршрут к сети сервисов через адрес узла minikube в мосту Docker — именно так пакеты на «внешний» адрес LoadBalancer попадают в кластер.
Удаление — одной командой у каждого: kind delete cluster --name lab, minikube delete, /usr/local/bin/k3s-uninstall.sh на сервере и k3s-agent-uninstall.sh на агентах.
Кластеры на одной машине пригодятся и после всей серии: манифесты, чарты и конфигурацию для GitOps удобно сперва проверить на kind, k3s или minikube — создать кластер за минуту и выбросить без сожаления. А как поведут себя LoadBalancer, сетевые тома и сеть между узлами, покажет только настоящий кластер вроде нашего стенда.
Источники
- kind: быстрый старт и загрузка образов, конфигурация кластера, выпуск v0.33.0 и образы узлов, LoadBalancer, cloud-provider-kind.
- k3s: архитектура, установка, выпуск v1.37.2+k3s1, переменные установщика, сетевые сервисы, встроенные компоненты, токены, резервное копирование и восстановление.
- minikube: быстрый старт, выпуск v1.39.0, драйверы, дополнения, дополнение Traefik, локальные образы, доступ к сервисам.
- Kubernetes: образы и политика загрузки, прекращение поддержки ingress-nginx.
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.