Имеется 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 — теперь всё работает.