Урок 04 · Kubernetes на практике
Service
Что-то не запустилось или осталось непонятным? Задайте вопрос в комментариях к разбору этого урока в канале — разберёмся вместе.
В уроке 3 вы удаляли Pod и видели, как ReplicaSet создаёт новый взамен — с другим именем и, важно, с другим IP-адресом. Пока вы обращались к нему через kubectl port-forward, это было незаметно. Но что если к вашему сервису должен обращаться кто-то другой — другой Pod, или вы сами из браузера — и делать это не разово, а постоянно? Адрес, который меняется при каждом перезапуске, для этого не годится. Нужен Service — стабильный адрес, который не меняется никогда, сколько бы Pod'ов ни падало и пересоздавалось за ним.
Зачем нужен Service
У Service две задачи одновременно:
- Стабильный адрес. IP самого Service не меняется всё время его существования — в отличие от IP отдельных Pod'ов, которые эфемерны по определению (см. урок 3).
- Балансировка нагрузки. Если за Service стоит два Pod'а, как в нашем Deployment из урока 3, — Service сам решает, какому из них отдать очередной запрос, а вызывающему об этом думать не нужно вовсе.
Находит «свои» Pod'ы Service точно так же, как ReplicaSet в прошлом уроке — через label selector. Тот же принцип, только на этот раз ярлыки сопоставляет не контроллер, а сетевой объект.
ClusterIP и NodePort
У Service есть несколько типов — в этом уроке нужны только два:
- ClusterIP (по умолчанию) — адрес виден только изнутри кластера. Это основной способ, которым один Pod находит другой: в лоб, по IP, Pod'ы друг с другом никогда не говорят.
- NodePort — то же самое, что ClusterIP, плюс сервис дополнительно открывается на отдельном порту каждой Node, то есть становится доступен снаружи кластера. Через него мы и заглянем в свой сервис из браузера.
Полноценный внешний доступ по-настоящему принято настраивать через отдельный объект Ingress — он будет в уроке 7. NodePort сейчас — учебный короткий путь, чтобы своими глазами увидеть работающую балансировку, не забегая вперёд.
Практика: откройте сервис через стабильный адрес
Deployment из урока 3 (hello-fastapi, 2 реплики) должен быть уже запущен — проверьте: kubectl get pods.
-
Создайте файл
service.yaml:apiVersion: v1 kind: Service metadata: name: hello-fastapi spec: type: NodePort selector: app: hello-fastapi ports: - port: 8000 targetPort: 8000selectorздесь — тот же ярлыкapp: hello-fastapi, что вы указывали в Deployment из урока 3. Service найдёт по нему оба Pod'а автоматически. -
Примените манифест:
kubectl apply -f service.yaml -
Посмотрите, что получилось:
Уkubectl get serviceshello-fastapiпоявится свойCLUSTER-IP— тот самый стабильный адрес — и в колонкеPORT(S)будет виден дополнительный NodePort вида8000:3XXXX/TCP. -
minikube умеет сам находить правильный адрес и порт для NodePort-сервиса — не нужно искать их вручную:
Откройте полученный адрес с припискойminikube service hello-fastapi --url/docsв браузере. Это тот же интерфейс FastAPI, что и раньше, — но теперь вы обращаетесь не к конкретному Pod'у напрямую, а к Service.
kubectl get pods, удалите любой из двух Pod'ов (kubectl delete pod <имя>) и, не меняя ничего, обновите страницу /docs в браузере ещё раз. Она продолжит отвечать — хотя один из Pod'ов позади Service только что был полностью заменён на новый, с другим IP. В уроке 3 для этого пришлось бы заново набирать kubectl port-forward — команда была привязана к конкретному Pod'у. Service от такой привязки не страдает в принципе.
hello-fastapi, как в этом уроке) — Kubernetes сам резолвит его через встроенный DNS в актуальный адрес, даже если Pod'ы внутри полностью пересоздались.
Проверьте себя
Зачем нужен Service, если у Deployment уже есть Pod'ы, которые он поддерживает?
Напишите команду, которая применит манифест service.yaml к кластеру:
Напишите команду, которая выдаст доступный извне URL для NodePort-сервиса hello-fastapi в minikube: