# kind: локальный Kubernetes в Docker

Индекс LLMS: [llms.txt](/llms.txt)

---

Kubernetes-кластер на ноутбуке — задача нередкая: CI/CD, эксперименты с операторами, проверка манифестов без нагрузки на prod. minikube тянет виртуалку, k3s просит отдельный host, а kind поднимает управляющую плоскость в Docker-контейнерах. Развернули, поработали, удалили — без побочных эффектов.

## Зачем kind

kind создает кластер из Docker-контейнеров: control-plane и worker-ноды — это образы `kindest/node`. Основной use-case — локальная разработка и CI. В GitHub Actions есть официальный action `create-kind`, что делает пайплайны с тестами поверх K8s тривиальными.

От minikube отличается отсутствием гипервизора и нативной поддержкой multi-node топологий. От k3d — тем, что не требует Rancher и работает с CRI/containerd напрямую.

## Установка

macOS, Linux и Windows (через WSL2) — бинарник из GitHub Releases.

```bash
# macOS
brew install kind

# Linux
curl -Lo /usr/local/bin/kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
chmod +x /usr/local/bin/kind

# Проверка
kind version
# kind v0.22.0 go1.21.8 linux/amd64
```

Понадобится Docker (или Podman с `kind use docker driver`). Убедись, что в Docker выставлен минимум 4 GB памяти для всех контейнеров.

## Первый кластер одной командой

```bash
kind create cluster
# Creating cluster "kind" ...
# ✓ Ensuring node image (kindest/node:v1.29.0) ✓
# ✓ Preparing nodes ✓
# ✓ Writing configuration ✓
# ✓ Starting control-plane ✓
# ✓ Installing CNI ✓
# ✓ Installing StorageClass ✓
# ✓ Waiting for node readiness ✓
# Successfully created cluster "kind"!
```

kind создал кластер с именем `kind`, записал kubeconfig в `~/.kube/config`. Проверяем:

```bash
kubectl get nodes
# NAME                 STATUS   ROLES           AGE   VERSION
# kind-control-plane   Ready    control-plane   2m    v1.29.0

kubectl get pods -A
# NAMESPACE            NAME                                         READY
# kube-system          coredns-...                                  1/1
# local-path-storage   local-path-provisioner-...                   1/1
```

Готово. Single-node кластер поднят за минуту.

## Конфиг: multi-node и runtime

Для кластера с несколькими worker-нодами используется YAML-конфиг. Создадим три worker-ноды:

```yaml
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 80
    hostPort: 8080
    protocol: TCP
- role: worker
- role: worker
- role: worker
```

```bash
kind create cluster --name multi --config kind-config.yaml
```

Флаги создания кластера:

| Флаг | Назначение | Пример |
|------|-----------|--------|
| `--name` | Имя кластера | `kind create cluster --name prod` |
| `--config` | Путь к YAML | `--config ./kind.yaml` |
| `--image` | Кастомный образ node | `--image kindest/node:v1.28.0` |
| `--wait` | Таймаут readiness | `--wait 5m` |
| `--kubeconfig` | Альтернативный kubeconfig | `--kubeconfig ~/.kube/dev` |

> [!TIP]
> Вместо флага `--image` можно указать `node.internalImage` в конфиге — полезно для air-gapped окружений.

## Загрузка образов в кластер

kind использует отдельный container runtime внутри ноды. Образы из локального Docker daemon не видны. Для загрузки:

```bash
# Сборка образа
docker build -t myapp:v1.0 ./myapp

# Загрузка в kind-ноды
kind load docker-image myapp:v1.0 --name multi

# Для всех нод сразу
kind load docker-image myapp:v1.1 --name multi --nodes kind-worker,kind-worker2
```

Для CI часто используют образ из tar-архива:

```bash
docker save myapp:v1.0 > myapp.tar
kind load image-archive myapp.tar --name multi
```

После загрузки образ доступен в кластере без registry.

## extraMounts и kubeadm-патчи

Смонтировать директорию хоста в ноду — для локального registry или фикстур:

```yaml
nodes:
- role: control-plane
  extraMounts:
  - hostPath: /tmp/registry
    containerPath: /var/lib/registry
```

Настройка kubelet или kube-proxy через kubeadm-патчи:

```yaml
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "env=test"
  - |
    kind: kube-proxy
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    mode: ipvs
```

Если порт API-сервера 6443 занят, задайте другой в конфиге кластера:

```yaml
networking:
  apiServerPort: 6444
```

## kind с kubeconfig

По умолчанию kind мержит контекст в `~/.kube/config`. Для изоляции:

```bash
# Отдельный kubeconfig
KUBECONFIG=~/.kube/kind-config kind create cluster --name isolated

# Или экспорт после создания
kind get kubeconfig --name multi > ./kubeconfig
export KUBECONFIG=./kubeconfig
kubectl get nodes
```

Управление несколькими кластерами:

```bash
kind get clusters
# kind
# multi
# isolated

# Удалить конкретный
kind delete cluster --name isolated
```

## Очистка

```bash
kind delete cluster --name multi
# Deleting cluster "multi" ...
```

Без `--name` удаляется кластер по умолчанию (`kind`). Все ресурсы Docker удаляются вместе с нодами. Если Docker был остановлен при работающем кластере — ноды остаются в статусе `NotReady` при следующем запуске. Лечится пересозданием кластера.

## Gotchas

**containerd внутри ноды.** kubectl работает с containerd напрямую. Привычные `docker ps` и `docker exec` не покажут поды — они живут внутри kind-ноды. Для отладки:

```bash
docker exec -it multi-control-plane crictl ps
docker exec -it multi-control-plane crictl logs <container-id>
```

**HostNetworking и PortMappings.** Для доступа извне к подам нужен `extraPortMappings` в конфиге. Без него hostPort не работает — pod Networking в kind изолирован.

**PersistentVolumes.** kind создает StorageClass `kind-node` на основе local-path-provisioner. Данные хранятся на хосте в `/var/local-path-provisioner`. Для чистого окружения — просто удали кластер.

**Cgroups v2.** В новых дистрибутивах (Ubuntu 22.04+, Fedora) Docker может требовать настройки:

```bash
docker info | grep cgroup
# Cgroup Driver: systemd
# Cgroup Version: 2
```

kind работает с обоими версиями, но в редких случаях с cgroups v2 на Arch Linux возникают проблемы с лимитами памяти. Решение — передать в конфиг:

```yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "MemoryManager": true
runtimeConfig:
  "memorymanager.k8s.io/v1alpha1": true
```

**Версии.** kind отстает от upstream Kubernetes на 1-2 минорные версии. Актуальную матрицу совместимости смотри в README проекта перед поднятием prod-подобного окружения.

**Port already allocated.** kind не смог занять порт API-сервера или проброшенный hostPort. Проверьте, что 6443 свободен, или смените `networking.apiServerPort`. Для Ingress `extraPortMappings` не должны пересекаться с сервисами на хосте.

**No space left on device.** Docker исчерпал диск. Почистите неиспользуемые образы и пересоздайте кластер:

```bash
docker system prune -a
kind delete cluster --name multi
```

---

kind — быстрый способ поднять Kubernetes на машине разработчика или в CI без виртуализации. Основной цикл: `kind create cluster`, работа, `kind delete cluster`. Для air-gapped или многонодовых сценариев — YAML-конфиг и `kind load docker-image`. Ограничения известны: нет GPU, нет реального сетевого стека, производительность ниже bare metal. Для остального — сойдет.
