Kubernetes YAML — минимальные манифесты
Для кого эта статья
Если вы гуглите kubernetes yaml example, deployment yaml nginx, kubectl apply example, service yaml clusterip или минимальный манифест k8s — здесь готовые файлы с разбором каждой строки, как в галерее Turtle для Python и Docker Compose для стеков контейнеров.
Подойдёт, если вы:
- проходите лабораторную по DevOps, облакам или микросервисам;
- уже поднимали стек через Compose и хотите тот же сценарий в кластере;
- учитесь читать манифесты перед курсом по Kubernetes или справочнику.
Kubernetes описывает желаемое состояние кластера в YAML (или JSON): какие контейнеры запустить, сколько копий, как к ним ходить по сети, где хранить настройки.
Архитектура кластера, Pod, Service, Ingress — Docker Swarm и Kubernetes. Установка Docker Desktop и включение Kubernetes — первые шаги. Локальные стеки без оркестратора — Docker Compose — готовые стеки. Синтаксис YAML (отступы, списки) — глава про YAML.
Демо выше проверяет отступы и синтаксис YAML — те же правила, что и в манифестах ниже. В пресетах — Docker Compose и Kubernetes Deployment; полные стеки — в блоках ниже.
Три слова — объект, 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:
# В Deployment
spec:
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
# В Service
spec:
selector:
app: web
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: 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
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
Разбор по строкам:
| Строка | Смысл |
|---|---|
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
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-cm
spec:
replicas: 1
selector:
matchLabels:
app: web-cm
template:
metadata:
labels:
app: web-cm
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
env:
- name: APP_MODE
valueFrom:
configMapKeyRef:
name: web-config
key: APP_MODE
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap:
name: web-config
items:
- key: index.html
path: index.html
Разбор по строкам:
| Строка | Смысл |
|---|---|
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 для пароля БД.
apiVersion: v1
kind: Secret
metadata:
name: pg-secret
type: Opaque
stringData:
POSTGRES_PASSWORD: dev-only-change-me
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: pg-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_DB
value: appdb
---
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: hashicorp/http-echo:0.2.3
args: ["-text=ok", "-listen=:8080"]
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: postgres
- name: DB_PORT
value: "5432"
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- port: 80
targetPort: 8080
Разбор ключевых идей:
| Фрагмент | Смысл |
|---|---|
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
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
spec:
ingressClassName: nginx
rules:
- host: demo.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
Разбор:
| Строка | Смысл |
|---|---|
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 — проверки здоровья
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 5
| Проба | Смысл |
|---|---|
livenessProbe | Pod «завис» — kubelet перезапустит контейнер |
readinessProbe | Pod ещё не готов — Service не шлёт трафик |
initialDelaySeconds | Пауза после старта (nginx успевает подняться) |
Тот же приём, что healthcheck в Compose.
Один файл — полный минимальный сайт
Deployment + Service NodePort в одном манифесте (удобно для сдачи лабораторной):
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
replicas: 2
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
type: NodePort
selector:
app: hello
ports:
- port: 80
targetPort: 80
nodePort: 30081
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 |
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Практическая карта типовых IT-задач: термины, пошаговое внедрение, проверка качества и типичные ошибки. Простой консольный чат на C# — учебное приложение с сокетами: TCP между клиентом и сервером, многопоточность и обмен сообщениями в консоли. Примеры вёрстки на HTML и CSS с разбором: центрирование, Flexbox, Grid, формы, шапка, подвал и адаптив для учебы и портфолио. Перед началом работы обязательно изучите главу Turtle . Галерея 3D-фигур на Panda3D — карточки, куб, пирамида, сфера, сетки и составные сцены; код для локального запуска. Готовые docker-compose.yml с разбором каждой строки — nginx, PostgreSQL, Redis, WordPress, MongoDB. Примеры для школьников и студентов: postgres example, поднять базу локально, app + db. Примеры nginx.conf для статики, reverse proxy, React/Vue SPA, PHP, SSL и балансировки — построчный разбор директив, проверка curl и типичные ошибки для лабораторных и VPS. dockerfile example — 10 готовых Dockerfile с построчным разбором: node, python, golang, react nginx, spring boot, php, dotnet. Для студентов, лабораторных и docker build с нуля. PromQL example — готовые запросы Prometheus и Grafana с построчным разбором: up, rate, node_exporter cpu, memory, disk, http_requests_total, histogram_quantile p99, алерты. Для студентов, лабораторных и devops docker compose. Примеры графиков Matplotlib на Python для школьников и студентов — sin, cos, парабола, столбцы, scatter, гистограмма, подграфики; код с подробным разбором. Примеры pandas на Python для школьников и студентов — DataFrame, фильтрация, groupby, очистка, merge, сводные таблицы и экспорт; код с подробным разбором каждой строки. p5.js и Processing — готовый код фигур с подробным разбором каждой строки: квадрат, треугольник, цветок, снежинка, фракталы, анимация; для школьников и студентов.Готовые решения
Простой консольный чат на CSharp
HTML + CSS — готовые макеты
Примеры фигур Turtle на Python
Примеры фигур Panda3D на Python
Docker Compose — готовые стеки
Nginx — конфиги под задачу
Dockerfile — 10 типовых образов
Prometheus + Grafana — запросы
Matplotlib — графики
Pandas — типовые операции
Примеры фигур на Processing/p5.js