Kube/Pythonproduction course
Курс · RU00-diagnostic-and-local-cluster.md

00. Диагностика Linux и локальный кластер

Незнакомый термин? Откройте словарь Kubernetes и терминов курса.

Назначение, предварительные знания и результаты обучения

Эта глава превращает рабочую станцию в воспроизводимую лабораторию и защищает от работы в неправильном контексте. Нужны командная оболочка Linux, curl, sha256sum, sudo для установки исполняемых файлов и работающий Docker Engine или совместимый Podman.

После главы вы сможете:

  • подтвердить версии ОС, cgroup, CPU/RAM и среды исполнения контейнеров;
  • установить kubectl v1.36.2 и kind v0.32.0 с проверкой контрольной суммы;
  • создать трёхузловой kind-kube-course, не затрагивая другой контекст;
  • собрать и загрузить kube-python-course:1.0.0;
  • разделить клиентскую, серверную и фактическую проверку среды исполнения;
  • собрать диагностические данные и удалить только учебный кластер.

Ментальная модель: четыре слоя

kubectl — клиент API, а не кластер. kind — инструмент управления жизненным циклом, который создаёт узлы Kubernetes как контейнеры. Docker/Podman — хостовый провайдер контейнеров. Kubernetes внутри узла использует containerd как реализацию Container Runtime Interface (CRI). Поэтому docker ps видит узлы kind, а Pods нужно искать через Kubernetes API.

kubectl → kube-apiserver → объекты/контроллеры Kubernetes
                               ↓
CLI kind → Docker/Podman → контейнеры узлов → kubelet/containerd → контейнеры Pod

Области отказа различны: неработающий Docker не равен неготовому Pod; неверный kubeconfig не равен падению сервера API; принятый YAML не означает, что образ запускается.

Предварительная проверка

uname -a
cat /etc/os-release
nproc
free -h
df -h .
stat -fc %T /sys/fs/cgroup
docker version            # или: podman version

Ожидается Linux x86_64/aarch64, cgroup v2 (cgroup2fs), не меньше 4 CPU, 8 GiB RAM и 20 GiB диска. Код завершения всех обязательных проверок — 0. Для Docker секция Server: должна отвечать; одна секция Client: не доказывает работу фонового процесса.

Машина, на которой создан курс: Ubuntu 24.04.3 LTS, ядро 6.8.0-88-generic, x86_64; инструменты для cgroup и среды исполнения контейнеров были недоступны. Ваши доказательства важнее этой справки.

Установка инструментов с проверкой

Не используйте URL с latest: версия должна быть видна в истории команд.

mkdir -p "$PWD/.tools"

curl -fL --retry 3 -o .tools/kubectl \
  https://dl.k8s.io/release/v1.36.2/bin/linux/amd64/kubectl
curl -fL --retry 3 -o .tools/kubectl.sha256 \
  https://dl.k8s.io/release/v1.36.2/bin/linux/amd64/kubectl.sha256
printf '%s  %s\n' "$(cat .tools/kubectl.sha256)" ".tools/kubectl" |
  sha256sum --check
chmod 0755 .tools/kubectl

curl -fL --retry 3 -o .tools/kind \
  https://kind.sigs.k8s.io/dl/v0.32.0/kind-linux-amd64
curl -fL --retry 3 -o .tools/kind.sha256sum \
  https://kind.sigs.k8s.io/dl/v0.32.0/kind-linux-amd64.sha256sum
(cd .tools && sha256sum --check kind.sha256sum)
chmod 0755 .tools/kind

export PATH="$PWD/.tools:$PATH"
kubectl version --client --output=yaml
kind version

Для aarch64 замените amd64 на arm64. Ожидается clientVersion.gitVersion: v1.36.2, [kind](98-glossary.md#kind) v0.32.0, код завершения 0. Несовпадение контрольной суммы — причина немедленно остановиться: удалите загрузку и исследуйте URL или прокси; не делайте исполняемый файл запускаемым.

Провайдер контейнеров устанавливайте по официальной документации вашей дистрибуции. Здесь не преподаётся Docker. Убедитесь, что docker run --rm hello-world завершился 0. Podman без root требует дополнительных настроек, описанных в документации kind; зафиксируйте KIND_EXPERIMENTAL_PROVIDER=podman.

Манифест кластера

Полный манифест локального кластера:

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: kube-course
nodes:
  - role: control-plane
  - role: worker
  - role: worker

Он сохранён в cluster/kind-config.yaml. Это API kind, а не объект Kubernetes API: у него нет metadata/spec, и kubectl его не принимает. Для первой серверной проверки используем настоящий объект:

apiVersion: v1
kind: Namespace
metadata:
  name: kube-course
  labels:
    app.kubernetes.io/part-of: kube-python-course
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: v1.36
spec: {}

Namespace.spec обычно пуст, но поле показано явно: apiVersion, kind, metadata, spec образуют полный объект API.

Практическое упражнение: создание → проверка → загрузка образа

Подготовка

Сохраните исходный контекст, но не выводите kubeconfig: там находятся учётные данные.

ORIGINAL_CONTEXT="$(kubectl config current-context 2>/dev/null || true)"
printf 'Original context: %s\n' "$ORIGINAL_CONTEXT"

kind create cluster \
  --name kube-course \
  --config cluster/kind-config.yaml \
  --image kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd5 \
  --wait 5m

Ожидаемая последняя строка содержит Set kubectl context to "kind-kube-course". Код завершения — 0. Проверка:

test "$(kubectl config current-context)" = "kind-kube-course"
kubectl version
kubectl cluster-info
kubectl get nodes -o wide
kubectl wait --for=condition=Ready nodes --all --timeout=180s
kubectl get pods -A
kubectl get storageclass

Должны быть kube-course-control-plane и два рабочих узла в Ready; системные Pods становятся Running. Клиент v1.36.2 и сервер v1.36.1 совместимы. Сохраните реальный StorageClass: локальный provisioner — дополнение конкретного дистрибутива, а не гарантия базовой поставки Kubernetes.

Собрать образ приложения

Минимальная операция с контейнером:

docker build --file app/Containerfile --tag kube-python-course:1.0.0 app
docker image inspect kube-python-course:1.0.0 \
  --format '{{.Id}} {{.Config.User}}'
kind load docker-image kube-python-course:1.0.0 --name kube-course
docker exec kube-course-worker crictl images |
  grep kube-python-course

Ожидаются неизменяемый идентификатор локального образа, пользователь 10001:10001 и наличие образа на узле; каждая команда завершается кодом 0. Для Podman укажите провайдер и используйте kind load docker-image; kind сам работает с выбранным провайдером. Если образ нужен на каждом узле, kind load загружает его туда; одна проверка через docker exec не заменяет crictl images на остальных узлах.

Уровни проверки

kubectl apply --dry-run=client -f manifests/base/namespace.yaml
kubectl apply --dry-run=server -f manifests/base/namespace.yaml
kubectl kustomize manifests/overlays/dev >/tmp/kube-course-dev.yaml
kubectl apply --dry-run=server -f /tmp/kube-course-dev.yaml

Ожидаются namespace/kube-course created (dry run) и принятие сервером. Клиентский dry-run разбирает и частично проверяет данные локально; серверный dry-run выполняет назначение значений API по умолчанию, проверку схемы, admission и авторизацию, но не планирование и загрузку образа. Только применение и наблюдаемый status проверяют фактическую среду исполнения.

Очистка и восстановление

Сначала соберите доказательства ошибки:

kind export logs /tmp/kube-course-logs --name kube-course
kubectl get events -A --sort-by=.metadata.creationTimestamp

Удаление:

test "$(kubectl config current-context)" = "kind-kube-course"
kind delete cluster --name kube-course
kind get clusters
if [ -n "$ORIGINAL_CONTEXT" ]; then
  kubectl config use-context "$ORIGINAL_CONTEXT"
fi

kind delete идемпотентен. Не используйте шаблоны подстановки и не удаляйте ~/.kube.

Самостоятельная задача

Создайте кластер с одним узлом плоскости управления и одним рабочим узлом под именем kube-course-small, отдельным --kubeconfig /tmp/kube-course-small.config. Докажите, что kubeconfig/контекст по умолчанию не изменился. Получите узлы через kubectl --kubeconfig ..., затем удалите именно этот кластер. Критерий приёмки: команды и коды завершения записаны; ни один другой кластер kind не исчез.

Намеренно сломанный сценарий

Измените последний символ digest и выполните создание под именем kube-course-broken. Ожидается ошибка загрузки или проверки образа, а кластер не станет готовым. Не исправляйте проблему повторными перезапусками. Сравните:

kind create cluster --name kube-course-broken \
  --image kindest/node:v1.36.1@sha256:3489c7674813ba5d8b1a9977baea8a6e553784dab7b84759d1014dbd78f7ebd0
kind get clusters
docker ps -a --filter name=kube-course-broken

Восстановление: kind delete cluster --name kube-course-broken, затем точный digest из примечаний к выпуску.

Дерево диагностических решений

Команда не найдена?
├─ да → PATH, бит выполнения, архитектура, контрольная сумма
└─ нет → среда контейнеров отвечает?
   ├─ нет → права на фоновый процесс/сокет/режим без root; kind ещё не виноват
   └─ да → создание кластера kind завершилось ошибкой?
      ├─ загрузка образа → DNS/прокси/диск/digest; изучите журналы среды
      ├─ начальная загрузка → kind --retain, kind export logs, журнал узла
      └─ успех, но kubectl завершается ошибкой
         ├─ неверный контекст → current-context/get-contexts
         ├─ отказ в соединении → журналы контейнера узла/сервера API
         └─ forbidden → идентификация/RBAC, а не повтор сетевого запроса

Типичные ошибки: плавающий тег образа узла, смешивание контекстов, sudo kubectl, создающий kubeconfig с владельцем root, проверка контрольной суммы без --check, ожидание NetworkPolicy от CNI без механизма политик, вывод всего kubeconfig в заявку.

Эксплуатационные компромиссы, безопасность и стоимость

kind — не дистрибутив для промышленной эксплуатации: узлы совместно используют ядро и хост провайдера, хранилище локально, а интеграции с облаком отсутствуют. Многоузловая конфигурация полезна для понимания scheduler, но не моделирует независимые зоны отказа. Лаборатория из трёх узлов потребляет больше RAM и диска; удаляйте кластер после работы. Фиксация digest снижает неопределённость цепочки поставки. Kubeconfig содержит клиентские учётные данные: задайте режим 0600 и не сохраняйте файл в Git. Не монтируйте kubeconfig из промышленного кластера в контейнер лаборатории.

Самопроверка

  1. Почему kubectl version --client не доказывает доступность кластера?
  2. Чем клиентский dry-run слабее серверного?
  3. Почему тег вместе с digest лучше одного тега?
  4. Где проходит граница между kind и Kubernetes?
  5. Как исключить изменение промышленного кластера?

Ответы: 1) вызов API не выполнен; 2) нет серверной схемы, admission, авторизации и назначения значений по умолчанию; 3) digest фиксирует байты; 4) kind управляет локальными контейнерами узлов, Kubernetes — объектами API и рабочими нагрузками; 5) точная проверка контекста, namespace и серверный diff/dry-run.

Резюме и источники

У вас должен быть воспроизводимый kind-kube-course, закреплённые версии инструментов и образа, а также трёхуровневая модель проверки. Далее — архитектура и API.