Kubernetes: Сервисы

Services of K8s

Posted by Vrublevskit Vitaliy on August 26, 2021 · 5 mins read

Учим наши приложения общаться

Сервисы(service) созданы как некая точка “обмена” данными с подами, как внутри кластера так и для общения вне кластера. Вашим клиентам и внутреним приложениям не важно знать сколько копий приложения(pod) в данный момент существует и где они находятся (на одном или множестве серверов).

Создавая сервис вы фиксируете один постоянный IP(Internet Protocol) по которому любые обращения будут перенаправлены в нужное приложение, адрес сервиса не меняется даже если IP пода был изменен по причине его отказа\перемещения и тп. Более того, создавая службу для внутреннего использования в вашем кластере вы можете обращаться к приложениям используя переменные виртуального окружения или DNS(Domain Name System)

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

Службы(services) как и многие сущности в кубернетес используют метки(labels) в качестве выбора нужных подов(pod), давайте убедимся в этом, создав абстракцию Deployment которая управляет 2 подами с простым приложением возвращающим нам hostname:

# Создаем Deployment с нашим приложением
kubectl create deploy --image zet694/simple-web-app:latest my-app
# Масштабируем его до 2 едениц
kubectl scale --replicas 2 deployment/my-app
# Проверяем готовность пода
kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
my-app-85845fd898-4b4pk   1/1     Running   0          21s
my-app-85845fd898-v4lk4   1/1     Running   0          12s

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

# Создаем Сервис 
kubectl expose deploy my-app --name=my-svc --port=8888 --target-port=8888 --type=NodePort
Теперь убедимся что сервис создан:
# Создаем Сервис 
kubectl get service
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)         
my-svc       NodePort    10.43.28.213   <none>        8888:31052/TCP

Сейчас архитектура нашего приложения выглядит так:

Пример обращения пользователя к приложению через сервис

Пример обращения пользователя к приложению через сервис

Далее вы убедимся с использованием curl что мы действительно может обратиться к приложению:

$ curl localhost:31052
Hostname:  my-app-85845fd898-v4lk4
$ curl localhost:31052
Hostname:  my-app-85845fd898-4b4pk

Внимание! Скорее всего вам будет выдан другой порт,так как кубернетес генерирует их случайным образом в диапозоне от 30000 до 32767, обратите внимание на вывод команды kubectl get service что бы узнать необходимый вам порт.

Иследование сервисов

После создания сервиса my-svc, мы видим ее внутрений IP(колонка CLUSTER-IP), давайте создаим еще один “под” и обратимся к сервису my-svc изнутри кластера. Воспокльзуемся образом для отладки сетевых проблем nicolaka/netshoot, данный образ содержит в себе все необходимые утилиты для отладки.

Запускает еще один ПОД

$ kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash
Теперь находясь внутри сервиса мы можем заметить некоторые интересные моменты, например кубрнетес добавил наш сервис в виде переменных окружения, взглянем на них:
$ printenv | sort
HOME=/root
HOSTNAME=netshoot
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
MY_SVC_PORT=tcp://10.98.169.198:8888
MY_SVC_PORT_8888_TCP=tcp://10.98.169.198:8888
MY_SVC_PORT_8888_TCP_ADDR=10.98.169.198
MY_SVC_PORT_8888_TCP_PORT=8888
MY_SVC_PORT_8888_TCP_PROTO=tcp
MY_SVC_SERVICE_HOST=10.98.169.198
MY_SVC_SERVICE_PORT=8888
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/root
SHLVL=0
TERM=xterm
_=/bin/printenv

Так как кубернетес добавляет в переменные виртуального окружения данные всех наших сервисов, в том числе созданого нами my-svcВсе переменные созданого сервиса начинаются на MY_SVC_ попробуем обратиться к сервису используя переменные виртуального окружения:

$ curl $MY_SVC_SERVICE_HOST:$MY_SVC_SERVICE_PORT
Hostname:  my-app-85845fd898-ll5r8
$ curl $MY_SVC_SERVICE_HOST:$MY_SVC_SERVICE_PORT
Hostname:  my-app-85845fd898-wh4l6
$ curl $MY_SVC_SERVICE_HOST:$MY_SVC_SERVICE_PORT
Hostname:  my-app-85845fd898-wh4l6

Как мы видим сервис перенаправляет наши запросы на нужные поды. Помимо использованная переменных виртуального окружения которые добавляет кубернетес в каждый наш “под”, мы можем использовать имя сервиса которое указали при создании, правда в этом случае, протокол и порт необходимо добавить самостоятельно(либо воскользоваться переменной окружения):

$ curl http://my-svc:8888
Hostname:  my-app-85845fd898-ll5r8
$ curl http://my-svc:8888
Hostname:  my-app-85845fd898-wh4l6

Этот вариант наиболее часто используется, так как представляет собой самый простой вариант при использовании “шаблонизаторов” вроде Helm. Внимание! Не пытайтесь “пинговать” (Использовать ping команду), в контексте сервисов это не работает.