Практически все знают, что такое Kubernetes Service, но не все могут быть в курсе, что такое Endpoint, так как обычно он работает «за кулисами», и мы его не видим, аналогично тому, как мы пользуемся Deployment, но редко видим ReplicaSet-ы.
Содержание
Kubernetes Service
Итак, Service — это абстракция Kubernetes, которая, используя labels, выбирает поды, на которые следует перенаправлять трафик, см. Kubernetes: ClusterIP vs NodePort vs LoadBalancer, Services и Ingress — обзор, примеры и Kubernetes: Service, балансировка нагрузки, kube-proxy и iptables:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376
Как только в кластере появляется новый под, лейблы которого совпадают с селектором Сервиса, в данном примере app=MyApp
— Service начнёт роутить трафик на него.
Реализуется это путём добавления IP-адреса пода в список Endpoints, который используется Сервисом.
Создадим простейший пример:
--- apiVersion: v1 kind: Pod metadata: name: nginx-pod labels: app: nginx spec: containers: - name: nginx-container image: nginx ports: - name: web containerPort: 80 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: nginx-svc spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80
Тут создаётся под с NGINX, и для него — Сервис с дефолтным типом ClusterIP
.
Создаём их:
[simterm]
$ kubectl apply -f svc-example.yaml pod/nginx-pod created service/nginx-svc created
[/simterm]
Проверяем Сервис:
[simterm]
$ kubectl get service nginx-svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-svc ClusterIP 172.20.69.253 <none> 80/TCP 26s
[/simterm]
Kubernetes Endpoints
Теперь рассмотрим этот Сервис детальнее:
[simterm]
$ kubectl describe service nginx-svc Name: nginx-svc Namespace: default Labels: <none> Annotations: <none> Selector: app=nginx Type: ClusterIP IP Families: <none> IP: 172.20.69.253 IPs: <none> Port: <unset> 80/TCP TargetPort: 80/TCP Endpoints: 10.21.56.143:80
[/simterm]
В конце мы собственно и видим Endpoints этого сервиса — IP-адрес пода.
Проверим под:
[simterm]
$ kubectl describe pod nginx-pod Name: nginx-pod Namespace: default Priority: 0 Node: ip-10-21-49-33.us-east-2.compute.internal/10.21.49.33 Start Time: Sat, 13 Mar 2021 08:37:55 +0200 Labels: app=nginx Annotations: kubernetes.io/psp: eks.privileged Status: Running IP: 10.21.56.143 ...
[/simterm]
Вот и наш IP.
А теперь проверим ендпоинты, которые являются отдельными объектами API-сервера — Endpoints, и с которыми можно работать так же, как с Services и Pods:
[simterm]
$ kubectl get endpoints nginx-svc NAME ENDPOINTS AGE nginx-svc 10.21.56.143:80 18m
[/simterm]
Если мы добавим ещё один под с той же лейблой, в Deployment или просто опишем вторым объектом — он будет добавлен в этот же Ендпоинт:
--- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-container image: nginx ports: - name: web containerPort: 80 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: nginx-svc spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80
Создаём:
[simterm]
$ kubectl apply -f svc-example.yaml deployment.apps/nginx-deploy created service/nginx-svc unchanged
[/simterm]
И проверяем ендпоинт:
[simterm]
$ kubectl get endpoints nginx-svc NAME ENDPOINTS AGE nginx-svc 10.21.37.55:80,10.21.54.174:80,10.21.56.143:80 21m
[/simterm]
Тут у нас остался старый под 10.21.56.143:80, и появилось два новых, которые указаны в replicas
нашего деплоймента.
Найдём из используя --selector
— аналогично Сервис ищет поды для добавления в Ендпоинты:
[simterm]
$ kubectl get pod --selector=app=nginx -o wide NAME READY STATUS RESTARTS AGE IP nginx-deploy-7fcd954c94-gbm6d 1/1 Running 0 2m28s 10.21.54.174 nginx-deploy-7fcd954c94-mg8kr 1/1 Running 0 2m28s 10.21.37.55 nginx-pod 1/1 Running 0 23m 10.21.56.143
[/simterm]
Custom Endpoint
Кроме ендпоинтов подов, мы можем создать кастомный ендпоинт, который будет слать трафик на любой ресурс.
К примеру, опишем такой сервис:
kind: Service apiVersion: v1 metadata: name: external-svc spec: ports: - name: web protocol: TCP port: 80 targetPort: 80
Обратите внимание, что тут мы не описываем selector
.
К нему описываем Endpoints:
kind: Endpoints apiVersion: v1 metadata: name: external-svc subsets: - addresses: - ip: 139.59.205.180 ports: - port: 80 name: web
Тут:
name
: должно быть таким же, как у Serviceaddresses
: адрес, на который шлём трафик, в этом примере — IP адрес сервера в DigitalOcean, на котором работает блог rtfm.co.ua, можно указать несколько — тогда Service будет выполнять load balancing между ними, как описано в Kubernetes: Service, балансировка нагрузки, kube-proxy и iptablesports.port
иports.name
такие же, как у Service
Создаём:
[simterm]
$ kubectl apply -f external-endpoint.yaml service/external-svc created endpoints/external-svc created
[/simterm]
Проверяем Service и его Endpoints:
[simterm]
$ kubectl describe svc external-svc Name: external-svc Namespace: default Labels: <none> Annotations: <none> Selector: <none> Type: ClusterIP IP Families: <none> IP: 172.20.45.77 IPs: <none> Port: web 80/TCP TargetPort: 80/TCP Endpoints: 139.59.205.180:80
[/simterm]
Запускаем для проверки под:
[simterm]
$ kubectl run pod --rm -i --tty --image ubuntu -- bash
[/simterm]
Устанавливаем в нём curl
:
[simterm]
root@pod:/# apt update && apt -y install curl
[/simterm]
И проверяем по имени сервиса:
[simterm]
root@pod:/# curl -Ls external-svc | grep \<title\> <title>RTFM: Linux, DevOps, and system administration</title>
[/simterm]
Или по его FQDN:
[simterm]
root@pod:/# curl -Ls external-svc.default.svc.cluster.local | grep \<title\> <title>RTFM: Linux, DevOps, and system administration</title>
[/simterm]
externalName
Другой вариант для доступа к внешним ресурсам — использовать Service с типом externalName
:
--- apiVersion: v1 kind: Service metadata: name: rtfm-service spec: ports: - port: 80 type: ExternalName externalName: rtfm.co.ua
Применяем, и проверяем:
[simterm]
root@pod:/# curl -Ls rtfm-service | grep \<title\> <title>RTFM: Linux, DevOps, and system administration</title>
[/simterm]
Готово.