Kubernetes YAML — минимальные манифесты
Приветствую! Здесь вы наверняка найдете, что ищете. Примеры в лаборатории рассчитаны на то, что мы разбираем что-то конкретное.
Текущая статья посвящена минимальным манифестам Kubernetes — Deployment, Service, Ingress.
Поэтому за теорией по текущей теме вам — в энциклопедию. Если ещё не погружались, то маршрут прост:
- Основы
- Система и сеть
- Данные и разметка
- Код и разработка
- Языки
- Искусственный интеллект
- Проект
- Инфраструктура и безопасность
- Спин-офф
Обязательно пройдитесь.
А теперь приступим к нашему предмету.
Архитектура кластера, 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.
Порядок действий
- Установите kubectl и локальный кластер: Minikube, kind, или Kubernetes в Docker Desktop (Settings → Kubernetes → Enable).
- Создайте папку, например
k8s-demo/. - Сохраните блок YAML в файл (
pod-nginx.yaml,app.yaml, …). Несколько объектов в одном файле разделяют строкой---. - В терминале в этой папке:
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 |
Удаляет объекты, описанные в файле |
- Для доступа с ПК к Service типа ClusterIP используйте NodePort, port-forward или Ingress (см. примеры ниже).
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-token → dGVzdC10b2tlbg==) |
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 |
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 |