Как создать под в Kubernetes: kubectl run и YAML-манифест с примерами | AdminWiki

Как создать под в Kubernetes: kubectl run и YAML-манифест с примерами

03 октября 2026 11 мин. чтения

Что такое под в Kubernetes и зачем его создавать

Под - минимальная единица развёртывания в Kubernetes: один или несколько контейнеров с общим сетевым пространством и общими томами. Контейнеры внутри пода видят друг друга на localhost, делят один IP и один жизненный цикл. Под не равен контейнеру: это обёртка, которая добавляет к контейнерам сеть, хранилище и правила перезапуска.

Создать под можно двумя способами. Императивный: строка в терминале с командой kubectl run. Декларативный: YAML-манифест, который применяется через kubectl apply -f. Первый способ экономит время при отладке, второй даёт воспроизводимый файл для Git и повторных запусков.

Kubernetes умеет выражать, запрашивать, выделять и ограничивать ресурсы рабочих нагрузок, включая специальные аппаратные устройства. Это поведение описано в документации Kubernetes по управлению ресурсами и раскрывается через requests и limits в спецификации контейнера.

Голый под не перезапускается после падения узла, не обновляется при смене образа и не масштабируется. В продакшене подами управляют контроллеры: Deployment, StatefulSet, DaemonSet, Job. Ниже разбираем оба способа создания пода по шагам и показываем переход к контроллерам.

Быстрый старт: создание пода командой kubectl run

Одна строка создаёт под с Nginx:

kubectl run nginx-demo --image=nginx:1.27 --port=80

kubectl загружает образ nginx:1.27, создаёт объект в текущем namespace и запускает контейнер. Флаг --port задаёт порт, который контейнер должен открыть: например, kubectl run hazelcast --image=hazelcast/hazelcast --port=5701. Этот же флаг требуется, если вы создаёте ассоциированный с подом ClusterIP-сервис через --expose.

Если нужен одноразовый под без контроллера, добавьте --restart=Never:

kubectl run nginx-demo --image=nginx:1.27 --port=80 --restart=Never

Флаг --restart влияет на тип создаваемого объекта. С --restart=Never создаётся под, который не перезапускается при выходе процесса: например, kubectl run -i -t busybox --image=busybox --restart=Never. Без этого флага kubectl run запускает развёртывание (Deployment) для контейнера, поэтому процесс будет перезапускаться при завершении, в отличие от запуска голого пода. Для отладки и разовых задач выбирайте Never, иначе удалённый под будет создан контроллером заново.

Проверить, что под появился:

kubectl get pods
kubectl get pod nginx-demo -o wide

Флаг -o wide добавляет IP пода и имя узла. Это первое, что стоит смотреть при разборе сетевых проблем. Для первого знакомства с кластером поднимите локальную среду: гайд по запуску сервисов в Kubernetes с минимальной конфигурацией описывает установку minikube и первый деплой.

Полезные флаги kubectl run

ФлагНазначениеПример
--imageОбраз контейнера, без него запуск невозможен--image=nginx:1.27
--portПорт, который контейнер должен открыть--port=80
--envПеременная окружения, флаг повторяемый--env="TZ=UTC"
--labelsМетки пода для селекторов--labels=app=nginx,tier=frontend
--restartNever создаёт под без перезапуска; без флага создаётся Deployment--restart=Never
--dry-run=client -o yamlПечатает манифест вместо создания объектаkubectl run nginx-demo --image=nginx:1.27 --dry-run=client -o yaml
--rm -itУдаляет под после выхода из контейнера--rm -it -- sh

Пример пода-утилиты, который живёт час и ничего не делает:

kubectl run debug --image=busybox --restart=Never -- sleep 3600

Двойной дефис отделяет аргументы контейнера от флагов kubectl. Без него kubectl попытается разобрать sleep как свой параметр и вернёт ошибку.

Флаги покрывают базовые сценарии: образ, порт, переменные окружения, метки. Задать requests и limits, тома, probes или несколько контейнеров в одном поде командой kubectl run не выйдет. Как только понадобился хотя бы один из этих параметров, переходите к манифесту.

Как проверить, что под запустился

kubectl get pods -w
kubectl describe pod nginx-demo
kubectl logs nginx-demo
kubectl exec -it nginx-demo -- sh
kubectl get pod nginx-demo -o yaml

Флаг -w держит вывод открытым и показывает смену статусов: Pending, ContainerCreating, Running. Секция Events в kubectl describe pod объясняет задержки и сбои: нехватку ресурсов на узле, неудачную загрузку образа, падение контейнера.

kubectl logs отдаёт stdout контейнера, kubectl exec открывает shell внутри пода. Вывод kubectl get pod -o yaml стоит сравнить с манифестом: там видно фактическое состояние, а не желаемое.

Удалить под: kubectl delete pod nginx-demo. Если объектом управляет контроллер, под вернётся, и удалять нужно сам контроллер.

Декларативный способ: YAML-манифест пода

Манифест описывает желаемое состояние, а kubectl приводит кластер к нему. Готовый файл pod.yaml:

apiVersion: v1          # версия API для Pod
kind: Pod               # тип объекта
metadata:
  name: nginx-demo      # имя пода, обязательно
  labels:
    app: nginx          # метка для селекторов Service и Deployment
    tier: frontend
spec:
  restartPolicy: Always # Always | OnFailure | Never
  containers:
    - name: nginx             # имя контейнера, обязательно
      image: nginx:1.27       # образ, обязательно
      ports:
        - containerPort: 80   # порт, который слушает контейнер
          name: http          # имя порта для Service
      resources:
        requests:
          cpu: 100m
          memory: 128Mi
        limits:
          cpu: 500m
          memory: 256Mi
      env:
        - name: TZ
          value: "UTC"

Отступы делайте пробелами, табы в YAML запрещены. Подробный разбор структуры apiVersion, kind, metadata и spec с другими примерами собран в гайде по структуре манифестов Kubernetes.

Обязательные и опциональные поля спецификации

ПолеОбязательностьКомментарий
apiVersionобязательноДля пода значение v1
kindобязательноPod
metadata.nameобязательноУникальное имя пода в namespace
metadata.labelsопциональноНужны для селекторов Service и Deployment
spec.containersобязательноСписок, минимум один контейнер
spec.containers[].nameобязательноИмя контейнера внутри пода
spec.containers[].imageобязательноОбраз с реестром и тегом
spec.containers[].portsопциональноДекларация портов, ничего не открывает
spec.containers[].resourcesопционально, но рекомендуетсяrequests и limits для планировщика
spec.restartPolicyопциональноПо умолчанию Always

Уберите metadata.name или spec.containers, и kubectl apply вернёт ошибку валидации, ничего не создав. Опечатка в имени поля обрабатывается мягче: при включённой на API-сервере серверной валидации полей режим warn предупреждает о неизвестных или дублирующихся полях, не блокируя запрос. Предупреждение приходит через стандартный warning-заголовок для каждого неизвестного поля, отброшенного из объекта, и для каждого встреченного дублирующегося поля. Если серверная валидация полей на API-сервере не включена, режим warn ведёт себя как ignore. Проверить файл до применения можно так:

kubectl apply -f pod.yaml --dry-run=server

Режим --dry-run=server прогоняет манифест через API-сервер без создания объекта. Ошибки в отступах и лишние поля всплывут здесь, а не в рабочем кластере.

resources: requests и limits на практике

requests - гарантированный минимум, который планировщик резервирует под контейнер. limits - потолок потребления. В примере выше контейнер просит 100m CPU и 128Mi памяти, а получить может до 500m CPU и 256Mi.

Что происходит при превышении. CPU сжимаемый ресурс: контейнер упирается в limit и начинает тормозить из-за throttling. Память несжимаема: выход за limit приводит к OOMKill и перезапуску контейнера. Отсюда правило: requests задавайте всегда, limits ставьте по замерам нагрузки, а не наугад.

Kubernetes присваивает каждому поду один из QoS-классов - Guaranteed, Burstable или BestEffort - на основе resource requests и limits его контейнеров. От класса зависит порядок вытеснения при нехватке ресурсов на узле.

QoS-классУсловиеПорядок вытеснения
Guaranteedу каждого контейнера пода есть и memory limit, и memory request (а также CPU request и limit)вытесняется последним
Burstablerequests меньше limits или заданы не для всех ресурсовсредний приоритет
BestEffortу контейнеров нет ни memory, ни CPU limits или requestsвытесняется первым

Когда узел исчерпывает ресурсы, Kubernetes сначала вытесняет поды BestEffort, затем Burstable и в последнюю очередь Guaranteed. Без limits под попадает в BestEffort и первым уходит под eviction, когда узлу не хватает памяти. Сводка механизмов выделения и ограничения ресурсов, включая специальные устройства вроде GPU, собрана в разделе документации по управлению ресурсами.

ports и сетевые настройки в манифесте

Секция ports ничего не открывает. Это декларация: какой порт слушает контейнер. Kubernetes использует её для читаемости, а Service - для ссылки на именованный порт, например http.

ports:
  - containerPort: 80
    name: http
    protocol: TCP

containerPort обязателен внутри элемента списка. name нужен, если Service ссылается на порт по имени, а не по номеру. protocol по умолчанию TCP.

Под сам по себе недоступен извне кластера. Чтобы связать приложение с другими подами или вывести его наружу, создайте Service:

kubectl expose pod nginx-demo --port=80

Применение манифеста и проверка результата

kubectl apply -f pod.yaml
kubectl get pods
kubectl get pod nginx-demo -o wide
kubectl describe pod nginx-demo
kubectl logs nginx-demo
kubectl exec -it nginx-demo -- sh
kubectl get pod nginx-demo -o yaml

kubectl apply идемпотентна: повторный запуск с тем же файлом ничего не меняет, если объект уже соответствует манифесту. Первая команда отвечает pod/nginx-demo created. Дальше смотрите на столбцы STATUS и READY: Running вместе с 1/1 означает, что контейнеры запущены и проверки пройдены.

Удаление выполняется тем же файлом: kubectl delete -f pod.yaml. Так вы удалите ровно тот объект, который описан в манифесте, и не заденете соседние ресурсы.

Типичные ошибки и как их диагностировать

СимптомПричинаКоманда диагностики
ImagePullBackOff, ErrImagePullОпечатка в имени образа, нет доступа к реестру, не задан imagePullSecretkubectl describe pod nginx-demo, секция Events
CrashLoopBackOffПроцесс в контейнере завершается с ошибкой сразу после стартаkubectl logs nginx-demo и kubectl logs nginx-demo --previous
PendingПланировщик не нашёл узел: мало CPU или памяти, не сходятся nodeSelector и taintskubectl describe pod nginx-demo, kubectl get nodes
Ошибка разбора YAMLТабы вместо пробелов, сбитые отступы, лишний символkubectl apply -f pod.yaml --dry-run=server
Предупреждение unknown fieldОпечатка в имени поля или неверный apiVersionТекст предупреждения в выводе kubectl apply

Общую картину по namespace даёт список событий, отсортированный по времени:

kubectl get events --sort-by=.lastTimestamp

Свежие записи внизу. Причины FailedScheduling и FailedMount обычно указаны прямо в тексте события, без похода в документацию.

kubectl run или YAML-манифест: что выбрать

Критерийkubectl runYAML-манифест
Скоростьодна команда в терминалефайл плюс kubectl apply
Воспроизводимостьнет, команда живёт в истории shellесть, результат одинаков при каждом запуске
Хранение в Gitнеудобноестественно, с ревью и историей правок
Идемпотентностьповторный запуск создаст новый объект или вернёт ошибкуapply повторяем и приводит состояние к описанному
Полнота параметровобраз, порт, env, метки, restartлюбые поля PodSpec: resources, volumes, probes, tolerations
GitOps и CI/CDне подходитоснова пайплайна

Переходный приём: получите манифест из команды и отредактируйте его. Флаг --dry-run=client печатает соответствующие API-объекты без их создания, а комбинация --dry-run=client -o yaml позволяет сгенерировать спецификацию пода и записать её в файл. Дальше остаётся добавить resources и ports.

kubectl run nginx-demo --image=nginx:1.27 --port=80 --dry-run=client -o yaml > pod.yaml

Для всего, что живёт дольше отладочной сессии, берите манифест. Как встроить такие файлы в повторяемый пайплайн с параметризацией тега образа и проверкой rollout, показывает скрипт развёртывания приложения в Kubernetes.

Почему в продакшене поды не создают напрямую

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

Контроллеры закрывают эти пробелы. Deployment отвечает за stateless-приложения: держит заданное число реплик, делает rolling update и откат. StatefulSet даёт подам устойчивые имена и порядок запуска, что нужно базам данных и очередям. DaemonSet запускает по одному поду на каждом узле, его типичная задача - сбор метрик и логов. Job доводит задачу до завершения и не перезапускает её бесконечно. Сравнение этих объектов с примерами манифестов для Nginx, Redis и Node Exporter разобрано в материале о выборе контроллера Kubernetes.

Под остаётся строительным блоком: контроллер создаёт те же поды, только по шаблону и под своим присмотром. Самовосстановление, обновление без простоя и масштабирование берёт на себя контроллер.

Когда голый под всё-таки уместен

Прямое создание пода оправдано в четырёх случаях: отладка, разовая проверка образа, диагностика сети изнутри кластера, запуск утилиты. Пример пода с сетевыми инструментами:

kubectl run netcheck --image=nicolaka/netshoot --restart=Never -- sleep 3600

Внутри такого пода доступны dig, curl, tcpdump и traceroute. Под живёт до удаления, в Git не попадает и после проверки убирается командой kubectl delete pod netcheck.

Переход от Pod к Deployment

Быстрый путь для проверки идеи:

kubectl create deployment nginx --image=nginx:1.27 --replicas=3
kubectl get deployments
kubectl get pods -l app=nginx

Для постоянной работы перепишите pod.yaml в deployment.yaml: замените kind на Deployment, apiVersion на apps/v1, добавьте spec.replicas и spec.selector.matchLabels, а шаблон пода перенесите в spec.template.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

Метки пода в spec.template.metadata.labels обязаны совпадать с selector.matchLabels, иначе контроллер не свяжет поды с Deployment. Применение и проверка:

kubectl apply -f deployment.yaml
kubectl rollout status deployment/nginx
kubectl get pods -l app=nginx

Готовые манифесты с RollingUpdate, livenessProbe, readinessProbe и откатом релиза смотрите в руководстве по Kubernetes Deployment.

Чек-лист: создание пода от команды до продакшена

  1. Для отладки и разовых задач используйте kubectl run с флагом --restart=Never.
  2. Для повторяемого создания пишите манифест с обязательными полями metadata.name, spec.containers, container name и image.
  3. Задайте resources.requests всегда, limits - по результатам замеров.
  4. Опишите ports.containerPort и дайте порту имя, если на него будет ссылаться Service.
  5. Проверьте файл через kubectl apply -f pod.yaml --dry-run=server.
  6. Примените манифест и убедитесь в статусе Running и READY 1/1.
  7. При сбое смотрите kubectl describe pod, секцию Events, и kubectl logs.
  8. Для продакшена оберните описание пода в Deployment, StatefulSet, DaemonSet или Job.
  9. Храните манифесты в Git и применяйте их через CI/CD, а не руками с ноутбука.

Начните с копирования pod.yaml из раздела про манифест, примените его в тестовом namespace и доведите до Running. Дальше перенесите спецификацию контейнера в шаблон Deployment: это тот же YAML, но под управлением контроллера, который сам вернёт упавшую реплику и проведёт обновление образа.

Поделиться: