← Kubernetes: основы
8 мин · средне · Урок 8 из 11

kubectl edit и immutable поля Pod

Что у живого Pod можно поменять, что нельзя и как обойти ограничение.

Что делает kubectl edit

Pod - наименьшая единица, которую запускает Kubernetes. Внутри Pod работает один или несколько контейнеров. spec - это раздел манифеста, который описывает желаемое состояние объекта.

kubectl edit <kind>/<name> берёт текущий spec из API, открывает его во временном файле в редакторе и после выхода отправляет изменения обратно. Если ничего не поменял, команда тихо завершается. Если поменял, изменения уходят на API-сервер и проходят проверку.

Это три шага, собранные в одну команду:

kubectl get pod web -o yaml > /tmp/pod.yaml
vi /tmp/pod.yaml
kubectl apply -f /tmp/pod.yaml

Редактор по умолчанию - vi. Сменить его можно так:

export KUBE_EDITOR=nano
kubectl edit pod web

Карта: что меняется, что нет

Сначала общая картина, ниже разберём по пунктам.

Можно обычным editТолько через отдельный путьНельзя, нужно пересоздать
image контейнераresources (subresource resize)nodeSelector
labels, annotationsserviceAccountName
activeDeadlineSecondsinitContainers, volumes
tolerations (добавление)securityContext

Что можно менять у запущенного Pod

Когда Pod уже создан, API-сервер разрешает менять лишь узкий набор полей. Главное исключение - образ контейнера.

spec.containers[*].image менять можно. kubelet скачает новый образ и перезапустит контейнер. Сам Pod при этом остаётся, новый Pod не создаётся.

kubectl set image pod/web app=nginxinc/nginx-unprivileged:1.27

kubectl set image правит образ напрямую, без открытия редактора. Формат: pod/<имя> <контейнер>=<образ>. Имя контейнера здесь - app, не имя образа. Посмотреть имена контейнеров можно так:

kubectl get pod web -o jsonpath='{.spec.containers[*].name}'

Кроме image на живом Pod можно менять ещё несколько полей: metadata.labels, metadata.annotations, spec.activeDeadlineSeconds и spec.tolerations (только добавление).

Что менять нельзя

Большинство полей Pod после создания неизменяемы (immutable). При попытке их поправить валидатор вернёт ошибку.

Попытка вызовет ошибку, и kubectl предложит сохранить твою версию во временный файл:

error: pods "web" is invalid:
  spec: Forbidden: pod updates may not change fields other than
  `spec.containers[*].image`, ...

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

Ресурсы меняются на лету: subresource resize

С Kubernetes 1.35 CPU и память живого Pod меняются без пересоздания. Это называется in-place resize, и работает через отдельный subresource resize, а не через обычный update.

# обычный путь по-прежнему запрещён
kubectl patch pod web --type=json \
  -p '[{"op":"replace","path":"/spec/containers/0/resources/limits/cpu","value":"200m"}]'
# spec: Forbidden: pod updates may not change fields other than ...

# а так лимит меняется у работающего Pod
kubectl patch pod web --subresource resize --type=json \
  -p '[{"op":"replace","path":"/spec/containers/0/resources/limits/cpu","value":"200m"}]'
# pod/web patched

Результат смотрят через kubectl get pod web -o jsonpath='{.spec.containers[0].resources}'.

Kubernetes сообщает о ходе операции условиями PodResizePending и PodResizeInProgress в статусе Pod: часть изменений применяется мгновенно, часть требует, чтобы на ноде нашлось место.

Правило «Pod почти неизменяем» это не отменяет. Resize касается только ресурсов. Сменить nodeSelector, volumes или serviceAccountName живому Pod по-прежнему нельзя.

Как поменять то, что immutable

Ресурсы разобрали выше, они меняются через resize. Для остальных неизменяемых полей путь один: пересоздать Pod. Для этого есть kubectl replace --force:

replace --force не правит Pod, а подменяет его. Старый объект удаляется целиком, новый создаётся с тем же именем и всем остальным новым.

kubectl get pod web -o yaml > /tmp/pod.yaml
# правишь нужное поле в файле
kubectl replace --force -f /tmp/pod.yaml

--force означает: удали старый Pod и создай новый из файла. Это короткая запись для двух команд:

kubectl delete pod web
kubectl apply -f /tmp/pod.yaml

Имя у Pod сохранится, но это полностью новый объект. Новый UID (внутренний идентификатор объекта), новый IP, сброшенные счётчики. Pod не обновлён, он удалён и создан заново.

Почему в проде Pod без контроллера не запускают

Deployment - объект, который управляет набором одинаковых Pod и умеет обновлять их без простоя. Когда меняешь шаблон в Deployment, он не правит существующие Pod, а создаёт новые на замену. Поэтому у Deployment можно менять и image, и resources, и nodeSelector:

kubectl set image deploy/app app=nginx:1.27

В проде приложения держат под Deployment, чтобы обновления шли через плавную замену, а не через удаление и пересоздание вручную.

Домашка

Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-edit-pod     # развернуть стартовое состояние
./run.sh verify k8s-edit-pod    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.