Примечание переводчика: оригинал, опубликованный в официальном блоге Kubernetes, собрал лучшие практики по работе с конфигурациями. Мы перевели его, но не смогли удержаться от небольшого дополнения: наши коллеги из команды Deckhouse добавили несколько советов, которые регулярно помогают пользователям нашего дистрибутива избегать типичных «болевых точек» — особенно в части управления ресурсами, отказоустойчивости и автоматизации.
Конфигурация в Kubernetes — одна из тех вещей, что кажутся мелочью, пока не станут крупной проблемой. Именно конфигурация является сердцем любой рабочей нагрузки. Пропущенная кавычка, неправильная версия API или сбившийся отступ в YAML-файле способны полностью сломать ваш деплой.
В этой статье собраны проверенные временем рекомендации по работе с конфигурацией. Это те самые полезные привычки-практики, которые делают инфраструктуру Kubernetes чистой, консистентной и лёгкой в управлении. Независимо от того, только начинаете ли вы свой путь или развёртываете приложения ежедневно, эти мелочи помогут поддерживать стабильность кластера и сберегут ваши нервы в будущем.
Статья написана по мотивам оригинальной страницы Configuration Best Practices с лучшими практиками по конфигурации, которая со временем пополнялась благодаря вкладу многих участников сообщества Kubernetes.

Содержание:
Общие советы по работе с конфигурациями
Используйте самую свежую стабильную версию API
Kubernetes быстро развивается. Старые версии API рано или поздно устаревают и перестают работать. Поэтому при определении ресурсов всегда убеждайтесь, что используете последнюю стабильную версию API. Проверить это можно с помощью команды kubectl api-resources.
Этот простой шаг избавит вас от проблем с совместимостью в будущем.
В Kubernetes встроена справка по API-ресурсам, всегда можно посмотреть, какие есть параметры в объекте и возможные значения:
kubectl explain pod.spec.containers
Храните конфигурацию в системе контроля версий
Никогда не применяйте манифесты прямо со своего компьютера. Всегда держите их в системе контроля версий вроде Git — это ваша страховка. Если что-то пойдёт не так, можно будет моментально откатиться к предыдущему коммиту, сравнить изменения или пересоздать кластер — без паники.
Пишите конфигурации в YAML, а не в JSON
Для файлов конфигураций используйте YAML, а не JSON. Технически работают оба, но YAML просто удобнее для людей. Он легче читается, в нём меньше «шума», и он стал стандартом в сообществе.
При этом у YAML есть свои подводные камни с булевыми значениями: используйте только true или false. Избегайте yes, no, on или off. В одной версии YAML они могут сработать, в другой нет. Чтобы избежать проблем, берите в кавычки всё, что похоже на булево значение (например, "yes").
Стремитесь к простоте и минимализму
Не задавайте значения по умолчанию, которые Kubernetes и так подставит сам. Чем меньше настроек в манифесте, тем проще его отлаживать, ревьюить и тем меньше шансов, что что-то сломается в будущем.
Группируйте связанные объекты вместе
Если Deployment, Service и ConfigMap относятся к одному приложению, поместите их в один манифест. Так проще отслеживать изменения и применять всё вместе. Пример такого синтаксиса можно посмотреть в файле all-in-one.yaml для приложения-примера «Гостевая книга».
Кроме того, с помощью команды kubectl apply -f configs/ можно применять целые директории. Одно нажатие на кнопку, и все ресурсы из директории развёрнуты.
Добавляйте толковые аннотации
Манифесты пишутся не только для машин, но и для людей. Используйте аннотации, чтобы объяснить, для чего нужен тот или иной ресурс. Одна строчка с описанием сэкономит часы при отладке в будущем и упростит совместную работу.
Самая полезная аннотация — kubernetes.io/description. Это как комментарий, только он сохраняется в API, и его будут видеть все даже после развёртывания.
Управление рабочими нагрузками: поды, Deployment'ы и Job'ы
Частая ошибка новичков в Kubernetes — создавать поды напрямую. Они, конечно, запустятся, но сами не перепланируются, если что-то пойдёт не так.
«Голые» поды (Naked Pods) — те, которыми не управляет контроллер вроде Deployment или StatefulSet, — вполне годятся для тестов, но для production они не подходят.
Почему? Потому что если «умрёт» узел, на котором работает под, то и под «умрёт» вместе с ним. Проблема в том, что такие поды Kubernetes автоматом не вернёт.
Используйте Deployment'ы для приложений, которые должны работать непрерывно
Примитив Deployment — почти всегда лучший выбор, чем создание подов вручную. Он создаёт ReplicaSet, который следит за нужным количеством реплик, и задаёт стратегию обновления (например, RollingUpdate). Можно выкатить новую версию, а если что-то сломается — моментально откатиться.
Используйте Job'ы для задач, которые должны выполниться и завершиться
Job отлично подходит, когда нужно что-то однократно запустить, например миграцию базы данных или пакетную обработку. Этот примитив перезапустит задачу в случае ошибки и отчитается об успехе, когда всё будет готово.
Настройка Service’ов и сети
Через Service’ы рабочие нагрузки общаются друг с другом внутри кластера (а порой и с внешним миром). Без них поды существуют, но не могут друг с другом связаться. Конечно же, это малоприятно.
Создавайте Service’ы до рабочих нагрузок, которые их используют
Когда Kubernetes запускает под, он автоматом прокидывает в него переменные окружения для уже существующих Service’ов. Если под зависит от некоторого Service, создавайте этот Service до его соответствующих бэкенд-нагрузок (Deployment'а или StatefulSet'а) и до любых других приложений, которым он нужен.
Предположим, что в кластере работает Service foo. В этом случае во всех запускаемых контейнерах будут определены следующие переменные окружения:
FOO_SERVICE_HOST=<хост, на котором запущен Service>
FOO_SERVICE_PORT=<порт, на котором доступен Service>
У обнаружения Service’ов через DNS такой проблемы нет, но следовать данному правилу — это в любом случае хорошая практика.
Используйте DNS для обнаружения Service’ов
Если в кластере установлен DNS add-on (что характерно для большинства кластеров), для каждого Service автоматически создаётся DNS-запись. То есть к нему можно обращаться по имени, а не по IP-адресу curl http://my-service.default.svc.cluster.local.
Это одна из тех фич, которые делают сетевое взаимодействие в Kubernetes по-настоящему магическим.
Не используйте hostPort и hostNetwork без крайней необходимости
Иногда в манифестах можно встретить следующие параметры:
hostPort: 8080
hostNetwork: true
Дело в том, что они жёстко привязывают поды к определённым узлам, из-за чего их становится сложнее планировать и масштабировать. Причина в том, что каждая комбинация <hostIP, hostPort, protocol> обязана быть уникальной. Если не указать hostIP и protocol явно, Kubernetes будет по умолчанию использовать 0.0.0.0 для hostIP и TCP для протокола. Старайтесь избегать этих полей, если только не занимаетесь отладкой или не пишите что-то вроде сетевого плагина.
Если вам просто нужен локальный доступ для тестов, попробуйте kubectl port-forward: kubectl port-forward deployment/web 8080:80.
Подробнее об этом можно почитать в документации. Если действительно нужен доступ извне, создайте Service типа NodePort. Это более безопасный и правильный, «кубернетовский» путь.
Используйте headless Service для внутреннего обнаружения
Иногда требуется отказаться от балансировки трафика средствами Kubernetes и обращаться напрямую к каждому поду. В таких случаях применяется так называемый headless Service.
Чтобы создать такой Service, нужно установить clusterIP: None. В этом случае DNS вместо единственного IP-адреса Service’а будет возвращать список IP-адресов всех подов, в него входящих. Это идеальное решение для приложений, которые сами управляют своими подключениями.
Эффективная работа с лейблами
Лейблы — это пары «ключ-значение», которые навешиваются на объекты вроде подов. Лейблы помогают организовывать, опрашивать и группировать ресурсы. Сами по себе они не выполняют никаких действий, но обеспечивают слаженную совместную работу других компонентов — от Service’ов до Deployment'ов.
Лейблы должны быть осмысленными
Хорошие лейблы помогают разобраться, что к чему, даже спустя длительное время. Создавайте и применяйте лейблы, которые описывают суть приложения или Deployment'а. Например:
labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/component: web
tier: frontend
phase: test
Здесь:
app.kubernetes.io/name:— что за приложение;tier:— к какому слою оно относится (фронтенд/бэкенд);phase:— на какой оно стадии (test/prod).
Потом с помощью этих лейблов можно будет делать крутые выборки. Например: kubectl get pods -l tier=frontend.
Эта команда выведет все фронтенд-поды в кластере — неважно, к какому Deployment'у они относятся. То есть не нужно вручную перечислять все поды по именам — вы просто описываете нужный результат. Смотрите примеры такого подхода в приложении «Гостевая книга».
Используйте стандартные лейблы Kubernetes
Kubernetes предлагает свой набор рекомендованных лейблов. Это стандартный способ именовать ресурсы в разных рабочих нагрузках и проектах. Если следовать этому соглашению, манифесты станут чище, а такие инструменты, как Headlamp, дашборд и внешние системы мониторинга, смогут автоматически понимать, что и где запущено.
Используйте лейблы для отладки
Поскольку контроллеры (такие как ReplicaSet или Deployment) используют лейблы для управления подами, можно временно удалить лейбл, чтобы «отсоединить» под.
Пример:
kubectl label pod mypod app-
Часть app- удалит лейбл с ключом app. После этого контроллер перестанет управлять данным подом. Это всё равно что поместить его в «карантин» для детального изучения. Для интерактивного удаления или добавления лейблов используйте kubectl label.
Затем можно посмотреть логи пода, зайти внутрь через exec, а закончив работу, удалить вручную. Это суперполезный приём, о котором должен знать каждый инженер Kubernetes (хотя его часто недооценивают).
Полезные советы по работе с kubectl
Эти простые советы значительно облегчат жизнь при работе с кучей файлов-манифестов или несколькими кластерами.
Применяйте директории целиком
Вместо того чтобы применять файлы по одному, можно применить всю директорию сразу:
# Использование server-side apply — тоже отличная идея.
kubectl apply -f configs/ --server-side
Эта команда находит все .yaml-, .yml- и .json-файлы в директории и применяет их скопом. Так получается быстрее, аккуратнее и позволяет держать ресурсы одного приложения вместе.
Используйте селекторы лейблов для выбора или удаления ресурсов
Не всегда обязательно вводить имена ресурсов по одному. Вместо этого можно использовать селекторы для выполнения операций сразу над группами ресурсов:
kubectl get pods -l app=myapp
kubectl delete pod -l phase=test
Это особенно удобно в CI/CD-пайплайнах, когда нужно динамически подчищать тестовые ресурсы.
Эта же идея отлично работает для масштабирования и роллаутов:
kubectl scale deployment -l app=myapp
kubectl rollout undo deployment -l phase=test
Просматривайте логи всех контейнеров пода
Если у пода есть несколько контейнеров, можно просматривать их логи одновременно — особенно это актуально с флагом -f:
kubectl logs -l app=myapp --all-containers -f
Поднимайте тестовые Deployment'ы и Service’ы из командной строки
Для простых экспериментов необязательно писать манифест. Можно поднять Deployment прямо из командной строки:
kubectl create deployment webapp --image=nginx
А затем «открыть» его как Service:
kubectl expose deployment webapp --port=80
Это особенно удобно, когда нужно что-то по-быстрому проверить, прежде чем писать полноценные манифесты. Пример можно найти в статье Use a Service to Access an Application in a cluster.
Быстро и мягко перезапускайте Deployment'ы
Когда стоит задача просто перезапустить все поды Deployment'а, можно воспользоваться rollout restart. В этом случае обновление произойдёт с использованием стратегии обновления Deployment'а.
kubectl rollout restart deployment my-app
Если нужно временно остановить все поды Deployment'а, просто отмасштабируйте их в 0:
kubectl scale deployment my-app --replicas=0
Используйте pod disruption budgets
Использование PDB облегчает обслуживание кластера, он позволяет избежать нежелательных прерываний работы приложения при дрейне узлов.
Советы по работе в Deckhouse Kubernetes Platform
Всегда добавляйте Vertical Pod Autoscaler
Даже если вам не нужно автоматически масштабировать ресурсы в подах, всегда добавляйте VPA. У него есть специальный режим off, который позволяет получить рекомендацию на основе утилизации ресурсов. С помощью этой статистики вы сможете лучше и точнее проводить capacity planning вашего кластера и понимать, насколько больше или меньше ресурсов вы запрашиваете, чем нужно в реальности.
Прописывайте ресурсы в подах
Стоит всегда прописывать запрос по CPU и памяти во всех контейнерах подов, это помогает планировщику распределять поды по узлам и позволяет избегать перегрузок.
Это дискуссионный момент, но я бы предложил прописывать лимиты ресурсов только по памяти и ephemeral storage. Дело в том, что лимит по CPU в подавляющем большинстве случаев будет только замедлять приложение. Чтобы понимать, что реквест по CPU слишком мал, используйте VPA.
Задавайте приоритет подам
В Deckhouse Kubernetes Platform «из коробки» есть десяток классов, используйте их для приложений, особенно если активно пользуетесь HPA: это позволяет вытеснять некритичные Service’ы в пользу жизненно важных.
Заключение
Чем прозрачнее конфигурация, тем спокойнее администраторы кластера. Придерживайтесь нескольких простых правил: делайте конфигурацию простой и минималистичной, всё версионируйте, используйте понятные лейблы и не полагайтесь на «голые» поды. Это сэкономит вам кучу времени на отладку в будущем.
А знаете, что самое крутое? Простые, минималистичные конфигурации остаются легко читаемыми! Даже через несколько месяцев вы или кто-то другой из команды сможете сразу понять, что к чему, просто взглянув на них.
P. S.
Читайте также в нашем блоге: