Олег Марков
Что нужно знать о 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
Контейнеры проходят несколько стадий в своей жизни:
- Создание Pod: Когда в кластер поступает команда на создание Pod, начинается подготовка (выделение ресурсов, подготовка томов, создание сетевого namespace и пр.).
- Pull образа: Node, где будет запущен Pod, скачивает указанный образ, если его нет локально.
- Создание и запуск контейнера: После подтверждения, что всё подготовлено, запускается процесс, который является контейнером.
- Выполнение приложения: Контейнер работает до завершения основного процесса.
- Завершение: Если процесс падает — определяется дальнейшая стратегия (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
для наследования.
Постройте личный план изучения Kubernetes до уровня Middle — бесплатно!
Kubernetes — часть карты развития DevOps
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Kubernetes
Лучшие курсы по теме

Kubernetes и Helm
Антон Ларичев
Docker и Ansible
Антон Ларичев