Deployment, ReplicaSet и восстановление копий API
Первый Pod показал, как образ превращается в процесс. Но объект api-once не выражает требование поддерживать несколько экземпляров приложения. Теперь заменим его Deployment api и отдельно создадим Deployment web. Результат урока — увидеть цепочку управления и понять, почему удаление экземпляра не означает удаление приложения.
Работа продолжает локальный проект «Площадка». Образы уже описаны во втором уроке, кластер — в третьем. Команды остаются будущими действиями читателя: автор не применял манифесты и не наблюдал восстановление Pod. Все ожидаемые эффекты относятся к указанной лаборатории и не доказывают устойчивость сайта при потере физического узла.
Шаблон для двух экземпляров
Полный manifests/02-api-deployment.yaml содержит Deployment с двумя копиями:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: ploshchadka
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
automountServiceAccountToken: false
containers:
- name: api
image: ploshchadka-api:1
imagePullPolicy: Never
ports:
- name: http
containerPort: 3000
Верхние metadata описывают Deployment, а template.metadata — будущие Pod. У них различное назначение. Метка на Deployment сама по себе не попадёт автоматически на все дочерние экземпляры. Для выбора копий важно содержимое шаблона. Именно оно будет использовано при создании каждого нового Pod.
Селектор app: api совпадает с меткой шаблона. Это договорённость между управляющим объектом и его экземплярами. Если начинающий разработчик переименует только одну сторону, система уже не сможет корректно сопоставить намерение и Pod; некоторые несовпадения API отклонит сразу. Выбирайте устойчивую метку принадлежности, а версию образа показывайте отдельным признаком, не меняя идентичность Deployment.
Отказ от автоматического монтирования ServiceAccount-токена здесь возможен, потому что API не обращается к Kubernetes API. Для выдачи JSON ему не нужны права читать Pod, создавать объекты или получать Secrets. Это не запрещает всю сетевую активность контейнера, но убирает ненужный способ доступа к управляющему API. Более подробные права рассмотрим отдельно.
Кому принадлежит восстановление
Deployment управляет ReplicaSet, а ReplicaSet поддерживает число Pod своего шаблона. Получается цепочка владельцев. Разработчик работает с Deployment как с приложением, а конкретные ReplicaSet и Pod появляются в результате работы контроллеров. При последующем изменении шаблона Deployment сможет создать другую ReplicaSet и постепенно переключить количество экземпляров. Поведение описано в документации Deployment.
Перед переходом удаляем только прежний самостоятельный Pod. Затем создаём оба Deployment:
kubectl --context kind-ploshchadka -n ploshchadka delete pod api-once
kubectl --context kind-ploshchadka apply -f manifests/02-api-deployment.yaml
kubectl --context kind-ploshchadka apply -f manifests/03-web-deployment.yaml
kubectl --context kind-ploshchadka -n ploshchadka get deployments,replicasets,pods
Ожидаются две копии API и одна web. Имена Pod включают дополнительные части, а не равны просто api. Эти имена удобны для расследования конкретного экземпляра, но не должны становиться адресом в API_BASE. Web пока не сможет надёжно разрешить имя api, потому что Service ещё не создан. Это промежуточное состояние, а не основание переписывать код frontend.
Представим адресное удаление одного API Pod. ReplicaSet увидит, что имеющееся количество меньше желаемого, и создаст замену с новым именем. При этом образ и число replicas останутся прежними. Если же удалить Deployment, удаляется намерение поддерживать приложение; восстановление «по памяти» не происходит. Для повторного появления приложения нужно снова передать соответствующую декларацию.
Изменение количества и изменение шаблона
Идентичность владельца хранится не только в читаемом имени, но и в ссылках объектов. Поэтому новый Deployment с прежним названием после удаления не следует считать продолжением того же объекта по всем внутренним признакам. Для учебной передачи важны декларация и наблюдаемая цепочка владельцев, а для расследования — также идентификаторы конкретных ресурсов.
Количество копий и версия процесса — разные параметры. Изменение replicas с двух на три добавляет ещё один экземпляр того же шаблона. Изменение template.spec.containers[0].image меняет шаблон и приводит к обновлению экземпляров. Поэтому масштабирование не является выпуском нового кода. И наоборот, новый образ сам по себе не означает увеличение вычислительной мощности системы.
На этом этапе все копии одинаково читают константный каталог. Такой API можно горизонтально размножать без согласования записей. Если добавить в память счётчик посещений, каждая копия начнёт вести собственное значение. Kubernetes исправно поддержит три процесса, но ответ зависит от выбранного экземпляра. Это ошибка модели данных, а не ошибка ReplicaSet.
Не редактируйте дочерний Pod как основной способ настройки приложения. Контроллер может заменить его, взяв значения из шаблона Deployment, и ручное изменение исчезнет. Намерение нужно фиксировать на уровне владельца. Аналогично изменение созданного ReplicaSet обычно обходит более высокий уровень управления и делает дальнейший rollout менее понятным.
Селектор Deployment в apps/v1 не предназначен для произвольного переименования после создания. Поэтому полезно заранее выбрать стабильное имя принадлежности. Для «Площадки» оно совпадает с ролью приложения: api и web. Когда появятся дополнительные компоненты, дадим им отдельные метки вместо использования одной общей метки для всех контейнеров курса.
Что действительно подтверждает готовность
Команда get показывает текущие числа, но даже полный набор запущенных Pod ещё не подтверждает пользовательский сценарий. Возможна ситуация: API слушает порт, web отдаёт HTML, а запросы каталога идут по неправильному адресу. Поэтому число копий нужно сравнивать с намерением, а HTTP-путь проверять отдельно. Эти наблюдения отвечают на разные вопросы.
Для будущего локального просмотра одной копии можно временно использовать port-forward deployment/api 3000:3000. Команда выберет конкретный Pod из Deployment. Она не балансирует все ваши обращения между двумя экземплярами. Если выбранный Pod исчезнет, соединение потребуется открыть заново. Значение pod в JSON поможет увидеть, с какой копией связано это временное соединение.
В наборе пока нет readinessProbe. Процесс может считаться готовым контейнером до завершения нашей задержки инициализации. Это ограничение исправим после настройки Service и конфигурации. Стадии курса разделены намеренно: сначала выясняем, кто поддерживает экземпляры, затем — кто направляет к ним трафик и по какому признаку экземпляр должен участвовать в обслуживании.
После урока читатель должен различать три операции: остановить процесс, удалить конкретный Pod и удалить управляющий Deployment. У них различные последствия, даже если на экране в первый момент исчезает одинаковый ответ HTTP. Продолжим со стабильными именами Service и обнаружением адресатов, чтобы web больше не зависел от имени одной копии.