Имеется 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
А теперь сравниваем:
- селектор Сервиса:
applicatonmap[
:gorush-server-redis]
- и тег у пода:
applicationmap[
: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 – теперь всё работает.