логотип PurpleSchool
логотип PurpleSchool

Что нужно знать о Kubernetes Container

Автор

Олег Марков

Введение

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

Контейнеры — основная единица вычисления в Kubernetes. В этой статье объясню, как создаются и управляются контейнеры, какие опции предоставляет вам Kubernetes для контроля их жизненного цикла, ресурсов, среды выполнения, сетевых и дисковых опций. Вы увидите, как оформляются декларации контейнеров, какие параметры взаимодействуют друг с другом, и сможете углубиться в нюансы продвинутой настройки.

Что такое контейнеры в Kubernetes

Кратко о контейнерах

Контейнер — это изолированная среда, где запускается приложение. В Docker (а также других средах запуска, таких как containerd или cri-o) контейнеры представляют собой легковесные, воспроизводимые и изолированные процессы, включающие всё необходимое для выполнения: код приложения, библиотеки, переменные среды, конфиги.

Связь контейнера и Pod

В отличие от "голого Docker", в Kubernetes контейнер не создается "напрямую" — он всегда размещается внутри объекта Pod. Pod — это минимальная управляемая единица в Kubernetes, которая может содержать один или несколько контейнеров, разделяющих общую сетевую и, опционально, хранилищную среду.

Важное уточнение: В 99% случаев в каждом Pod используется один контейнер, но есть ситуации, когда несколько контейнеров запускаются вместе для решения одной задачи (паттерн Sidecar).

Образ контейнера

Любой контейнер создается из своего образа. В Kubernetes вы указываете путь к образу (Image), например:
nginx:1.19 или полный путь к приватному реестру.

Пример контейнера на базе Nginx: ```yaml containers:

  • name: my-nginx image: nginx:1.19 ``` Этот фрагмент будет частью спецификации Pod или Deployment.

Базовые параметры и поля контейнера

Чаще всего используемые секции

Рассмотрим базовые поля контейнера с пояснениями, чтобы понять, какие возможности вам доступны:

containers:
  - name: web-app # Имя контейнера
    image: my-app:1.2.3 # Образ контейнера
    ports:
      - containerPort: 8080 # Открываем порт внутри контейнера
    env: # Переменные окружения
      - name: ENVIRONMENT
        value: production
    resources: # Ресурсы
      limits:
        memory: "512Mi"
        cpu: "500m"
      requests:
        memory: "256Mi"
        cpu: "250m"
    volumeMounts:
      - name: logs-volume
        mountPath: /var/log/app # Точка монтирования тома

Теперь детальнее по отдельным полям.

Поле name

Имя контейнера должно быть уникальным внутри Pod. Оно помогает различать контейнеры в логах и событиях.

Поле image

Каждый контейнер создается на основе образа, например nginx:1.19 или собственного собранного image.

Поле ports

Здесь указывается список портов, которые слушает контейнер. Это важно для проброса трафика через Service.

env (переменные окружения)

Дают способ прокинуть параметры или секреты внутрь приложения через переменные окружения.

resources

Параметры requests/limits позволяют указывать сколько ресурсов этот контейнер должен запрашивать и какие лимиты нельзя превышать:

  • requests — гарантированный минимум ресурсов (CPU, память)
  • limits — максимальный предел, который контейнер может использовать

volumeMounts

Определяет какие тома будут доступны контейнеру и куда именно они будут примонтированы внутри файловой системы.

Как работает жизненный цикл контейнера в Kubernetes

Контейнеры проходят несколько стадий в своей жизни:

  1. Создание Pod: Когда в кластер поступает команда на создание Pod, начинается подготовка (выделение ресурсов, подготовка томов, создание сетевого namespace и пр.).
  2. Pull образа: Node, где будет запущен Pod, скачивает указанный образ, если его нет локально.
  3. Создание и запуск контейнера: После подтверждения, что всё подготовлено, запускается процесс, который является контейнером.
  4. Выполнение приложения: Контейнер работает до завершения основного процесса.
  5. Завершение: Если процесс падает — определяется дальнейшая стратегия (restartPolicy).

Поле restartPolicy

По умолчанию в Deployment это policy "Always": контейнеры будут перезапускаться при сбоях.

Пример для собственного Pod: yaml restartPolicy: OnFailure # или Never / Always

Probes: readiness, liveness, startup

Kubernetes отслеживает состояние контейнера через механизмы Probe:

  • Liveness Probe — проверяет, жив ли контейнер, и перезапускает его при сбоях
  • Readiness Probe — определяет, готов ли контейнер принимать трафик
  • Startup Probe — для долгозапускаемых приложений, помогает избежать преждевременных рестартов

Пример liveness и readiness probes: ```yaml livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10

readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 3 periodSeconds: 5 ``` Обратите внимание, что эти проверки выполняются Kubernetes-агентом и определяют, когда контейнер нуждается в рестарте или может быть подключен к сервису.

Работа с переменными окружения и секретами

Простые переменные

Их можно определить явно: ```yaml env:

  • name: LOG_LEVEL value: debug // простой текст

  • name: DB_HOST value: db.example.net ```

    Использование ConfigMap и Secret

Лучше управлять параметрами приложения через ConfigMap и Secret. Смотрите, я покажу вам, как это делается.

Пример с ConfigMap:

envFrom:
  - configMapRef:
      name: my-config

Пример с Secret:

envFrom:
  - secretRef:
      name: app-secret

Индивидуальные значения из Secret можно назначать переменным окружения:

env:
  - name: PASSWORD
    valueFrom:
      secretKeyRef:
        name: app-secret
        key: db-password

Этот подход упрощает работу с конфиденциальными данными и позволяет изменять параметры не перекатывая новые контейнеры.

Управление ресурсами контейнера

Управлять CPU и памятью критически важно: это защищает кластер от "захвата" слишком прожорливыми контейнерами и позволяет планировщику Kubernetes правильно распределять задачи.

Пример задания ресурсов

resources:
  requests:
    memory: "64Mi"   # Минимально гарантированное количество памяти
    cpu: "250m"      # Минимально гарантированный объем процессора
  limits:
    memory: "128Mi"  # Максимально допустимый объем памяти
    cpu: "500m"      # Максимально допустимый объем процессора

Обратите внимание: если контейнер превысит лимит памяти — он будет убит (OOMKilled). CPU-лимит ограничивает не память, а скорость выполнения контейнера.

Работа с хранилищем и томами

Контейнеры по умолчанию не сохраняют данные между перезапусками — файловая система контейнера эфемерна.

Kubernetes решает эту проблему с помощью томов (Volumes), которые монтируются в контейнер:

volumes:
  - name: app-data
    persistentVolumeClaim:
      claimName: app-pvc

containers:
  - name: my-app
    ...
    volumeMounts:
      - name: app-data
        mountPath: /data

Теперь /data в контейнере будет связано с PersistentVolume, и данные сохранятся даже если контейнер умирает.

Сетевые аспекты

Все контейнеры внутри Pod разделяют сетевой namespace, то есть общие IP-адрес и порты. Входящий трафик в контейнер обычно организуется через Service.

Пример публикации порта:

ports:
  - containerPort: 8080

Service перенаправляет трафик с внешнего IP (или ClusterIP) на containerPort внутри Pod.

Логи контейнеров

Контейнеры по умолчанию пишут логи в stdout/stderr. Kubernetes автоматически захватывает эти потоки и делает их доступными через команду:

kubectl logs pod-name -c container-name

Если Pod всего с одним контейнером, флаг -c можно не использовать.

Для долгосрочного хранения логов применяют сторонние системы (ELK, Loki и др.), но на старте достаточно встроенной команды.

Переиспользование контейнеров

Контейнеры можно собирать на базовых образах (например, alpine, ubuntu, node, python), наращивая нужные зависимости по мере надобности. Это помогает создавать более легкие и быстрые контейнеры для Kubernetes.

Пример Dockerfile: dockerfile FROM python:3.11-slim WORKDIR /app COPY . . RUN pip install -r requirements.txt CMD ["python", "main.py"]

Образ собирается, загружается в реестр (DockerHub, Harbor, GitHub Container Registry) и используется в Kubernetes YAML.

Полезные параметры и advanced-настройки

command и args

Если образ поддерживает запуск разных процессов, можно переопределять их через поля command и args. yaml command: ["python"] args: ["worker.py"]

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

Необязательно прокидывать все секреты через env, можно примонтировать их как файлы: ```yaml volumeMounts:

  • name: secret-volume mountPath: /etc/secret volumes:
  • name: secret-volume secret: secretName: my-secret ```

Тонкая настройка runtime

Можно указать отдельные runtime-классы (например, для запуска контейнеров в gVisor или Kata Containers с дополнительной изоляцией):

runtimeClassName: gvisor

Мультиконтейнерные Pod

В одном Pod можно запускать несколько взаимосвязанных контейнеров (sidecar, init-контейнеры).

Пример init-контейнера:

initContainers:
  - name: init-db
    image: busybox
    command: ['sh', '-c', 'until nc -z db 5432; do sleep 1; done;']

Основной контейнер стартует только после завершения всех init-контейнеров.

Обработка сигналов завершения

Kubernetes отправляет сигнал SIGTERM контейнеру перед остановкой. Я советую вам реализовать корректную обработку завершения (graceful shutdown) в вашем приложении, чтобы избежать потери данных или некорректного завершения транзакций.

Использование аннотаций и метаданных

Контейнеры поддерживают добавление аннотаций к Pod, чтобы интегрировать его с пользователями, CI/CD, мониторингом:

metadata:
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"

Эти поля не влияют на сам контейнер, но позволяют подключать инструменты мониторинга, трейсинга, кастомные тулзы.

Основные антипаттерны и грабли

  • Не бегите запускать один и тот же процесс в нескольких контейнерах внутри Pod — предполагается, что контейнеры внутри Pod решают одну общую задачу.
  • Не кладите внутрь контейнера логику, связанную с хранением долгоживущих данных, без подключения persistent volume.
  • Не храните секреты и пароли в Dockerfile или явном виде в YAML.
  • Не забывайте о resource limits: отсутствие лимитов может привести к торможению или падению всего узла.

Заключение

Контейнеры — это фундамент Kubernetes, и понимание их устройства, параметров и ограничений критически важно. Вы научились различать базовые и продвинутые параметры контейнера, увидели, как управлять ресурсами, переменными среды, томами, сетевой конфигурацией и логами. Если вы правильно опишете контейнер, масштабирование, отказоустойчивость и обновления приложений станут куда проще: вещи, ради которых и создавали Kubernetes.


Частозадаваемые технические вопросы по теме статьи и ответы на них

Как узнать, с какими аргументами был запущен контейнер внутри Pod?

Используйте команду: bash kubectl get pod pod-name -o jsonpath="{.spec.containers[*].args}" Если нужны команды запуска — замените args на command.

Почему мой контейнер все время перезапускается? Как узнать root-ошибку?

Выполните: bash kubectl describe pod pod-name Проверьте секции Events и Status — там указаны причины рестарта (например, OOMKilled, CrashLoopBackOff). Посмотрите логи: bash kubectl logs pod-name --previous Это покажет логи предыдущего сбоя.

Как примонтировать архив или бинарник в контейнер, не пересобирая образ?

Вы можете использовать специальный Init Container, который скачает архив в volume до старта основного контейнера.
Пример: ```yaml initContainers:

  • name: download image: busybox command: ["wget", "-O", "/data/app.bin", "http://url/app.bin"] volumeMounts:
    • name: bin-dir mountPath: /data containers:
  • name: main ... volumeMounts:
    • name: bin-dir mountPath: /opt/bin ```

Как сделать, чтобы мой контейнер видел хостовую директорию?

Используйте volume типа hostPath, но будьте осторожны — это снижает переносимость и может стать источником потенциальных уязвимостей: ```yaml volumes:

  • name: host-volume hostPath: path: /path/on/host containers:
  • name: app volumeMounts:
    • name: host-volume mountPath: /mnt/host ```

Как передать переменные окружения из Pod в подчиненные Jobs или CronJobs?

Определите нужные переменные в секции env или envFrom внутри спецификации template для Job/CronJob. Если значения статичны для большинства ресурсных шаблонов — применяйте ConfigMap/Secret и используйте envFrom для наследования.

Стрелочка влевоНазначение и примеры Controllers в KubernetesПримеры использования ConfigMap в KubernetesСтрелочка вправо

Постройте личный план изучения Kubernetes до уровня Middle — бесплатно!

Kubernetes — часть карты развития DevOps

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Kubernetes

Terraform и Kubernetes инфраструктура как кодНастройка и использование Runners в KubernetesНастройка и деплой PostgreSQL в KubernetesСравнение и интеграция Openshift и KubernetesПримеры интеграции GitHub Actions и KubernetesDeploy приложений в Kubernetes - пошаговое руководство для начинающих и не толькоКак настроить CD в KubernetesИнтеграция Ansible в KubernetesИнтеграция CI/CD с Jenkins и KubernetesИнтеграция Kubernetes с GitLab - Автоматизация CI CD в облачной инфраструктуреГайд по DevOps инструментам в KubernetesОсобенности платформы Deckhouse в Kubernetes
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Kubernetes и Helm

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Микросервисы

Антон Ларичев
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий