Kubernetes: 503 no endpoints available for service – причины и решения

Автор: | 15/06/2020
 

Имеется Redis, для которого создан Service типа ClusterIP.

К этому Редису должны ходить поды этого неймспейса (Gorush).

 

Проблема в том, что поды с Gorush подключиться к Redis по адресу gorush-server-redis-svc:6379 не могут – отваливаются с ошибкой “Can’t connect redis server: connection refused“:

[simterm]

$ kk -n gorush-test logs gorush-server-55cd659dff-9wfbw
time="2020/06/12 - 13:44:02" level=debug msg="Init App Status Engine as redis"
2020/06/12 13:44:03 Can't connect redis server: dial tcp 172.20.198.35:6379: connect: connection refused
time="2020/06/12 - 13:44:03" level=error msg="storage error: dial tcp 172.20.198.35:6379: connect: connection refused"

[/simterm]

Проверяем наличие сервиса:

[simterm]

$ kk -n gorush-test get svc
NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP                                                                       PORT(S)        AGE
gorush-server-redis-svc   ClusterIP      172.20.198.35    <none>                                                                            6379/TCP       102s

[/simterm]

Ошибка “no endpoints available for service”

Попробуем подключиться к сервису напрямую, с рабочей машины, как описывалось в посте Kubernetes: ClusterIP vs NodePort vs LoadBalancer, Services и Ingress — обзор, примеры.

Запускаем прокси:

[simterm]

$ kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080

[/simterm]

И пробуем curl:

[simterm]

$ curl localhost:8080/api/v1/namespaces/gorush-test/services/gorush-server-redis-svc/proxy
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "no endpoints available for service \"gorush-server-redis-svc\"",
  "reason": "ServiceUnavailable",
  "code": 503
}

[/simterm]

Хотя под с Redis запущен, работает, и подключения принимает – проверяем с помощью port-forwadrd, запускаем его:

[simterm]

$ kk -n gorush-test port-forward gorush-server-redis-6566764cb7-9s8qk 6379:6379
Forwarding from 127.0.0.1:6379 -> 6379
Forwarding from [::1]:6379 -> 6379

[/simterm]

И проверяем:

[simterm]

$ curl localhost:6379
curl: (1) Received HTTP/0.9 when not allowed

[/simterm]

Всё хорошо, но почему не работает через Service?

И почему ругается на отсутствующий ендпоинт?

Проверяем ендпоинты:

[simterm]

$ kk -n gorush-test get endpoints
NAME                      ENDPOINTS   AGE
gorush-server-redis-svc   <none>      3m3s

[/simterm]

В самом деле – <none>.

Причина #1: labels mismatch

Проверяем какие лейлбы использует Сервис для выбора подов – находим его selector:

[simterm]

$ kk -n gorush-test get svc gorush-server-redis-svc -o jsonpath={.spec.selector}
map[applicaton:gorush-server-redis]

[/simterm]

Или вот как он выглядит в манифесте:

apiVersion: v1
kind: Service
metadata:
  name: {{ .Chart.Name }}-redis-svc
  labels:
    application: {{ .Chart.Name }}-redis-svc
spec:
  ports:
  - port: 6379
  selector:
    applicaton: {{ .Chart.Name }}-redis

И проверяем какие лейлбы заданы самому поду:

[simterm]

$ kk -n gorush-test get deploy gorush-server-redis -o jsonpath={.spec.template.metadata.labels}
map[application:gorush-server-redis]

[/simterm]

Деплоймент пода выглядит так:

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}-redis
spec:
  replicas: 1
  template:
    metadata:
      labels:
        application: {{ .Chart.Name }}-redis
    spec:
      containers:
      - name: redis-master
        image: redis
        ports:
        - containerPort: 6379

А теперь сравниваем:

  • селектор Сервиса: map[applicaton:gorush-server-redis]
  • и тег у пода: map[application:gorush-server-redis]

И видим опечатку – applicaTOn и applicaTIOn.

Соответственно, сам Service создавался, потому что сам манифест синтактически верен, но из-за того, что искал по неправильному тегу – не мог найти поды, которые стали бы бекендом для ендпоинта этого сервиса, и Service некуда было перенаправлять трафик, что и приводило к ошибке 503.

Исправляем селектор, передеплоиваем, проверяем сервис:

[simterm]

$ curl -Lkk -n gorush-test describe svc gorush-server-redis-svc
Name:              gorush-server-redis-svc
Namespace:         gorush-test
Labels:            app.kubernetes.io/managed-by=Helm
                   application=gorush-server-redis
Annotations:       meta.helm.sh/release-name: gorush-server
                   meta.helm.sh/release-namespace: gorush-test
Selector:          application=gorush-server-redis
Type:              ClusterIP
IP:                172.20.124.195
Port:              <unset>  6379/TCP
TargetPort:        6379/TCP
Endpoints:         10.3.47.94:6379
...

[/simterm]

Или:

[simterm]

$ kk -n gorush-test get endpoints
NAME                      ENDPOINTS         AGE
gorush-server-redis-svc   10.3.47.94:6379   77m

[/simterm]

Endpoints: 10.3.47.94:6379 появился – готово, всё завелось.

Причина #2: named port

Аналогичная же ошибка может возникнуть при использовании именованных портов:

apiVersion: v1
kind: Service
metadata:
  name: gorush
  labels:
    app: gorush
    tier: frontend
spec:
  selector:
    app: gorush
    tier: frontend
  type: LoadBalancer
  ports:
  - name: gorush
    protocol: TCP
    port: 80
    targetPort: 8088

ports: – name: gorush

При этом сам endpoint создаётся:

[simterm]

$ kubectl -n eks-dev-1-gorush get ep
NAME ENDPOINTS AGE
gorush 10.3.35.14:8088 44m

[/simterm]

Но при обращении к API-серверу – он возвращает нам всё ту же ошибку “message”: “no endpoints available for service \”gorush\””:

[simterm]

$ curl -sL localhost:8080/api/v1/namespaces/eks-dev-1-gorush/services/gorush/proxy/metrics | grep gorush | head
“message”: “no endpoints available for service \”gorush\””,

[/simterm]

В данном случае причина в том, что в API-запросе не указано имя порта, которое указывается через “:” :

[simterm]

$ curl -sL localhost:8080/api/v1/namespaces/eks-dev-1-gorush/services/gorush:gorush/proxy/metrics | head
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile=”0″} 9.194e-06
go_gc_duration_seconds{quantile=”0.25″} 1.2092e-05
go_gc_duration_seconds{quantile=”0.5″} 2.1812e-05
go_gc_duration_seconds{quantile=”0.75″} 5.1794e-05
go_gc_duration_seconds{quantile=”1″} 0.000145631
go_gc_duration_seconds_sum 0.001080551
go_gc_duration_seconds_count 32
# HELP go_goroutines Number of goroutines that currently exist.

[/simterm]

services/gorush:gorush – теперь всё работает.