Перейти к содержанию

Service, DNS и готовые адресаты API

Deployment поддерживает две копии API, однако их имена и адреса могут меняться. Web не должен получать новую конфигурацию при каждом восстановлении Pod. Добавим Service api: он создаёт постоянное имя для обращения к набору экземпляров. Второй Service web станет внутренней точкой доступа к frontend. После этого цепочка приложения приобретёт устойчивые связи.

Продолжаем «Площадку» из предыдущего урока. Полный файл находится в examples/kubernetes-web-lab/manifests/04-services.yaml. Он применяется отдельно после двух Deployment. Команды и результаты ниже предназначены для самостоятельной работы читателя; автор не создавал Service, не проверял DNS и не выполнял HTTP-запросы.

Метки определяют набор экземпляров

Первая декларация создаёт Service api:

apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: ploshchadka
spec:
  selector:
    app: api
  ports:
    - name: http
      port: 3000
      targetPort: http

Селектор Service сравнивается с метками Pod. Он не ссылается на Deployment по имени. Это различие полезно при диагностике: объект Deployment api может существовать, но Service останется без подходящих адресатов, если шаблон Pod имеет другую метку. Названия объектов читаются человеком, а связь в данном примере устанавливается именно селектором.

В четвёртом уроке порт контейнера получил имя http. Поэтому targetPort: http указывает на именованный порт подходящего Pod. Число port: 3000 задаёт порт самого Service. Эти значения могут различаться: внутренний адрес приложения и адрес точки доступа не обязаны использовать одинаковое число. Здесь сохраняем 3000, чтобы первая сеть читалась без дополнительного преобразования.

Поле type не указано, поэтому используется ClusterIP. Такой Service предназначен для доступа внутри кластера. Он не создаёт публичный адрес и не добавляет запись DNS вашего компьютера. Когда web обращается к http://api:3000, это имя существует в сетевом окружении Kubernetes, а не во всём интернете.

Не используйте один и тот же app: api для web. Селектор тогда захватит экземпляры другой роли, и часть запросов попадёт на неподходящий сервер. Число успешно работающих Pod не предотвратит эту ошибку. Выбор адресатов должен соответствовать одинаковому HTTP-контракту, а не просто объединять все компоненты одного проекта.

DNS и область namespace

В пределах namespace ploshchadka приложение web может использовать короткое имя api. Полное имя имеет структуру api.ploshchadka.svc.cluster.local при стандартном домене кластера. Короткая форма удобна для компонентов одной лаборатории. При обращении из другого namespace нужно явно указать область, иначе поиск короткого имени относится к namespace вызывающего Pod.

Это можно сравнить с именами файлов в разных каталогах: одинаковое краткое название не означает один и тот же объект во всей системе. В курсе используем один namespace, поэтому API_BASE=http://api:3000 остаётся достаточным. Когда рассматриваем разделение окружений, будем отдельно обсуждать перенос конфигурации, а не менять все обращения на IP.

Service сохраняет свою идентичность при замене дочерних Pod Deployment. При обычном обновлении изменяется набор адресатов, а программа web продолжает использовать прежнее имя. Механизм Service и его типы описаны в официальной документации; устройство имён — в документации DNS для Services и Pods.

Стабильный адрес не обещает успешный ответ. Если все подходящие экземпляры отсутствуют или не готовы, название Service по-прежнему может разрешаться, но обслужить запрос некому. Поэтому «DNS работает» и «каталог отвечает» — разные результаты. Разработчик должен выяснить, на каком переходе цепочки возникает проблема, прежде чем изменять разрешение имён.

EndpointSlice показывает фактических получателей

После будущего применения полезно прочитать связанные объекты:

kubectl --context kind-ploshchadka apply -f manifests/04-services.yaml
kubectl --context kind-ploshchadka -n ploshchadka get services
kubectl --context kind-ploshchadka -n ploshchadka get pods -l app=api --show-labels
kubectl --context kind-ploshchadka -n ploshchadka get endpointslices -l kubernetes.io/service-name=api

EndpointSlice представляет обнаруженные адресаты Service. В ожидаемом состоянии набор относится к копиям API, а не web или прежнему api-once. Здесь не подставляем конкретные IP: они назначаются в лаборатории. Смысл чтения — сопоставить адресатов с селектором и понять, есть ли у Service пригодные экземпляры.

Если EndpointSlice пуст, начните с меток. Сравните spec.selector Service с template.metadata.labels Deployment. Затем посмотрите состояние Pod и готовность. Если адресаты присутствуют, но запрос идёт не на нужный порт, проверьте именованный targetPort и адрес прослушивания Node-сервера. Такая последовательность связывает каждый вывод с конкретной декларацией.

В нашем промежуточном состоянии контейнер ещё не имеет readinessProbe. Для приложения это означает, что первые обращения могут попасть на API во время трёхсекундной задержки. Сам сервер вернёт 503. В дальнейшем probe уберёт неготовую копию из обычного обслуживания. Нельзя исправлять такой начальный ответ увеличением DNS timeout: проблема относится к готовности адресата.

Открытие страницы через Service web

Вторая декларация того же файла создаёт Service web с портом 80 и targetPort: http. Именованный порт web в Deployment равен 8080. Поэтому внутри кластера можно обращаться к http://web, не указывая 8080. HTTP-процесс продолжает слушать прежний порт; Service лишь выражает способ добраться до него.

Будущий временный доступ с компьютера выглядит так:

kubectl --context kind-ploshchadka -n ploshchadka port-forward service/web 8080:80

Читатель открывает http://127.0.0.1:8080/ и нажимает «Загрузить каталог». Ожидается список двух уроков и имя обслужившего API Pod. Браузер обращается к локальному origin, web отправляет запрос к Service api. Внутреннее имя кластера не попадает в адресную строку пользователя и не требует настройки DNS ноутбука.

Есть существенная особенность: port-forward к Service выбирает подходящий Pod и устанавливает временное соединение с ним. Это не полноценное моделирование всех сетевых путей через ClusterIP. Поэтому изменение имени API в ответе может происходить через прокси web, но изменение экземпляра самого web при таком доступе не доказывает распределение запросов между его репликами.

Не делайте вывод о равномерной балансировке по двум нажатиям кнопки. Соединения могут переиспользоваться, а алгоритм выбора адресата зависит от сетевого пути. Для этого урока достаточно другого свойства: frontend использует постоянное имя API, а смена конкретной копии не требует изменения HTML. Изучение распределения нагрузки начинается с такой устойчивой связи.

После урока web и API соединены через Service, но публичного входа у сайта нет. В следующем материале рассмотрим маршрутизацию браузерных запросов и место Gateway API, сохранив понятный локальный способ доступа.

Оглавление серии