Создание сервиса для открытия доступа к приложению

Узнайте о сервисах в Kubernetes. Разберитесь, какое отношение к сервисам имеют лейблы и селекторы. Сделайте приложение доступным вне кластера Kubernetes.

Цели

  • Узнать о сервисах в Kubernetes
  • Разобраться, какое отношение к сервисам имеют лейблы и селекторы
  • Сделать приложение доступным вне кластера Kubernetes

Обзор сервисов Kubernetes

Под — это расходный материал в Kubernetes. У них есть свой жизненный цикл. Когда рабочий узел прекращает работу, запущенные поды в узле также уничтожаются. После этого ReplicaSet попытается автоматически вернуть кластер обратно в требуемое состояние, создавая новые поды, чтобы поддержать работоспособность приложения. Другим примером жизни и смерти подов может служить бэкенд для обработки изображений с 3 репликами. Поскольку это взаимозаменяемые реплики, они не влияют на фронтенд-часть, даже если под был уничтожен и пересоздан. Тем не менее, каждый под в кластере Kubernetes имеет уникальный IP-адрес — даже под на одном и том же узле. Поэтому необходим способ автоматической координации изменений между подами, чтобы приложения продолжали функционировать.

Сервис (Service) в Kubernetes — это абстрактный объект, который определяет логический набор подов и политику доступа к ним. Сервисы создают слабую связь между подами, которые от них зависят. Сервис создаётся в формате YAML (рекомендуемый формат) или JSON, как и все остальные объекты в Kubernetes. Как правило, набор подов для сервиса определяется селектором лейблов (label selector) — ниже будет описано, в каких случаях может понадобиться сервис без указания селектора (selector) в его спецификации.

Хотя у каждого пода есть уникальный IP-адрес, эти IP-адреса не доступны за пределами кластера без использования сервиса. Сервисы позволяют приложениям принимать трафик. Сервисы могут быть по-разному открыты, в зависимости от значения поля type, указанного в спецификации сервиса:

  • ClusterIP (по умолчанию) — открывает доступ к сервису по внутреннему IP-адресу в кластере. Этот тип делает сервис доступным только внутри кластера;
  • NodePort — открывает сервис на том же порту каждого выбранного узла в кластере с помощью NAT. Делает сервис доступным вне кластера через <NodeIP>:<NodePort>. Является надмножеством ClusterIP.
  • LoadBalancer — создает внешний балансировщик нагрузки в текущем облаке (если это поддерживается) и назначает фиксированный внешний IP-адрес для сервиса. Является надмножеством NodePort.
  • ExternalName — открывает доступ к сервису по содержимому поля externalName (например, foo.bar.example.com), возвращая запись CNAME с его значением. При этом прокси не используется. Для этого типа требуется версия kube-dns 1.7+ или CoreDNS 0.0.8+.

Более подробно узнать о различных типах сервисах можно в руководстве Использование IP-порта источника. Также изучите Подключение приложений к сервисам.

Кроме этого, обратите внимание, что в некоторых случаях в сервисах не определяется selector в спецификации. Сервис без selector не будет создавать соответствующий эндпоинт (Endpoint). Таким образом, пользователь может вручную определить эндпоинты для сервиса. Ещё один возможный сценарий создания сервиса без селектора — это строгое использование type: ExternalName.

Краткое содержание

  • Открытие внешнего трафика для подов
  • Балансировка нагрузки трафика между подов
  • Использование лейблов

Сервис Kubernetes (Service) — это уровень абстракции, который определяет логический набор подов, перенаправляет внешний трафик, балансирует нагрузку и реализует service discovery для этих подов.


Сервисы и лейблы

Сервис направляет трафик через набор подов. Сервисы — это абстракция, позволяющая взаимозаменять поды Kubernetes без ущерба для работы приложения. Сервисы в Kubernetes находят и маршрутизируют трафик между зависимыми подами (это могут быть фронтенд- и бэкенд-компоненты приложения).

Сервисы для выбора набора подов используют лейблы и селекторы. Лейблы — пары ключ-значение, добавленные к объектам; например, они могут использоваться чтобы:

  • идентифицировать объекты для окружений разработки, тестирования и production;
  • встроить теги версии;
  • классифицировать объекты через теги.


Лейблы могут добавляться во время создания объектов или после этого. Они также могут быть изменены в любое время. Теперь давайте откроем доступ к приложению с помощью создания сервиса и добавим лейблы.

Создание нового сервиса

Давайте убедимся, что приложение работает. Воспользуемся командой kubectl get и посмотрим на существующие поды:

kubectl get pods

Если работающих подов нет, объекты из предыдущих разделов руководства была удалены. В таком случае вернитесь и повторно создайте деплоймент по инструкциям из раздела Использование kubectl для развёртывания приложения. После этого подождите несколько секунд и повторно запросите список подов. Как только увидите работающий под, можно следовать инструкциям ниже.

Далее посмотрим на список уже имеющихся сервисов в кластере:

kubectl get services

У нас есть сервис под названием kubernetes. Его по умолчанию создаёт minikube при запуске кластера. Чтобы создать новый сервис и сделать его доступным для внешних пользователей, воспользуемся командой expose с указанием типа сервиса NodePort в качестве параметра.

kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

Попробуем подкоманду get services ещё раз:

kubectl get services

Теперь у нас есть сервис под названием kubernetes-bootcamp. Мы можем увидеть, что у этого сервиса уникальный cluster-IP, внутренний порт и external-IP (IP соответствующего узла).

Чтобы выяснить, какой порт был открыт для внешнего мира (для сервиса со спецификацией type: NodePort), выполним подкоманду describe service:

kubectl describe services/kubernetes-bootcamp

Объявим переменную окружения NODE_PORT, в которую запишем значение назначенного порта узла:

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo "NODE_PORT=$NODE_PORT"

Теперь можно проверить, что приложение доступно вне кластера, с помощью curl, IP-адреса узла и порта, проброшенного вовне:

curl http://"$(minikube ip):$NODE_PORT"

Получим ответ от сервера. Сервис доступен внешнему миру.

Шаг 2: использование лейблов

Deployment автоматически создаёт лейбл для пода. Подкоманда describe deployment покажет его название (key):

kubectl describe deployment

Воспользуемся этим лейблом при выводе списка подов. Для этого вызовем команду kubectl get pods с флагом -l и нужными значениями лейблов в качестве параметра:

kubectl get pods -l app=kubernetes-bootcamp

То же самое можно делать при выводе списка сервисов:

kubectl get services -l app=kubernetes-bootcamp

Получим имя пода и запишем его в переменную окружения POD_NAME:

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
echo "Name of the Pod: $POD_NAME"

Чтобы добавить новый лейбл, воспользуемся подкомандой label, для которой укажем тип объекта, имя объекта и значение нового лейбла:

kubectl label pods "$POD_NAME" version=v1

Новый лейбл добавится к поду (мы зафиксировали версию приложения для этого пода), а мы сможем убедиться в этом с помощью команды describe pod:

kubectl describe pods "$POD_NAME"

Как видно, лейбл добавился к нашему поду. Теперь мы можем получить список всех подов, использующих новый лейбл:

kubectl get pods -l version=v1

Наш под будет в этом списке.

Удаление сервиса

Чтобы удалить сервис, воспользуйтесь подкомандой delete service. В ней могут указываться и лейблы:

kubectl delete service -l app=kubernetes-bootcamp

Убедитесь, что сервис удалился:

kubectl get services

Вывод подтвердит, что сервис был удалён. Убедиться в том, что удалился соответствующий маршрут для внешнего трафика, можно через curl к доступному ранее IP и порту:

curl http://"$(minikube ip):$NODE_PORT"

Так можно убедиться, что приложение более недоступно снаружи кластера. Проверить, что приложение всё ещё работает, можно через curl, который будет выполнен внутри пода:

kubectl exec -ti $POD_NAME -- curl http://localhost:8080

Мы увидим, что приложение запущено. Оно функционирует, потому что за его работу отвечает деплоймент (Deployment). Чтобы остановить приложение, потребуется также удалить и его деплоймент.

Когда всё готово, переходите к разделу Запуск нескольких экземпляров приложения.