kubectl apply vs set: Выбор правильной команды для обновления ресурсов
Поймите, когда использовать kubectl apply, set и edit без создания расхождений между живыми объектами Kubernetes и Git.
kubectl apply vs set: Выбор правильной команды для обновления ресурсов
Разница между kubectl apply и kubectl set — это не просто синтаксис. Это разница между управлением Kubernetes из объявленного источника истины и изменением живых объектов напрямую. Оба полезны. Оба могут навредить, если использовать их не в том месте.
Используйте kubectl apply, когда изменение должно стать желаемым состоянием системы. Используйте kubectl set, когда вам нужно целенаправленное живое изменение, обычно временное или срочное. Используйте kubectl edit, когда нужно интерактивно просмотреть и исправить живой объект, но помните, что это самый простой способ создать расхождение с Git.
Объект Kubernetes имеет желаемое состояние, хранящееся на сервере API. Deployment указывает, сколько реплик должно существовать, какой образ должен работать, какие метки идентифицируют поды, какие ресурсы запрашиваются и многое другое. Контроллеры работают, чтобы привести реальность в соответствие с этим желаемым состоянием. Ваша команда обновления изменяет желаемое состояние; контроллеры делают остальное.
С помощью kubectl apply вы храните желаемое состояние в YAML или JSON файлах. Файл — это то, что вы проверяете, фиксируете, продвигаете и откатываете. Типичная команда проста:
kubectl apply -f deployment.yaml
Если объект не существует, Kubernetes создает его. Если он существует, Kubernetes обновляет его в соответствии с манифестом. Повторное применение того же файла не должно вызывать новых поведенческих изменений. Эта идемпотентность — одна из причин, по которой apply хорошо работает в CI/CD и GitOps рабочих процессах.
Клиентский kubectl apply исторически использовал аннотацию последнего применения для расчета изменений. Серверный apply, включенный с помощью --server-side, отслеживает владение полями через управляемые поля на сервере API. Детали различаются, но операционная идея та же: объявленная конфигурация владеет желаемым состоянием.
Вот небольшой манифест Deployment:
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.25
ports:
- containerPort: 80
Если вы измените образ в файле и выполните kubectl apply -f deployment.yaml, Deployment обновится. Если файл находится в Git, изменение можно проверить. Если развертывание сломается, вы можете откатить коммит или использовать историю развертывания Kubernetes в зависимости от того, как ваш процесс развертывания записывает ревизии.
kubectl set работает иначе. Он изменяет определенное поле в живом объекте. Распространенный пример — изменение образа контейнера:
kubectl set image deployment/web nginx=nginx:1.26
Эта команда быстрая и читаемая. Во время инцидента скорость имеет значение. Если текущий образ сломан и вам нужно переместить Deployment на заведомо исправный образ, kubectl set image может быть самым быстрым путем. Опасность в том, что произойдет дальше. Если deployment.yaml все еще содержит nginx:1.25, следующий kubectl apply -f deployment.yaml может вернуть рабочую нагрузку обратно на 1.25.
Это несоответствие называется расхождением конфигурации. Живой кластер говорит одно. Исходный файл говорит другое. Расхождение не всегда катастрофично, но оно усложняет отладку, потому что люди перестают доверять репозиторию. Кто-то спрашивает: "Что работает в продакшене?" и честный ответ становится: "Дайте я проверю кластер."
kubectl set имеет несколько полезных подкоманд:
kubectl set image deployment/web nginx=nginx:1.26
kubectl set env deployment/web FEATURE_FLAG=true
kubectl set resources deployment/web -c=nginx --requests=cpu=200m,memory=256Mi --limits=cpu=500m,memory=512Mi
Они практичны для кластеров разработки, демонстраций, краткосрочных тестов и экстренных изменений в продакшене с последующим коммитом. Они не заменяют поддерживаемые манифесты.
kubectl edit извлекает живой объект, открывает его в вашем редакторе и отправляет измененный объект обратно на сервер API, когда вы сохраняете:
kubectl edit deployment/web
Это удобно, потому что вы видите полный живой YAML, включая поля, добавленные контроллерами. Это также рискованно, потому что живые объекты содержат много полей, которыми вы не должны управлять вручную, таких как status, сгенерированные метаданные, версии ресурсов и управляемые поля. Kubernetes проигнорирует или отклонит некоторые недопустимые правки, но не каждая плохая правка синтаксически неверна.
Распространенное безопасное использование kubectl edit — это быстрый непродуктивный эксперимент: увеличить реплики, изменить аннотацию или протестировать значение пробы. Распространенное небезопасное использование — ручное редактирование продакшен Deployment каждую неделю без обновления манифестов. Это создает кластер, который никто не может уверенно пересобрать.
Практическое правило таково: если вы хотите, чтобы изменение пережило следующее развертывание, поместите его в манифест и используйте apply. Если вам нужно только "ткнуть" живой объект, используйте set или edit, затем либо отмените изменение, либо перенесите его в Git.
Есть несколько случаев, когда императивные команды не только приемлемы, но и полезны. Во время отладки вы можете временно добавить переменную окружения, увеличивающую уровень детализации логов:
kubectl set env deployment/api LOG_LEVEL=debug
После сбора логов удалите ее:
kubectl set env deployment/api LOG_LEVEL-
Если настройка отладки должна стать постоянной, зафиксируйте ее в манифесте. Не полагайтесь на память.
Другой случай — экстренный откат. Если ваш конвейер развертывания застрял и затронуты клиенты, прямая установка образа может быть разумной:
kubectl set image deployment/api api=registry.example.com/api:2026-05-23-good
kubectl rollout status deployment/api
Последующее действие должно быть немедленным: открыть pull request или коммит, который приводит объявленный манифест в соответствие с аварийным состоянием, или запустить обычный процесс отката, как только конвейер станет здоровым. Живое исправление выигрывает время; оно не должно становиться новым недокументированным методом развертывания.
У kubectl apply тоже есть ловушки. Если вы смешиваете несколько инструментов, управляющих одними и теми же полями, вы можете получить конфликты или неожиданные перезаписи. Например, контроллер GitOps, Helm и человек, запускающий kubectl apply против одного и того же Deployment, могут все считать, что владеют частью объекта. Выберите четкое владение. Если Helm управляет ресурсом, обновите значения Helm и запустите процесс релиза Helm. Если Argo CD или Flux управляет им, измените Git и позвольте контроллеру синхронизироваться.
Будьте особенно осторожны с секретами и конфигурациями. kubectl set env может быстро внести изменения в Deployment, но может раскрыть значения в истории оболочки или журналах аудита. Для чувствительных значений обновляйте Secret через ваш обычный процесс управления секретами. Не вставляйте продакшен учетные данные в ad hoc команду, если ваша команда явно не приняла этот рабочий процесс.
Перед изменением живого объекта проверьте его:
kubectl get deployment web -o yaml
kubectl diff -f deployment.yaml
kubectl diff недооценен. Он показывает, что изменит apply до того, как вы сделаете изменение. В продакшене этот предварительный просмотр может выявить ошибки, такие как случайное удаление селектора меток, сброс лимита ресурсов или применение манифеста не того окружения.
Для серверного apply команда выглядит так:
kubectl apply --server-side -f deployment.yaml
Серверный apply может быть полезен, когда несколько участников управляют разными полями, но он не устраняет необходимость дисциплины владения. Если два менеджера пытаются владеть одним и тем же полем, Kubernetes может сообщить о конфликте. Это функция; она говорит вам, что рабочий процесс неоднозначен.
Вот простое руководство по принятию решений, которое я использую в реальных кластерах. Новый релиз приложения? Измените манифест и используйте apply через конвейер. Увеличить реплики для нагрузочного теста в стейджинге? kubectl scale или kubectl set подойдет, если вы отмените это. Исправить сломанный образ в продакшене? kubectl set image может быть приемлемо, но сразу же создайте изменение источника истины. Настроить запросы CPU на постоянной основе? Обновите манифест. Исследовать, какие поля есть у ресурса? Используйте kubectl get -o yaml, прежде чем хвататься за edit.
Когда команды делают это правильно, Kubernetes становится проще для понимания. Репозиторий рассказывает историю. Кластер соответствует репозиторию большую часть времени. Временные живые изменения помечаются как временные и очищаются. Инциденты все еще стрессовые, но конфигурация не становится второй загадкой.
Сама команда не является сутью. Суть в том, сможете ли вы завтра восстановить состояние кластера из доверенных файлов. kubectl apply поддерживает эту привычку. kubectl set и kubectl edit — это острые инструменты для моментов, когда прямое действие полезно. Держите эту границу четкой, и вы избежите множества предотвратимых проблем с Kubernetes.
Есть еще одна команда, которую люди помещают в ту же мысленную корзину: kubectl patch. Она также императивна, но лучше подходит для точных скриптовых изменений, чем edit. Например, вы можете пропатчить аннотацию Deployment, чтобы вызвать перезапуск или обновить небольшое поле в автоматизации. Применяется то же правило расхождения. Если пропатченное поле представляет долгосрочное желаемое состояние, обновите исходный манифест тоже.
kubectl patch deployment web -p '{"spec":{"template":{"metadata":{"annotations":{"restartedAt":"2026-05-24T10:00:00Z"}}}}}'
Для перезапусков предпочтительнее использовать специальную команду:
kubectl rollout restart deployment/web
Эта команда все еще изменяет живой объект, но ее намерение ясно: начать новый rollout из текущего шаблона пода. Это не замена изменению конфигурации в Git.
В средах GitOps граница еще строже. Если Argo CD или Flux владеет объектом, ручной kubectl set image может быть автоматически отменен, потому что контроллер видит расхождение и синхронизируется обратно с Git. Это может быть неожиданностью во время инцидента. Прежде чем вносить ручное изменение в продакшен, узнайте, будет ли контроллер GitOps бороться с вами. Иногда правильным экстренным действием является приостановка синхронизации для этого приложения, внесение исправления, затем фиксация соответствующего изменения в Git и возобновление синхронизации.
Вы также должны знать, как захватить живое различие, не фиксируя вслепую сгенерированные поля. kubectl get deployment web -o yaml включает статус, версии ресурсов, управляемые поля и другие данные, которые не должны попадать в чистый манифест. Если вам нужно перенести исправление, отредактируйте исходный манифест вручную или используйте такой инструмент, как Kustomize или Helm values, затем выполните kubectl diff, чтобы проверить предполагаемое изменение. Не заменяйте исходный файл сырым живым YAML, если вы не очистите его тщательно.
Для команд самая здоровая политика обычно короткая и явная. Изменения в продакшене проходят через Git. Экстренные живые изменения разрешены при необходимости, но они требуют последующего изменения источника или отката. Кластеры разработки более свободны, но все, что продвигается за пределы разработки, должно быть объявлено. Этой политике легче следовать, чем длинному списку запрещенных команд.
У этого есть и человеческая сторона. Во время сбоя человек с доступом к кластеру может сделать максимально быстрое исправление. Это нормально, когда команда рассматривает это как исключение в чрезвычайной ситуации. Это становится опасным, когда эти исключения становятся нормальной операцией. Если продакшен регулярно исправляется вручную, процесс развертывания либо слишком медленный, либо слишком хрупкий, либо ему не доверяют. Исправьте этот процесс, а не учите всех большему количеству трюков с живым редактированием.
RBAC может усилить рабочий процесс. Многие команды разрешают широкий доступ kubectl в разработке, но ограничивают запись в продакшен системами CI/CD, контроллерами GitOps или небольшой дежурной группой. Это не бюрократия ради самой бюрократии. Это уменьшает количество путей, которые могут изменить желаемое состояние. Когда что-то меняется, журналы аудита и история Git легче отслеживаются.
Для обучения все же стоит попрактиковаться со всеми тремя командами в одноразовом namespace. Создайте Deployment с помощью apply, измените его образ с помощью set, проверьте расхождение с помощью kubectl diff, затем обновите манифест и примените снова. Увидев расхождение один раз в безопасной среде, вы гораздо легче запомните правило для продакшена.