Kubernetes: запуск metrics-server в AWS EKS для Kubernetes Pod AutoScaler

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

Предполагается, что AWS EKS уже создан, и имеет рабочие ноды.

Ниже – выполним настройку подключения к кластеру, создадим тестовый деплоймент с HPA – Kubernetes Horizontal Pod AutoScaler, и попробуем получить данные об используемых ресурсах с помощью kubectl top.

Kubernetes cluster

Создаём тестовый кластер:

[simterm]

$ eksctl create cluster --profile arseniy --region us-east-2 --name eks-dev-1
...
[ℹ]  node "ip-192-168-54-141.us-east-2.compute.internal" is ready
[ℹ]  node "ip-192-168-85-24.us-east-2.compute.internal" is ready
[ℹ]  kubectl command should work with "/home/setevoy/.kube/config", try 'kubectl get nodes'
[✔]  EKS cluster "eks-dev-1" in "us-east-2" region is ready

[/simterm]

Переключаемся на него.

Kubernetes cluster context

Настраиваем kubectl:

[simterm]

$ aws eks --profile arseniy --region us-east-2 update-kubeconfig --name eks-dev-1
Added new context arn:aws:eks:us-east-2:534***385:cluster/eks-dev-1 to /home/setevoy/.kube/config

[/simterm]

Проверяем доступные в аккаунте и регионе кластера EKS:

[simterm]

$ aws eks --profile arseniy --region us-east-2 list-clusters --output text
CLUSTERS        eksctl-bttrm-eks-production-1
CLUSTERS        mobilebackend-dev-eks-0-cluster
CLUSTERS        eks-dev-1

[/simterm]

Проверяем текущий профиль:

[simterm]

$ kubectl config current-context 
arn:aws:eks:us-east-2:534***385:cluster/eks-dev-1

[/simterm]

aws eks уже настроил и подключил нам новый профиль kubectl.

При необходимости – находим настроенные профили:

[simterm]

$ kubectl config get-contexts

[/simterm]

И переключаемся на нужный:

[simterm]

$ kubectl config use-context arn:aws:eks:us-east-2:534***385:cluster/eks-dev-1
Switched to context "arn:aws:eks:us-east-2:534***385:cluster/eks-dev-1".

[/simterm]

Deployment

Для тестов используем деплоймент с AutoScaler.

HPA использует метрики, полученные от mertics-server для собра данных о нагрузке на нодах и подах для принятия решения о необходимости скейлинга подов.

Создаём HPA и деплоймент:

---
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: hello-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hello
  minReplicas: 1
  maxReplicas: 2
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: hello
          image: gcr.io/google-samples/node-hello:1.0
          resources:
            limits:
              cpu: "0.1"
            requests:
              cpu: "0.1"

Деплоим:

[simterm]

$ kubectl apply -f example-deployment.yml 
horizontalpodautoscaler.autoscaling/hello-hpa created
deployment.apps/hello created

[/simterm]

Проверяем:

[simterm]

$ kubectl get hpa
NAME        REFERENCE          TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
hello-hpa   Deployment/hello   <unknown>/80%   1         2         1          26s

[/simterm]

HPA – TARGETS <TARGETS> и unable to get metrics

Если проверить состояние HPA сейчас – то увидим, что он не видит текущего состояния своих таргетов (подов в  деплойментах):

[simterm]

$ kubectl get hpa
NAME        REFERENCE          TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
hello-hpa   Deployment/hello   <unknown>/80%   1         2         1          26s

[/simterm]

В Conditions и Events можем увидеть более детальные сообщения об ошибках:

[simterm]

$ kubectl describe hpa hello-hpa
...
Conditions:
  Type           Status  Reason                   Message
  ----           ------  ------                   -------
  AbleToScale    True    SucceededGetScale        the HPA controller was able to get the target's current scale
  ScalingActive  False   FailedGetResourceMetric  the HPA was unable to compute the replica count: unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server could not find the requested resource
 (get pods.metrics.k8s.io)
...
Events:
  Type     Reason                        Age                From                       Message
  ----     ------                        ----               ----                       -------
  Warning  FailedGetResourceMetric       12s (x3 over 43s)  horizontal-pod-autoscaler  unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server could not find the requested resource (get pods.metrics.k8s.io)
  Warning  FailedComputeMetricsReplicas  12s (x3 over 43s)  horizontal-pod-autoscaler  failed to get cpu utilization: unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server could not find the requested resource (get pods.metrics.k8s.io)

[/simterm]

Собственно,  вот наша ошибка:

failed to get cpu utilization: unable to get metrics for resource cpu

Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)

Кроме того, при попытке выполнить сейчас top для подов или нод – Kubernetes сообщит:

[simterm]

$ kubectl top node
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)
$ kubectl top pod
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)

[/simterm]

Что бы top мог отобразить данные об испуользуемых ресурсах – он пытается обратиться к Heapster, см. исходный код:

...
o.Client = metricsutil.NewHeapsterMetricsClient(clientset.CoreV1(), o.HeapsterOptions.Namespace, o.HeapsterOptions.Scheme, o.HeapsterOptions.Service, o.HeapsterOptions.Port)
...

А Heaspter – устаревший сервис, который ранее использовался для сбора метрик.

Сейчас для получения метрик об используемых CPU и памяти – используем metrics-server, который заменил Heapster.

Запуск metrics-server

Клонируем репозиторий:

[simterm]

$ git clone https://github.com/kubernetes-sigs/metrics-server.git
$ cd metrics-server/

[/simterm]

Настройки для AWS EKS

Что бы metrics-сервер мог собирать метрики в AWS Elastic Kubernetes Service кластере – редактируем его деплоймент deploy/kubernetes/metrics-server-deployment.yaml, и добавляем command с запуском сервера с четырьмя аргументами:

...
        command:
          - /metrics-server
          - --logtostderr
          - --kubelet-insecure-tls=true
          - --kubelet-preferred-address-types=InternalIP
          - --v=2
...
  • kubelet-insecure-tls – не выполнять проверку CA сертификата kubelet-клиента на нодах
  • kubelet-preferred-address-types – как выполнять обращение к нодам и подам – по Hostname, InternalDNS, InternalIP, ExternalDNS или ExternalIP, для EKS задаём InternalIP
  • v=2 – уровень детализации логов

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

[simterm]

$ kubectl apply -f deploy/kubernetes/
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
serviceaccount/metrics-server created
deployment.apps/metrics-server created
service/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created

[/simterm]

Проверяем:

[simterm]

$ kubectl -n kube-system get pod
NAME                              READY   STATUS    RESTARTS   AGE
aws-node-mt9pq                    1/1     Running   0          2m5s
aws-node-rl7t2                    1/1     Running   0          2m2s
coredns-74dd858ddc-xmrhj          1/1     Running   0          7m33s
coredns-74dd858ddc-xpcwx          1/1     Running   0          7m33s
kube-proxy-b85rv                  1/1     Running   0          2m5s
kube-proxy-n647l                  1/1     Running   0          2m2s
metrics-server-546565fdc9-56xwl   1/1     Running   0          6s

[/simterm]

Или так:

[simterm]

$ kubectl get apiservices | grep metr
v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        91s

[/simterm]

Проверяем его логи:

[simterm]

$ kubectl -n kube-system logs -f metrics-server-546565fdc9-qswck
I0215 11:59:05.896014       1 serving.go:312] Generated self-signed cert (/tmp/apiserver.crt, /tmp/apiserver.key)
I0215 11:59:06.439725       1 manager.go:95] Scraping metrics from 0 sources
I0215 11:59:06.439749       1 manager.go:148] ScrapeMetrics: time: 2.728µs, nodes: 0, pods: 0
I0215 11:59:06.450735       1 secure_serving.go:116] Serving securely on [::]:4443
E0215 11:59:10.096632       1 reststorage.go:160] unable to fetch pod metrics for pod default/hello-7d6c85c755-r88xn: no metrics known for pod
E0215 11:59:25.109059       1 reststorage.go:160] unable to fetch pod metrics for pod default/hello-7d6c85c755-r88xn: no metrics known for pod

[/simterm]

Пробуем top ноды:

[simterm]

$ kubectl top node
error: metrics not available yet

[/simterm]

И под:

[simterm]

$ kubectl top pod
W0215 13:59:58.319317 4014051 top_pod.go:259] Metrics not available for pod default/hello-7d6c85c755-r88xn, age: 4m51.319306547s
error: Metrics not available for pod default/hello-7d6c85c755-r88xn, age: 4m51.319306547s

[/simterm]

Через 1-2 минуты в логах metrics-server:

[simterm]

I0215 12:00:06.439839       1 manager.go:95] Scraping metrics from 2 sources
I0215 12:00:06.447003       1 manager.go:120] Querying source: kubelet_summary:ip-192-168-54-141.us-east-2.compute.internal
I0215 12:00:06.450994       1 manager.go:120] Querying source: kubelet_summary:ip-192-168-85-24.us-east-2.compute.internal
I0215 12:00:06.480781       1 manager.go:148] ScrapeMetrics: time: 40.886465ms, nodes: 2, pods: 8
I0215 12:01:06.439817       1 manager.go:95] Scraping metrics from 2 sources

[/simterm]

Пробуем ещё раз top:

[simterm]

$ kubectl top node
NAME                                           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
ip-192-168-54-141.us-east-2.compute.internal   25m          1%     406Mi           5%
ip-192-168-85-24.us-east-2.compute.internal    26m          1%     358Mi           4%

[/simterm]

Под:

[simterm]

$ kubectl top pod
NAME                     CPU(cores)   MEMORY(bytes)
hello-7d6c85c755-r88xn   0m           8Mi

[/simterm]

И проверим HPA:

[simterm]

$ kubectl describe hpa hello-hpa
...
Conditions:
  Type            Status  Reason            Message
  ----            ------  ------            -------
  AbleToScale     True    ReadyForNewScale  recommended size matches current size
  ScalingActive   True    ValidMetricFound  the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
  ScalingLimited  True    TooFewReplicas    the desired replica count is more than the maximum replica count
Events:
  Type     Reason                        Age                     From                       Message
  ----     ------                        ----                    ----                       -------
  Warning  FailedComputeMetricsReplicas  4m23s (x12 over 7m10s)  horizontal-pod-autoscaler  failed to get cpu utilization: unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server could not find the requested resource (get pods.metrics.k8s.io)
  Warning  FailedGetResourceMetric       4m8s (x13 over 7m10s)   horizontal-pod-autoscaler  unable to get metrics for resource cpu: unable to fetch metrics from resource metrics API: the server could not find the requested resource (get pods.metrics.k8s.io)

[/simterm]

Тут обращаем внимание на:

  • the HPA was able to successfully calculate a replica count from cpu resource utilization – HPA смог получить метрики
  • unable to get metrics for resource cpu – смотрим Age, и счётчик событий (х13), должен перестать расти

Собственно, на этом всё.

Ниже – ещё одна достаточно часто встречающая проблема при настройке HPA, связанная с метриками.

HPA was unable to compute the replica count: missing request for cpu

Иногда HPA может сообщать об ошибках вида:

[simterm]

$ kubectl describe hpa hello-hpa
...
Conditions:
  Type            Status  Reason                   Message
  ----            ------  ------                   -------
  AbleToScale     True    SucceededGetScale        the HPA controller was able to get the target's current scale
  ScalingActive   False   FailedGetResourceMetric  the HPA was unable to compute the replica count: missing request for cpu
...
  Warning  FailedGetResourceMetric       2s (x2 over 17s)      horizontal-pod-autoscaler  missing request for cpu

[/simterm]

Возникает она при отсутствии resources и requests в шаблоне пода – тут они закомментированы, и деплоймент был обновлён:

...
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: hello
          image: gcr.io/google-samples/node-hello:1.0
#          resources:
#            limits:
#              cpu: "0.1"
#            requests:
#              cpu: "0.1"

Возвращаем обратно requests – и всё работает.

Готово.