Thank you for reading this post, don't forget to subscribe!
Итак, Service — это абстракция Kubernetes, которая, используя labels, выбирает поды, на которые следует перенаправлять трафик
1 2 3 4 5 6 7 8 9 10 11 |
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 |
Как только в кластере появляется новый под, лейблы которого совпадают с селектором Сервиса, в данном примере app=MyApp — Service начнёт роутить трафик на него.
Реализуется это путём добавления IP-адреса пода в список Endpoints, который используется Сервисом.
Создадим простейший пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
--- 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
.
Создаём их:
kubectl apply -f svc-example.yaml
Проверяем Сервис:
1 2 3 |
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 |
Kubernetes Endpoints
Теперь рассмотрим этот Сервис детальнее:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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 |
В конце мы собственно и видим Endpoints этого сервиса — IP-адрес пода.
Проверим под:
1 2 3 4 5 6 7 8 9 10 |
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 |
Вот и наш IP.
А теперь проверим ендпоинты, которые являются отдельными объектами API-сервера — Endpoints, и с которыми можно работать так же, как с Services и Pods:
1 2 3 |
kubectl get endpoints nginx-svc NAME ENDPOINTS AGE nginx-svc 10.21.56.143:80 18m |
Если мы добавим ещё один под с той же лейблой, в Deployment или просто опишем вторым объектом — он будет добавлен в этот же Ендпоинт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
--- 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 |
kubectl apply -f svc-example.yaml
И проверяем ендпоинт:
1 2 3 |
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 |
Тут у нас остался старый под 10.21.56.143:80, и появилось два новых, которые указаны в replicas
нашего деплоймента.
Найдём их используя --selector
— аналогично Сервис ищет поды для добавления в Ендпоинты:
1 2 3 4 5 |
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 |
Custom Endpoint
Кроме ендпоинтов подов, мы можем создать кастомный ендпоинт, который будет слать трафик на любой ресурс.
К примеру, опишем такой сервис:
1 2 3 4 5 6 7 8 9 10 |
kind: Service apiVersion: v1 metadata: name: external-svc spec: ports: - name: web protocol: TCP port: 80 targetPort: 80 |
Обратите внимание, что тут мы не описываем selector
.
К нему описываем Endpoints:
1 2 3 4 5 6 7 8 9 10 |
kind: Endpoints apiVersion: v1 metadata: name: external-svc subsets: - addresses: - ip: 13.59.20.180 ports: - port: 80 name: web |
Тут:
name
: должно быть таким же, как у Serviceaddresses
: адрес, на который шлём трафик, в этом примере — IP адрес сервера в DigitalOcean, на котором работает блог можно указать несколько — тогда Service будет выполнять load balancing между нимиports.port
иports.name
такие же, как у Service
Создаём:
kubectl apply -f external-endpoint.yaml
Проверяем Service и его Endpoints:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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: 13.59.20.180:80 |
Запускаем для проверки под:
kubectl run pod --rm -i --tty --image ubuntu -- bash
Устанавливаем в нём curl
:
root@pod:/# apt update && apt -y install curl
И проверяем по имени сервиса:
externalName
Другой вариант для доступа к внешним ресурсам — использовать Service с типом externalName
:
1 2 3 4 5 6 7 8 9 10 |
--- apiVersion: v1 kind: Service metadata: name: test-service spec: ports: - port: 80 type: ExternalName externalName: test.co.ua |
Применяем, и проверяем: