Перейти к содержанию

Локальный кластер и первый Pod API

После подготовки собственных образов перенесём API в локальную лабораторию. На этом этапе нужен один Pod: он позволяет увидеть объект Kubernetes без дополнительных контроллеров. Важный результат урока — различить кластер, выбранный контекст, наличие образа на узле и состояние контейнера. Если эти понятия смешать, одна ошибка загрузки образа легко превращается в длинное бесполезное изменение YAML.

Команды ниже читатель выполняет самостоятельно из examples/kubernetes-web-lab. Требуются заранее подготовленные Docker, kind 0.33.0 и kubectl ветки 1.37. Автор не устанавливал инструменты, не создавал ресурсы и не получал приведённые состояния. Локальная лаборатория не связана с производственным кластером и не предполагает облачный аккаунт.

Узел kind и выбранное окружение

Полный файл kind.yaml описывает один control-plane узел:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5

Этот образ опубликован в релизе kind 0.33.0. Digest фиксирует содержимое конкретного образа узла. Версия kind.x-k8s.io/v1alpha4 относится к формату конфигурации kind, а не к API приложений внутри Kubernetes. Поэтому слово alpha здесь не означает, что будущий Deployment использует экспериментальную схему.

Будущие команды создают именованную лабораторию и загружают ваши образы:

kind create cluster --name ploshchadka --config kind.yaml
kind load docker-image ploshchadka-api:1 ploshchadka-web:1 --name ploshchadka
kubectl --context kind-ploshchadka get nodes

Имя кластера kind ploshchadka образует контекст kind-ploshchadka в kubeconfig. Контекст связывает адрес API сервера с учётными данными. Параметр --context делает этот выбор видимым в каждой команде. Он полезен даже на компьютере с единственной лабораторией: читатель привыкает отделять намерение от текущего состояния терминала.

Загрузка образов — самостоятельный этап. Команда Docker build сохраняет образ в хранилище Docker вашего компьютера. kind load переносит его в runtime узлов kind. Если пропустить перенос, YAML останется синтаксически правильным, но контейнер не запустится. Никакой Service или дополнительный порт не устранит отсутствие исполняемого образа.

Namespace и самостоятельный Pod

Сначала применяем manifests/00-namespace.yaml, создающий namespace ploshchadka. Затем применяем 01-pod.yaml. Полный манифест Pod:

apiVersion: v1
kind: Pod
metadata:
  name: api-once
  namespace: ploshchadka
  labels:
    app: api-once
spec:
  containers:
    - name: api
      image: ploshchadka-api:1
      imagePullPolicy: Never
      ports:
        - containerPort: 3000

Имя объекта api-once задаёт адрес для команд управления. Метка app: api-once описывает принадлежность и позже позволит отличить этот учебный Pod от управляемых экземпляров API. Здесь метка намеренно не равна app: api: будущий Service не должен случайно захватить одиночную старую копию.

Политика Never означает: runtime должен использовать локально доступный образ и не пытаться скачать его. Для локальной лаборатории это делает ошибку явной. Если образ не загружен, Pod не получит нужную программу. В производственной системе обычно используют registry и другую политику; переносить Never туда без доступных образов на каждом узле нельзя.

Поле containerPort описывает порт контейнера, но не открывает его на ноутбуке. Сервер уже слушает 3000 благодаря своему исходному коду. Kubernetes не заставляет процесс слушать число из YAML. Если разработчик изменит Node-программу на другой порт, манифест и последующие сетевые объекты тоже должны согласованно измениться.

Чтение состояния вместо догадок

Создание узла может занять заметное время: нужно получить образ и запустить управляющие компоненты. Продолжительность зависит от сети и ресурсов компьютера. Поэтому инструкция не обещает готовый кластер «через несколько секунд». Если создание не завершилось, сначала читают сообщение kind, а не применяют приложение к неизвестному адресу.

Версия kubectl должна быть совместима с API сервера. В курсе выбираем ту же minor-ветку 1.37, чтобы не добавлять расхождение инструментов. Это не значит, что любое отличие всегда запрещено: у Kubernetes есть отдельная политика version skew. Для самостоятельной лаборатории одинаковая ветка делает объяснение API и диагностики проще.

После будущего применения полезно посмотреть объекты и подробности:

kubectl --context kind-ploshchadka apply -f manifests/00-namespace.yaml
kubectl --context kind-ploshchadka apply -f manifests/01-pod.yaml
kubectl --context kind-ploshchadka -n ploshchadka get pods
kubectl --context kind-ploshchadka -n ploshchadka describe pod api-once
kubectl --context kind-ploshchadka -n ploshchadka logs api-once

В исправном окружении ожидается переход Pod к Running; приложение пишет JSON-сообщение listening. Конкретные время, IP, имя узла и число перезапусков зависят от окружения. Эти значения не следует сравнивать с вымышленным «эталонным выводом». Смысл проверки — установить, что контейнер действительно создан и HTTP-процесс начал работу.

Если Pod остаётся Pending, ещё не обязательно виновато приложение. Размещение может ожидать ресурсы или другой обязательный элемент окружения. Если состояние связано с образом, смотрите Events и указанное имя. Если контейнер запускается и завершается, важны код завершения и журнал процесса. Название причины помогает выбрать слой диагностики, но само по себе не объясняет бизнес-проблему.

У приложения есть трёхсекундная задержка готовности. Сейчас Kubernetes ещё не настроен спрашивать /readyz, поэтому колонка готовности не отражает наш предметный смысл «можно принимать каталог». Это намеренная промежуточная стадия. Мы сначала наблюдаем процесс, а затем введём probes, чтобы состояние маршрутизации соответствовало состоянию программы.

Временное соединение с HTTP API

Kubeconfig содержит адрес управляющего API и данные доступа, а не каталог приложений или слои образов. Его сохранение не заменяет исходники и не восстанавливает удалённый кластер. Если лабораторию создать заново, нужно снова загрузить собственные образы и применить декларации в соответствующем порядке.

Перед повторным созданием полезно проверить, существует ли кластер с выбранным именем. Сообщение о существующем окружении не требуется обходить случайным новым именем: иначе файлы и команды начнут обращаться к разным лабораториям. Согласованное имя позволяет следующему уроку опираться на определённое состояние.

Для первого доступа используем локальную переадресацию:

kubectl --context kind-ploshchadka -n ploshchadka port-forward pod/api-once 3000:3000

Пока команда работает, читатель может открыть http://127.0.0.1:3000/api/lessons. После задержки инициализации ожидается JSON с каталогом и pod: "api-once". Если локальный порт занят другой программой, выберите свободный левый порт, например 13000:3000. Правая часть остаётся портом API внутри Pod.

Такое соединение привязано к выбранному экземпляру. Оно не моделирует обычный трафик Service и не делает API публичным сайтом. При удалении Pod соединение заканчивается. Эта особенность полезна именно сейчас: вы видите конкретный процесс и понимаете, почему постоянный доступ нельзя строить на случайном имени экземпляра.

В следующем уроке адресно удалим api-once и создадим Deployment, поддерживающий нужное число копий. Не применяйте сразу весь каталог manifests: он содержит последующие состояния и отдельные необязательные ветки. Порядок файлов в README показывает учебные зависимости, а не приглашает создавать неизвестные ресурсы одной общей командой.

Оглавление серии