Цели
- Узнать о сервисах в 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). Чтобы остановить приложение, потребуется также удалить и его деплоймент.
Когда всё готово, переходите к разделу Запуск нескольких экземпляров приложения.