Kubernetes YAML — минимальные манифесты

Приветствую! Здесь вы наверняка найдете, что ищете. Примеры в лаборатории рассчитаны на то, что мы разбираем что-то конкретное.

Текущая статья посвящена минимальным манифестам Kubernetes — Deployment, Service, Ingress.

Поэтому за теорией по текущей теме вам — в энциклопедию. Если ещё не погружались, то маршрут прост:

  1. Основы
  2. Система и сеть
  3. Данные и разметка
  4. Код и разработка
  5. Языки
  6. Искусственный интеллект
  7. Проект
  8. Инфраструктура и безопасность
  9. Спин-офф

Обязательно пройдитесь.

А теперь приступим к нашему предмету.

Теория и соседние материалы

Архитектура кластера, Pod, Service, Ingress — Docker Swarm и Kubernetes.

Установка Docker Desktop и включение Kubernetes — первые шаги.

Локальные стеки без оркестратора — Docker Compose — готовые стеки.

Синтаксис YAML (отступы, списки) — глава про YAML.


Три слова — объект, Pod, контроллер

Термин Простыми словами Аналогия с Compose
Объект (resource) Запись в API кластера (Pod, Service, …) Сервис или volume в compose.yaml
Pod Один или несколько контейнеров, которые кластер запускает вместе на одной ноде Один контейнер (или связка sidecar)
Deployment «Держатель» подов: число копий, обновление образа deploy.replicas + политика перезапуска
Service Стабильный DNS и IP для набора подов Имя сервиса db, web в сети compose
Namespace Виртуальная «папка» объектов в кластере Имя проекта compose (изоляция)
Manifest YAML-файл с apiVersion, kind, metadata, spec Файл compose.yaml
  kubectl apply -f app.yaml
         │
         ▼
  API-сервер Kubernetes  ──►  Scheduler ставит Pod на ноду
         │
         ▼
  Service (ClusterIP)  ──►  другие поды ходят по имени my-app:80

Запомните: внутри кластера приложение к базе подключается по имени Service (postgres), как db в Compose. localhost внутри пода — это сам Pod, а не соседний сервис.


Структура манифеста

Поле Смысл
apiVersion Версия API (например v1 для Pod, apps/v1 для Deployment)
kind Тип объекта: Pod, Deployment, Service, …
metadata.name Имя в namespace; по нему же часто строится DNS
metadata.labels Метки для выбора объектов (связь Service ↔ Pod)
metadata.namespace Namespace (если не указан — default)
spec Желаемое состояние — образ, порты, реплики, …

Связка Deployment → Pod и Service → Pod строится через одинаковые labels:

Service направляет трафик на все поды с меткой app: web.


Порядок действий

  1. Установите kubectl и локальный кластер: Minikube, kind, или Kubernetes в Docker Desktop (Settings → Kubernetes → Enable).
  2. Создайте папку, например k8s-demo/.
  3. Сохраните блок YAML в файл (pod-nginx.yaml, app.yaml, …). Несколько объектов в одном файле разделяют строкой ---.
  4. В терминале в этой папке:
kubectl cluster-info
kubectl apply -f pod-nginx.yaml
kubectl get pods
kubectl get svc

Разбор команд:

Команда Что делает
kubectl cluster-info Проверяет, что kubectl видит кластер
kubectl apply -f файл.yaml Создаёт или обновляет объекты из манифеста
kubectl get pods Список подов и статус (Running, CrashLoopBackOff, …)
kubectl describe pod имя События, причина ImagePullBackOff, лимиты
kubectl logs имя-pod Логи контейнера
kubectl delete -f файл.yaml Удаляет объекты, описанные в файле
  1. Для доступа с ПК к Service типа ClusterIP используйте NodePort, port-forward или Ingress (см. примеры ниже).
Minikube и Docker Desktop
Minikube: minikube start, затем minikube kubectl -- get pods или настройте alias kubectl.
Docker Desktop: включите Kubernetes в настройках, дождитесь зелёного статуса — context docker-desktop появится в kubectl config get-contexts.
Секреты в примерах

Пароли вроде `secret` и base64 в учебных манифестах — только для локального кластера.

В Git коммитьте ConfigMap без паролей; секреты — через Sealed Secrets, External Secrets или CI variables.


Обязательный каркас Pod

Любой пример ниже опирается на этот минимум:

apiVersion: v1
kind: Pod
metadata:
  name: minimal
spec:
  containers:
    - name: app
      image: alpine:3.20
      command: ["sleep", "infinity"]
Фрагмент Смысл
apiVersion: v1 Стабильное Core API для Pod
kind: Pod Тип объекта
metadata.name Имя Pod в текущем namespace
spec.containers Список контейнеров (минимум один)
name: app Имя контейнера внутри Pod (для kubectl logs app)
image: Образ из registry
command: Переопределяет CMD образа

Проверка до apply (сухой прогон клиента):

kubectl apply -f minimal-pod.yaml --dry-run=client

Стартовые манифесты

Пять конфигураций — от одного Pod до связки Deployment + Service.

Как устроен каждый пример ниже
Задача — что вы получите и цель
YAML — готовый файл для копирования.
Разбор по строкам — таблица «что означает каждая строка».
Проверка — команды kubectl, чтобы убедиться, что объект жив.

Так же устроены Docker Compose и curl / fetch.


1. Один Pod с nginx

Задача: убедиться, что кластер и kubectl apply работают. kubernetes pod nginx yaml example.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.27-alpine
      ports:
        - containerPort: 80

Разбор по строкам:

Строка Смысл
kind: Pod Запускается один Pod без автоматического пересоздания при сбое (для прода обычно Deployment)
labels: app: nginx Метка для будущего Service
image: nginx:1.27-alpine Тот же образ, что в Compose №1
containerPort: 80 Порт внутри контейнера; снаружи кластера сам по себе не открыт

Проверка:

kubectl apply -f nginx-pod.yaml
kubectl get pod nginx-pod
kubectl port-forward pod/nginx-pod 8080:80

Откройте http://localhost:8080 — страница nginx. Остановка: Ctrl+C у port-forward, затем kubectl delete pod nginx-pod.

Команда Смысл
port-forward pod/… 8080:80 Туннель с вашего ПК на порт 80 контейнера
delete pod Pod исчезает; Deployment бы пересоздал копию

2. Deployment — три копии приложения

Задача: масштабирование и самовосстановление. Запрос: kubernetes deployment yaml replicas.

Разбор по строкам:

Строка Смысл
apiVersion: apps/v1 API группы apps для Deployment
replicas: 3 Кластер держит три пода с этим шаблоном
selector.matchLabels Deployment управляет подами с меткой app: web
template Шаблон Pod — те же поля, что в примере №1
template.metadata.labels Должны совпадать с matchLabels

Проверка:

kubectl apply -f web-deployment.yaml
kubectl get deployment web
kubectl get pods -l app=web

Удалите один Pod — Deployment создаст новый:

kubectl delete pod -l app=web --field-selector=status.phase=Running --wait=false
kubectl get pods -l app=web

3. Service ClusterIP — доступ внутри кластера

Задача: стабильное имя web для других подов. Запрос: kubernetes service clusterip yaml.

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

Разбор по строкам:

Строка Смысл
type: ClusterIP IP только внутри кластера (по умолчанию, можно не писать)
selector.app: web Трафик на поды с меткой app: web (из Deployment выше)
port: 80 Порт Service (куда стучатся клиенты)
targetPort: 80 Порт контейнера (containerPort)

Проверка (нужен запущенный Deployment из примера №2):

kubectl apply -f web-service.yaml
kubectl get svc web
kubectl run curl-test --rm -it --image=curlimages/curl --restart=Never -- curl -s http://web

Внутри временного Pod команда curl http://web обращается к Service по DNS.


4. Service NodePort — доступ с вашего ПК

Задача: открыть приложение на localhost без port-forward. Запрос: kubernetes nodeport yaml example.

apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080

Разбор по строкам:

Строка Смысл
type: NodePort Проброс порта на каждую ноду кластера
nodePort: 30080 Порт на ноде (диапазон обычно 30000–32767)
port / targetPort Как в ClusterIP — маппинг Service → контейнер

Проверка:

kubectl apply -f web-nodeport.yaml
minikube service web-nodeport --url

На Minikube команда выведет URL. На Docker Desktop часто работает http://localhost:30080.


5. ConfigMap — настройки без пересборки образа

Задача: передать конфиг-файл или переменные. Запрос: kubernetes configmap yaml example.

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-config
data:
  APP_MODE: "development"
  index.html: |
    Hello from ConfigMap

Разбор по строкам:

Строка Смысл
data.APP_MODE Ключ → переменная окружения
data.index.html Многострочное значение — файл в volume
env.valueFrom.configMapKeyRef Подставить значение ключа в env
volumes.configMap Смонтировать ключи как файлы
items.key / path Какой ключ ConfigMap стать каким файлом в каталоге

Проверка:

kubectl apply -f web-configmap.yaml
kubectl get configmap web-config
kubectl logs deployment/web-cm
kubectl port-forward deployment/web-cm 8080:80

Страница на localhost:8080 покажет заголовок из ConfigMap.


Связка «приложение + база»

Классический учебный стек — API (или заглушка) и PostgreSQL. Аналог Compose app + db.

Задача: два Deployment, два Service, Secret для пароля БД.

Разбор ключевых идей:

Фрагмент Смысл
stringData в Secret Кластер сам кодирует в base64; удобнее для учебных файлов
secretKeyRef Пароль не в открытом виде в Deployment
Service name: postgres DNS-имя postgres в namespace
DB_HOST: postgres То же правило, что DB_HOST=db в Compose
hashicorp/http-echo Минимальный HTTP-ответ без своего Dockerfile
--- между документами Один файл — несколько объектов за один apply

Проверка:

kubectl apply -f stack-app-db.yaml
kubectl get pods
kubectl get svc
kubectl port-forward svc/api 8080:80
curl -s http://localhost:8080

Проверка DNS до БД:

kubectl get endpoints postgres

Дополнительные объекты

Namespace — отдельная «песочница»

apiVersion: v1
kind: Namespace
metadata:
  name: lab
kubectl apply -f namespace-lab.yaml
kubectl apply -f web-deployment.yaml -n lab
kubectl get pods -n lab

Secret (тип Opaque) — отдельно от Deployment

apiVersion: v1
kind: Secret
metadata:
  name: api-token
type: Opaque
data:
  TOKEN: dGVzdC10b2tlbg==
Строка Смысл
data.TOKEN Значение уже в base64 (test-tokendGVzdC10b2tlbg==)
stringData Альтернатива — писать текстом, кластер закодирует сам

Подключение в Pod:

env:
  - name: API_TOKEN
    valueFrom:
      secretKeyRef:
        name: api-token
        key: TOKEN

Ingress — HTTP снаружи (нужен Ingress Controller)

Задача: один входной URL для нескольких Service. На Minikube:

minikube addons enable ingress

Разбор:

Строка Смысл
ingressClassName: nginx Какой контроллер обрабатывает Ingress (в Minikube addon — nginx)
host: demo.local Имя в HTTP-заголовке Host
backend.service.name Имя существующего Service
pathType: Prefix Путь / и всё под ним

Добавьте в hosts файл на ПК: 127.0.0.1 demo.local (для Minikube IP возьмите minikube ip).


Liveness и readiness — проверки здоровья

Проба Смысл
livenessProbe Pod «завис» — kubelet перезапустит контейнер
readinessProbe Pod ещё не готов — Service не шлёт трафик
initialDelaySeconds Пауза после старта (nginx успевает подняться)

Тот же приём, что healthcheck в Compose.


Один файл — полный минимальный сайт

Deployment + Service NodePort в одном манифесте (удобно для сдачи лабораторной):

kubectl apply -f hello-all-in-one.yaml
kubectl get all -l app=hello

Частые ошибки — симптом и лечение

Симптом Частая причина Что сделать
connection refused к localhost из другого Pod Обращение к себе, а не к Service DB_HOST=postgres, имя Service
ImagePullBackOff Нет сети / опечатка в image: kubectl describe pod → Events
CreateContainerConfigError Secret/ConfigMap не найден kubectl get secret, имя и ключ
Service есть, endpoints пустые Labels не совпадают Сравнить selector Service и labels Pod
Forbidden при apply Нет прав RBAC Учебный кластер — context admin; в проде — RoleBinding
Ingress 404 Нет controller или неверный host kubectl get ingress, включить addon
YAML «ломается» при apply Табы вместо пробелов 2 пробела на уровень; демо YAML
Как читать Pending / CrashLoopBackOff
kubectl describe pod имя → блок Events снизу. Там причина: нехватка памяти на ноде, неверный монтирование volume, падение команды в контейнере. Логи — kubectl logs имя и при перезапусках kubectl logs имя --previous.

Шпаргалка — что вставить в отчёт по лабораторной

В кластере Kubernetes развёрнуто приложение по декларативному описанию в YAML. Манифест Deployment задаёт образ контейнера и число реплик; объект Service обеспечивает стабильный сетевой доступ к подам по меткам labels. Команда kubectl apply -f применяет желаемое состояние; kubectl get pods,svc проверяет статус. Для доступа с рабочей станции использован NodePort / kubectl port-forward. Секреты вынесены в объект Secret, конфигурация — в ConfigMap.


Куда дальше

Задача Материал
Таблицы API, kubectl, архитектура Справочник по Kubernetes
Курс, Helm, прод-стек Реализация Kubernetes
Локально без k8s Docker Compose — стеки
CI с деплоем в кластер GitHub Actions — рецепты
Вопросы для самопроверки 200 вопросов по Kubernetes
Официальная документация Навигатор kubernetes.io