KRR — ваш личный советник по ресурсам в Kubernetes

KRR (Kubernetes Resource Recommender) — это CLI-инструмент для оптимизации использования ресурсов в Kubernetes. Он анализирует метрики Pod’ов, собираемые в Prometheus, и предлагает оптимальные настройки requests и limits для CPU и памяти. Это помогает снизить расходы на облачные ресурсы и повысить производительность приложений. В этом посте будет рассмотрен периодический запуск krr в kubernetes с сохранением в html формат для удобного отображения через браузер как web-сайт.

Зачем нужно KRR

Согласно исследованию Sysdig, в среднем кластеры Kubernetes имеют:

  • 69% неиспользуемого процессора
  • 18% неиспользуемой памяти Правильно подобрав размеры ваших контейнеров с помощью KRR, вы можете сэкономить в среднем 69% на облачных затратах.

Как работает KRR

KRR получает данные из Prometheus и рассчитывает оптимальные request и limit на основе истории использования ресурсов. По умолчанию разработчики выставляют следующие рекомендации:

  • CPU request на 66-й перцентиль.
  • CPU limit на 95-й перцентиль.
  • Память рассчитывается по максимальному использованию + буфер.

Использование KRR из командной строки

Конечно, вы можете запустить KRR локально.

  • Получение рекомендаций в терминале:krr simple-limit -p <Prometheus_URL> --formatter yaml
  • Запуск с фильтрацией по namespace:krr simple-limit -p <Prometheus_URL> -n my-namespace

Запуск KRR в виде сервиса, который будет автоматически просчитывать рекомендации по ресурсам

Но лучше чтобы рекомендации по ресурсам видели все сотрудники вашей команды.

Пример HTML работы KRR 

Для этого вам необходимо в кластере создать:

Namespace

Код ns.yaml

---
apiVersion: v1
kind: Namespace
metadata:
  name: krr

ServiceAccount

Код sa.yaml

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: krr-service-account
  namespace: krr

ClusterRole и ClusterRoleBinding

Код ClusterRole.yaml

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: krr-cluster-role
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - daemonsets
      - deployments
      - namespaces
      - pods
      - replicasets
      - replicationcontrollers
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - apps
    resources:
      - daemonsets
      - deployments
      - deployments/scale
      - replicasets
      - replicasets/scale
      - statefulsets
    verbs:
      - get
      - list
      - watch

Код ClusterRoleBinding.yaml

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: krr-cluster-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: krr-cluster-role
subjects:
  - kind: ServiceAccount
    name: krr-service-account
    namespace: krr

Deployment с контейнером KRR

Код deploy.yaml

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: krr
  namespace: krr
spec:
  replicas: 1
  selector:
    matchLabels:
      app: krr
  template:
    metadata:
      labels:
        app: krr
    spec:
      serviceAccount: krr-service-account
      serviceAccountName: krr-service-account
      volumes:
        - name: shared-storage
          emptyDir: {}
      containers:
        - name: nginx
          image: nginx:1.27.4
          volumeMounts:
            - name: shared-storage
              mountPath: /usr/share/nginx/html
          ports:
            - containerPort: 80
        - name: krr
          image: robustadev/krr:v1.22.0
          volumeMounts:
            - name: shared-storage
              mountPath: /output
          env:
            - name: COLUMNS
              value: "400"
          command:
            - /bin/sh
            - -c
            - |
              while true; do
                TEMP_FILE="/output/index_tmp.html"
                FINAL_FILE="/output/index.html"
                python krr.py simple-limit \
                  -p https://vmselect.corp/select/0/prometheus \
                  --prometheus-label cluster -l dev \
                  --allow-hpa \
                  --use-oomkill-data \
                  --formatter html \
                  --fileoutput "$TEMP_FILE" && mv "$TEMP_FILE" "$FINAL_FILE";
                sleep 1d;
              done
          resources:
            limits:
              memory: 2Gi
            requests:
              memory: 1Gi

Документация по коду deploy.yaml

Ширина html страницы регулируется с помощью переменной COLUMNS.

Приложение krr ходит в текущий k8s и смотрит там текущие pod, поэтому ему нужны ClusterRole, ClusterRoleBinding, ServiceAccount.

Для параметра —prometheus-label cluster нужно указать контекст для текущего кластера в VictoriaMetrics.

Используется стратегия simple-limit, у которой cpu limit = cpu request, так как в обычной стратегии simple cpu limit отключен.

Время после команды sleep указывает сколько ждать перед тем как запустить следующий раз.

Service

Код svc.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: krr-service
  namespace: krr
spec:
  selector:
    app: krr
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Ingress для доступа к результатам

Код ingress.yaml

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: krr-ingress
  namespace: krr
  annotations:
    cert-manager.io/cluster-issuer: cluster-issuer
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - krr.k8s.dev.corp
      secretName: krr-tls
  rules:
    - host: krr.k8s.dev.corp
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: krr-service
                port:
                  number: 80

Разница с Kubernetes VPA

На странице Github KRR показана разница с k8s VPA

Заключение

KRR — мощный инструмент для автоматической оптимизации ресурсов в Kubernetes, который помогает экономить CPU и память. Простота настройки и гибкость интеграции делают его отличным выбором для DevOps-инженеров.