Kubernetes — это мощная платформа для оркестрации контейнеров, которая позволяет эффективно управлять развертыванием, масштабированием и эксплуатацией контейнерных приложений. Одним из ключевых компонентов Kubernetes является сервис (service), который обеспечивает доступ к приложениям, запущенным в подах, и управляет сетевым взаимодействием. В данной статье мы подробно познакомимся с типами сервисов в Kubernetes, рассмотрим их особенности и отличия. Также мы рассмотрим практические примеры для наглядной работы.
Так как мы будем рассматривать практическую часть, нам понадобится кластер Kubernetes. Арендовать готовый кластер можно с помощью сервиса Kubernetes в облаке.
Для начала арендуем кластер Kubernetes.
1) Авторизируемся в аккаунте при помощи логина или адреса электронной почты и пароля.
2) После успешной авторизации отобразится панель управления текущего проекта. Переходим в раздел «Kubernetes» в меню слева и нажимаем на кнопку «Создать».
3) Выбираем необходимый регион из списка доступных:
4) Далее необходимо выбрать тип кластера. На выбор доступно 3 типа — Dev, Base и Custom. В нашем случае нам будет достаточно Dev-конфигурации:
5) В качестве конфигурации для воркер-нод выберем минимальную, а именно одноядерный процессор, 2 ГБ оперативной памяти и 30 ГБ места на NVMe-диске:
6) Все остальные параметры можно оставить без изменений:
7) Для заказа кластера нажимаем на кнопку «Заказать»:
После заказа кластера он будет готов к использованию в течение пары минут. kubeconfig
для подключения к кластеру будут сгенерирован и доступен в раздел «Дашборд».
Сервис в Kubernetes — это объект, который используется для определения логических групп подов и правил доступа к ним. Поды в Kubernetes имеют временный (эфирный) характер: их можно создавать, удалять, перезапускать или перемещать между узлами кластера. Это делает прямой доступ к подам по их IP-адресам ненадежным. Сервисы решают эту проблему, предоставляя стабильный сетевой интерфейс для взаимодействия с подами. Каждый сервис получает виртуальный IP-адрес (ClusterIP) или DNS-имя, через которые можно обращаться к группе подов, даже если сами поды меняются.
Сервисы в Kubernetes классифицируются на несколько видов, каждый из которых разработан для конкретных задач и сценариев применения. Всего в Kubernetes присутствует пять типов сервисов:
Далее рассмотрим каждый тип сервиса более подробно, включая его описание, назначение особенности и конфигурацию.
Тип сервиса, который используется в Kubernetes по умолчанию. Сервис создает виртуальный IP-адрес внутри кластера, который используется для доступа к подам, соответствующим селектору сервиса. ClusterIP обеспечивает внутреннюю маршрутизацию трафика, то есть доступ возможен только внутри кластера без доступа во внешнюю сеть. Данный тип сервиса подходит для приложений, которые взаимодействуют только с другими компонентами внутри кластера, например, СУБД PostgreSQL или брокер сообщений Apache Kafka.
Используется виртуальный IP-адрес для сетевого взаимодействия только внутри кластера.
Балансировка трафика происходит между подами, которые соответствуют селектору сервиса.
Подходит для работы со внутренними сервисами — СУБД, API, брокеры сообщений.
В качестве примера создадим файл типа Deployment, в котором будет указан сервис ClusterIP вместе с контейнером, где будет запущен веб-сервер Nginx. Конфигурация приведена ниже:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-clusterip-deployment
namespace: service-clusterip
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26.0
ports:
- containerPort: 80
resources:
limits:
cpu: "0.5"
memory: "512Mi"
requests:
cpu: "0.2"
memory: "256Mi"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
- name: test-curl
image: curlimages/curl:8.12.0
command: ["/bin/sh", "-c", "while true; do curl http://nginx-clusterip-service; sleep 10; done"]
resources:
limits:
cpu: "0.2"
memory: "128Mi"
requests:
cpu: "0.1"
memory: "64Mi"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-clusterip-service
namespace: service-clusterip
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Для начала создадим новый namespace с именем service-clusterip
:
kubectl create namespace service-clusterip
Далее сохраняем конфигурацию выше в файл с именем nginx-test-deployment.yaml
и применяем ее:
kubectl apply -f nginx-test-deployment.yaml
Проверяем, что все объекты были созданы:
kubectl get all -n service-clusterip
В качестве теста выполним команду curl
из ранее созданного пода (в нашем примере это под с именем nginx-clusterip-deployment-54ffdb7c4b-87dsl
) на имя созданного ClusterIP сервиса — http://nginx-clusterip-service
:
kubectl exec -it nginx-clusterip-deployment-54ffdb7c4b-87dsl -n service-clusterip -- curl http://nginx-clusterip-service
Как можно увидеть на скриншоте выше, был получен ответ от сервиса. В этом примере сервис nginx-service
направляет трафик на поды с меткой app: nginx
далее сервис перенаправляет запросы на порт 80 подов. Внешний доступ отсутствует, что обеспечивает изоляцию.
Сервис типа NodePort открывает доступ к подам через порт на каждом узле кластера. Kubernetes выделяет порт из диапазона 30000–32767 (по умолчанию) и привязывает его к сервису. Это позволяет внешним клиентам обращаться к приложению через IP-адрес любого узла кластера и назначенный порт. NodePort часто используют для тестирования или в тех случаях, где требуется прямой доступ к сервису без использования внешнего балансировщика нагрузки.
Доступ к приложениям возможен через комбинацию IP-адреса узла кластера и номера порта.
Сервис также обладает внутренним адресом ClusterIP, что позволяет использовать его внутри кластера.
Подходит для временного доступа или для использования в кластерах без внешнего балансировщика нагрузки.
Предположим, у нас в кластере запущен под с веб-сервером Nginx. Для доступа к Nginx с локального компьютера создадим сервис типа NodePort. Используем конфигурацию ниже:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-nodeport-deployment
namespace: service-nodeport
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport-service
namespace: service-nodeport
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
type: NodePort
Для начала создадим новый namespace с именем service-nodeport
:
kubectl create namespace service-nodeport
Далее сохраняем конфигурацию выше в файл с именем nginx-nodeport-deployment.yaml
и применяем ее:
kubectl apply -f nginx-nodeport-deployment.yaml
Проверяем, что все объекты были созданы:
kubectl get all -n service-nodeport
В данном примере сервис открывает порт 30080 на всех узлах кластера на внешнем IP-адресе. Чтобы узнать внешний IP-адрес кластера, необходимо выполнить команду ниже:
kubectl get nodes -o wide
Если внешний IP-адрес узла — 5.129.210.247
(столбец EXTERNAL-IP
), то приложение будет доступно по адресу 5.129.210.247:30080
. Выполним команду curl
на внешний IP-адрес и порт 30080:
curl 5.129.210.247:30080
Трафик перенаправляется на порт 8080 подов. Этот подход удобен для быстрого тестирования, но не рекомендуется для использования в production-системах из-за ограничений безопасности и масштабируемости.
Обеспечивает доступ к приложениям в кластере через балансировщик нагрузки, созданный в облачной инфраструктуре. Этот тип сервиса автоматически присваивает внешний IP-адрес для доступа пользователей к приложению. LoadBalancer можно использовать для production-приложений, где важны высокая доступность и масштабируемость.
Создает внешний IP-адрес, доступный из внешней сети.
Интегрируется с облачными балансировщиками нагрузки.
Включает функциональность ClusterIP и NodePort.
В качестве примера создадим конфигурацию? в которой будет использоваться под с Nginx. Доступ будет осуществляться через внешний IP-адрес балансировщика:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-loadbalancer-deployment
namespace: service-loadbalancer
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer-service
namespace: service-loadbalancer
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
Для начала создадим новый namespace с именем service-loadbalancer
:
kubectl create namespace service-loadbalancer
Далее сохраняем конфигурацию выше в файл с именем nginx-loadbalancer-deployment.yaml
и применяем ее:
kubectl apply -f nginx-loadbalancer-deployment.yaml
Время создания внешнего балансировщика может занять 5-10 минут. Только после этого можно будет проверить, что все объекты были созданы:
kubectl get all -n service-loadbalancer
На скриншоте выше в разделе EXTERNAL-IP
появился внешний IP-адрес. Если выполнить curl
на данный IP-адрес, то вернется ответ от Nginx:
curl http://46.149.66.211:80
ExternalName — тип сервиса, который используется для создания ссылки на внешний ресурс, находящийся за пределами кластера Kubernetes, без необходимости создания локального прокси. Это позволяет направлять трафик к внешнему сервису, используя DNS-имя, без выделения ClusterIP или создания подов в кластере.
Работает как DNS-алиас для внешнего ресурса.
Не создает виртуальный IP-адрес.
Headless Service — это тип сервиса, который не привязан к ClusterIP. Он обеспечивает DNS-записи для всех подов, соответствующих указанному селектору. Такой сервис применяется для прямого взаимодействия с каждым подом, например, в распределенных системах, таких как базы данных или системы обработки сообщений.
Не создает виртуальный IP-адрес.
DNS-запрос возвращает IP-адреса всех подов.
Подходит для приложений, где требуется прямое взаимодействие с каждым подом.
В качестве примера создадим конфигурацию? в которой будет запущено два пода с Nginx. Ключевая особенность — установка clusterIP со значением None, при котором Kubernetes не будет выделять виртуальный IP-адрес. Вместо этого DNS будет возвращать IP-адреса всех подов, соответствующих селектору:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-headless-deployment
namespace: service-headless
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
namespace: service-headless
spec:
clusterIP: None
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Для начала создадим новый namespace с именем service-headless
:
kubectl create namespace service-headless
Далее сохраняем конфигурацию выше в файл с именем nginx-headless-deployment.yaml
и применяем ее:
kubectl apply -f nginx-headless-deployment.yaml
Проверяем, что все объекты были созданы:
kubectl get all -n service-headless
Далее проверяем, что все поды запущены. Также получим IP-адрес узлов кластера, на которых были запущены поды:
kubectl get pods -l app=nginx -o wide -n service-headless
Запустим временный под на основе образа curl
для выполнения запросов внутри кластера:
kubectl run curl-pod --image=curlimages/curl --restart=Never -n service-headless -- /bin/sh -c "sleep 3600"
Отправим запрос при помощи curl
на адрес ранее созданного сервиса (nginx-headless.service
). Имя сервиса записывается в формате <имя-сервиса>.<пространство-имен>.svc.cluster.local
. Имя сервиса можно узнать при помощи команды:
kubectl get service -n service-headless
В нашем примере имя сервиса выглядит как nginx-headless.service-headless.svc.cluster.local
.
kubectl exec -it curl-pod -n service-headless -- curl -v http://nginx-headless.service-headless.svc.cluster.local
Так как поды запущены на разных нодах, при выполнении команды IP-адреса всегда будет разными:
Для наглядности воспользуемся таблицей ниже чтобы детально сравнить все четыре типа сервисов:
ClusterIP |
NodePort |
LoadBalancer |
Headless Service |
|
Наличие виртуального IP адреса |
Да |
Да |
Да |
Нет |
Доступ из внешней сети |
Нет |
Да |
Да |
Нет |
Балансировка |
Да |
Да |
Да |
Нет |
DNS-записи |
Да |
Да |
Да |
Да |
Примеры использования |
Для внутренних сервисов |
Для тестирования |
Для использования в production-системах |
Для прямого доступа к подам |
Сервисы в Kubernetes предоставляют гибкие инструменты для управления сетевым взаимодействием внутри кластера. Каждый вид сервиса выполняет определенные функции: от организации внутренней связи между микросервисами до предоставления внешнего доступа или интеграции с внешними системами. Выбор подходящего типа сервиса определяется архитектурой приложения и требованиями к его доступности. Практические примеры, приведенные выше, демонстрируют, как настроить каждый тип сервиса для типичных сценариев. Понимание их особенностей позволяет эффективно управлять приложениями в Kubernetes и обеспечивать их надежность и масштабируемость.