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

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

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

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

 

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

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"

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

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

Ошибка «no endpoints available for service»

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

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

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

И пробуем curl:

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
}

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

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

И проверяем:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---
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.

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

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
...

Или:

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

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 создаётся:

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

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

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\»»,

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

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.

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