Learning Platform
Глоссарий Troubleshooting
Урок 19.04 · 20 мин
Продвинутый
aggregated APIAPIServicemetrics-serverextensionkube-apiserver

Aggregated API servers

CRD — основной способ расширить Kubernetes API, но не единственный. Есть второй, более тяжёлый и редкий, механизм — aggregated API server. Идея: к kube-apiserver «подключается» отдельный полноценный API server, который обрабатывает запросы к определённой API group. С точки зрения клиента всё прозрачно — он по-прежнему дёргает kubectl get через kube-apiserver, но за scene запрос проксируется на отдельный сервер. Каноничный пример — metrics-server (тот, что отвечает за kubectl top).


REST поверх HTTP: resources, uniform interface, statelessness

Что такое aggregated API server

Aggregated API server (AAS) — это самостоятельный HTTP-сервер, который:

  • Реализует Kubernetes API contract: те же verbs (get, list, watch, create, update, patch, delete), тот же AdmissionReview, тот же OpenAPI discovery.
  • Регистрируется в kube-apiserver через объект APIService в группе apiregistration.k8s.io/v1.
  • Получает прокси-запросы от kube-apiserver: когда приходит запрос на API group, зарегистрированную через APIService, kube-apiserver делает HTTP-запрос на endpoint AAS и проксирует ответ.

AAS сам отвечает за storage, validation, business logic. Он может хранить данные в etcd (своём отдельном или shared с kube-apiserver), в SQL database, в внешнем service, в памяти, где угодно. Это полная свобода — и полная ответственность.

Запрос к aggregated API: kubectl → kube-apiserver → AAS
kubectl top podkubectl делает GET /apis/metrics.k8s.io/v1beta1/namespaces/default/pods. Клиент не знает, что это aggregated — для него это обычный API request.
kube-apiserver routerkube-apiserver видит, что API group metrics.k8s.io зарегистрирована через APIService v1beta1.metrics.k8s.io. Извлекает spec.service: namespace=kube-system, name=metrics-server.
proxy requestkube-apiserver делает HTTPS-запрос на Service metrics-server.kube-system.svc:443/apis/metrics.k8s.io/v1beta1/... От своего имени (через service account кубапи), пробросив user info в заголовках для downstream auth.
metrics-server Podmetrics-server — это Deployment в kube-system. Внутри Pod — Go-сервер на k8s.io/apiserver framework. Принимает proxied request, делает свою логику: запрашивает cAdvisor через kubelet API на каждой ноде.
storage: memorymetrics-server не использует etcd — данные хранятся в памяти (rolling window 60s). Каждые 15s scrape kubelet → /metrics/resource на всех нодах, агрегирует и держит in-memory. Restart Pod = потеря истории.
response JSONAAS возвращает результат в Kubernetes API format: kind: PodMetricsList. kube-apiserver проксирует ответ обратно клиенту. kubectl рендерит таблицу.

APIService: регистрация AAS

APIService — объект, который регистрирует aggregated API server в kube-apiserver:

apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: v1beta1.metrics.k8s.io        # обязательно <version>.<group>
spec:
  group: metrics.k8s.io               # какую API group обслуживает
  version: v1beta1                     # какую version
  service:
    name: metrics-server               # Service в кластере → AAS Pods
    namespace: kube-system
    port: 443                          # HTTPS endpoint AAS
  insecureSkipTLSVerify: true          # для self-signed cert AAS (production: caBundle)
  caBundle: <base64 CA cert>           # CA, подписавший cert AAS
  groupPriorityMinimum: 100            # для merging conflicting groups (e.g. shadowing built-in)
  versionPriority: 100                 # ordering versions в API discovery

После создания этого объекта kube-apiserver запоминает: «всё, что приходит на /apis/metrics.k8s.io/v1beta1/..., проксировать на https://metrics-server.kube-system.svc:443».

NOTE

Внутри Kubernetes есть специальный kube-aggregator компонент, встроенный в kube-apiserver, который читает APIService objects и поддерживает таблицу маршрутизации. Он же проверяет health AAS (через GET на endpoint), и помечает APIService.status.conditions[].type=Available. Если AAS недоступен — Available становится False, и kubectl получит 503.


CRD vs Aggregated API: сравнение

АспектCRDAggregated API
Storageetcd кластера (через kube-apiserver)Любой: etcd, SQL DB, in-memory, external service
ValidationOpenAPI v3 schema (declarative) + CEL для cross-fieldCustom Go код, полная свобода
SubresourcesBasic: /status, /scale (declarative)Любые custom: /metrics, /proxy, /portforward, что угодно
Authenticationчерез kube-apiserverчерез kube-apiserver (proxy)
Authorizationчерез RBAC kube-apiserverчерез RBAC kube-apiserver (или собственный)
ImplementationYAML manifest, без Go-кодаРеальный Go-сервер на k8s.io/apiserver framework
Deploymentkubectl apply CRD objectDeployment + Service + APIService + RBAC
LatencyНизкая (in-tree apiserver)Higher (network hop kube-apiserver → AAS)
СложностьНизкая (declarative)Высокая (нужно понимать apiserver internals)

Главное различие: CRD — это «расширение хранилища etcd через метаданные»; AAS — это «отдельный сервер, говорящий на K8s API protocol».


Примеры aggregated API server-ов

AASAPI groupЧто предоставляет
metrics-servermetrics.k8s.io/v1beta1PodMetrics, NodeMetrics — current CPU/memory usage. Используется kubectl top, HPA, VPA. In-memory storage.
custom-metrics-apiservercustom.metrics.k8s.io/v1beta1Custom metrics для HPA (например, qps_per_pod из Prometheus). Adapter, проксирующий в Prometheus.
external-metrics-apiserverexternal.metrics.k8s.io/v1beta1External metrics (CloudWatch, Datadog) для HPA.
service-catalog (deprecated)servicecatalog.k8s.io/v1beta1Open Service Broker API integration. Сейчас deprecated; альтернатива — Crossplane (через CRD).
Knative Eventing (частично)eventing.knative.dev/v1В основном CRD, но некоторые subresources — AAS.
virt-api (KubeVirt)subresources.kubevirt.io/v1VM lifecycle subresources: /vnc, /console, /pause, /restart. CRD для main objects, AAS для action subresources.

Канонический use-case AAS — metrics-server: не нужно хранить данные в etcd (они эфемерны), нужно собирать с многих kubelets, нужна низкая latency. CRD не подходит — etcd не дизайнено для high-throughput метрик.


Почему AAS — редкость

В практике 99% extension в Kubernetes — это CRD + Operator. AAS используется в очень узком наборе случаев:

  1. Данные с собственным жизненным циклом, отличным от объекта. metrics-server: метрики обновляются каждые 15s, etcd не подходит для таких write rates.
  2. Storage backend не etcd. Например, ML model registry с custom DB (объекты огромные, нужна versioning, etcd плохо подходит).
  3. Subresources с custom logic. KubeVirt /vnc — это не просто read-write объекта, это live WebSocket session к виртуальной машине.
  4. Performance critical. CRD идёт через generic etcd path; AAS может использовать оптимизированный backend.

В большинстве cases CRD + controller покрывают потребность. AAS требует на порядок больше work: реализовать REST API правильно, поддерживать watch streams, реализовать pagination, делать defaulting через webhook, делать version conversion, integrate с RBAC. Это полноценный сервер, а не yaml-объект.

TIP

Эвристика выбора: «нужен ли тебе собственный storage backend?» Если да — AAS. Если нет — CRD. В 99% случаев etcd работает отлично, и нужно «просто хранить декларативное состояние объекта» — это CRD-кейс.


Поток развёртывания metrics-server

Чтобы поставить metrics-server, нужен пакет ресурсов:

# 1. ServiceAccount + RBAC для metrics-server
apiVersion: v1
kind: ServiceAccount
metadata: {name: metrics-server, namespace: kube-system}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata: {name: system:metrics-server}
rules:
- apiGroups: [""]
  resources: [nodes/metrics, pods]
  verbs: [get, list, watch]
- apiGroups: [""]
  resources: [nodes/stats, nodes/proxy]
  verbs: [get]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata: {name: system:metrics-server}
subjects: [{kind: ServiceAccount, name: metrics-server, namespace: kube-system}]
roleRef: {kind: ClusterRole, name: system:metrics-server, apiGroup: rbac.authorization.k8s.io}
---
# 2. Deployment с metrics-server образом
apiVersion: apps/v1
kind: Deployment
metadata: {name: metrics-server, namespace: kube-system}
spec:
  selector: {matchLabels: {k8s-app: metrics-server}}
  template:
    metadata: {labels: {k8s-app: metrics-server}}
    spec:
      serviceAccountName: metrics-server
      containers:
      - name: metrics-server
        image: registry.k8s.io/metrics-server/metrics-server:v0.7.2
        args:
        - --secure-port=10250
        - --cert-dir=/tmp
        - --kubelet-preferred-address-types=InternalIP
        - --kubelet-insecure-tls               # для kind/minikube; production: проверенный CA
        ports:
        - containerPort: 10250
          name: https
---
# 3. Service exposes Pods на 443
apiVersion: v1
kind: Service
metadata: {name: metrics-server, namespace: kube-system}
spec:
  selector: {k8s-app: metrics-server}
  ports:
  - port: 443
    targetPort: 10250
---
# 4. APIService — регистрирует AAS в kube-apiserver
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata: {name: v1beta1.metrics.k8s.io}
spec:
  group: metrics.k8s.io
  version: v1beta1
  service: {name: metrics-server, namespace: kube-system, port: 443}
  insecureSkipTLSVerify: true                  # production: caBundle
  groupPriorityMinimum: 100
  versionPriority: 100

После apply — kubectl top начинает работать через минуту-две (как только metrics-server начнёт scraping и накопит данные).


CKAD scope

CKAD не требует уметь писать AAS. Минимум:

  • Знать, что есть такой механизм расширения.
  • Понимать, что metrics-server — это AAS, и kubectl top работает через него.
  • Различать CRD vs AAS концептуально.
  • Уметь troubleshoot: kubectl get apiservice → ищи Available: False.
# Список всех APIServices в кластере
kubectl get apiservice

# Built-in APIServices (всегда Local: True) и aggregated (Local: False, Service: ...)
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml

# Если status.conditions показывает Available=False — AAS Pod упал или RBAC сломан
kubectl describe apiservice v1beta1.metrics.k8s.io

Killer-моменты

  • AAS — это полноценный API server рядом с kube-apiserver. Не плагин, не YAML — Go-программа на framework apiserver-runtime.
  • APIService — это «route entry» в kube-apiserver. Объект говорит: «всё на этом path проксировать на этот Service».
  • AAS управляет своим storage. Это его килer feature и одновременно его сложность. CRD получает etcd «бесплатно», AAS должен выбрать и реализовать.
  • metrics-server — единственный AAS, который встречается в каждом production-кластере. Без него HPA + kubectl top не работают.
  • Если поставлен APIService и он недоступен (Pod упал), kubectl get на ту group вернёт 503 / timeout. Это легко диагностируется через kubectl get apiservice.

Проверка знанийKnowledge check
Чем aggregated API отличается от CRD на уровне архитектуры, и почему 99% extension — это CRD?
ОтветAnswer
CRD — это декларативный YAML, говорящий kube-apiserver: 'добавь новый kind, валидируй по этой schema, храни в моём etcd, давай мне RBAC и watch'. Никакого кода. Aggregated API — это реальный отдельный Go-сервер на framework apiserver. Он отвечает на HTTP-запросы proxied от kube-apiserver, сам управляет storage (etcd / SQL / memory / external), сам валидирует, сам делает versioning. CRD выигрывает в 99% случаев потому, что: (1) etcd как storage работает для подавляющего большинства use cases — declarative state of small objects; (2) declarative schema проще писать и поддерживать; (3) не нужно реализовывать REST/watch/pagination/openAPI — всё бесплатно от kube-apiserver. AAS оправдан, когда нужен собственный storage backend (metrics с high write rate, или custom DB) или нестандартные subresources (live VNC stream).
Проверка знанийKnowledge check
kubectl top pod не работает, выдаёт 'error: Metrics API not available'. Где искать причину?
ОтветAnswer
Это означает, что aggregated API metrics.k8s.io не отвечает. Цепочка диагностики: (1) kubectl get apiservice v1beta1.metrics.k8s.io -o yaml — смотри status.conditions, поле Available. Если False — есть message с причиной (e.g. 'no endpoints available for service metrics-server'). (2) Если APIService есть, но Available=False: kubectl get pods -n kube-system -l k8s-app=metrics-server — Pod существует? Running? Не CrashLoopBackOff? (3) Логи: kubectl logs -n kube-system deployment/metrics-server — типичные ошибки: 'unable to fetch metrics from node X: x509: certificate signed by unknown authority' (нужен --kubelet-insecure-tls для kind/self-signed) или 'connection refused on port 10250' (kubelet не отвечает). (4) Если Pod ok, но логи чистые — caBundle в APIService может быть неверный (TLS handshake fails между kube-apiserver и metrics-server). Production fix: использовать cert-manager + правильный caBundle, не insecureSkipTLSVerify.
Проверка знанийKnowledge check
Можно ли использовать aggregated API для замены конкретной встроенной API group (например, чтобы override behavior на /apis/apps/v1/deployments)?
ОтветAnswer
Да, теоретически. Если зарегистрировать APIService на v1.apps с указанием своего Service, kube-apiserver начнёт проксировать запросы на твой AAS. Но это extremely опасно — все Deployments в кластере пойдут через твой сервер, и любая ошибка сломает основной workflow. groupPriorityMinimum контролирует, какая регистрация выигрывает при коллизии — встроенная всегда имеет высокий приоритет по умолчанию. Практический use case — НЕТ, для built-in API это не делается. Реальный use case priority — конфликт между несколькими aggregated extensions, или shadow API для testing. В production пытаться override built-in apps/v1 — это рецепт outage. Существует уровень API discovery, где kube-aggregator показывает только один сервер на pair (group, version) — конфликт разрешается через priority.
Проверка знанийKnowledge check
metrics-server держит данные в памяти, не в etcd. Что произойдёт при его рестарте?
ОтветAnswer
Все накопленные метрики теряются. Через 15 секунд (default scrape interval) metrics-server делает первый scrape всех nodes/Pods и начинает заполнять in-memory store. До тех пор kubectl top вернёт пустой результат или 'metrics not available yet'. HPA, которая опирается на metrics-server, не сможет принять решения о scaling в этот момент — будет log 'unable to fetch metrics'. Это не критично для HPA (она просто пропустит итерацию), но критично для observability. Поэтому: (1) metrics-server обычно ставится как Deployment с replicas: 1 — нет смысла в HA, потеря 30s метрик не критична; (2) для долговременной истории и SLO-driven decisions нужен Prometheus + Prometheus Adapter (который сам по себе AAS, custom.metrics.k8s.io), где данные хранятся в TSDB на диске. metrics-server — это «current values for HPA», Prometheus — «полноценный observability backend».

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. kubectl top pod возвращает 'error: Metrics API not available'. Куда смотреть первым делом?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5