Learning Platform
Глоссарий Troubleshooting
Урок 04.04 · 20 мин
Продвинутый
kubectlexplainapi-resourcesOpenAPIREST APIkubectl proxyverbose

Навигация по API: explain, api-resources, REST endpoints

Этот урок — главный в модуле. Если предыдущие уроки давали правила работы с инструментом, этот объясняет, что на самом деле происходит между моментом «вы нажали Enter» и моментом «в etcd появился новый объект». Спойлер: kubectl читает kubeconfig, формирует HTTP запрос на REST endpoint вида /api/v1/..., отправляет TLS-соединением на apiserver, получает JSON-ответ. Никакой магии. После этого урока вы сможете отлаживать любую проблему kubectl без помощи документации — увидите реальный HTTP-трафик в -v=8 и поймёте, что не так.


curl и wget: скачивание и HTTP из command line

kubectl как HTTP-клиент

kubectl get pods

Эта команда — лжёт. Не в смысле «не работает», а в смысле «прячет, что делает». На самом деле kubectl выполняет:

GET /api/v1/namespaces/default/pods?limit=500 HTTP/1.1
Host: kubernetes.default.svc:6443
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Accept: application/json

Apiserver отвечает JSON-документом со списком Pod-ов в namespace default. kubectl парсит, вытаскивает поля name, ready, status, restarts, age, форматирует в таблицу. Всё.

kubectl ↔ apiserver: настоящая картина
kubectl get podsШаг 1: kubectl парсит команду — verb=GET, resource=pods. Шаг 2: читает kubeconfig — server URL и credentials. Шаг 3: формирует HTTP запрос с auth headers.
HTTPS + TLS
HTTP GETЗапрос на /api/v1/namespaces/default/pods. Заголовок Authorization: Bearer token. Accept: application/json или application/vnd.kubernetes.protobuf (для перформанса).
apiserver pipeline
kube-apiserverAuthenticate (validate token) → Authorize (RBAC check) → Admission (webhooks) → Storage (etcd read). Для GET — только authn/authz, без admission.
JSON response
kubectl renderПарсит JSON → объекты Go (если используется client-go). Применяет column-printer формат: NAME READY STATUS RESTARTS AGE. Это уже клиентская обработка, apiserver не знает про таблицу.

Когда у вас в голове эта картинка, фраза «у меня не работает kubectl» становится конкретной: «у меня TLS handshake fail» (CA не совпал), «401» (token истёк), «404» (resource нет в этом cluster), «403» (RBAC запрещает), «timeout» (apiserver недоступен).


kubectl api-resources: что вообще есть в кластере

Прежде чем работать с ресурсом, надо знать, существует ли он:

kubectl api-resources
# NAME              SHORTNAMES   APIVERSION    NAMESPACED   KIND
# bindings                       v1            true         Binding
# componentstatuses cs           v1            false        ComponentStatus
# configmaps        cm           v1            true         ConfigMap
# endpoints         ep           v1            true         Endpoints
# events            ev           v1            true         Event
# limitranges       limits       v1            true         LimitRange
# namespaces        ns           v1            false        Namespace
# nodes             no           v1            false        Node
# persistentvolumeclaims pvc     v1            true         PersistentVolumeClaim
# persistentvolumes pv           v1            false        PersistentVolume
# pods              po           v1            true         Pod
# ...
# deployments       deploy       apps/v1       true         Deployment
# statefulsets      sts          apps/v1       true         StatefulSet
# daemonsets        ds           apps/v1       true         DaemonSet
# replicasets       rs           apps/v1       true         ReplicaSet
# ...
# ingresses         ing          networking.k8s.io/v1   true   Ingress
# networkpolicies   netpol       networking.k8s.io/v1   true   NetworkPolicy

Колонки:

  • NAME — имя в URL (/api/v1/pods).
  • SHORTNAMES — алиасы для kubectl (kubectl get po == kubectl get pods).
  • APIVERSION — group/version. Для core (Pod, Service, ConfigMap) — v1. Для остальных — apps/v1, networking.k8s.io/v1, batch/v1.
  • NAMESPACED — true → ресурс живёт в namespace, false → cluster-scoped.
  • KIND — имя в YAML (kind: Deployment).

Фильтры:

kubectl api-resources --namespaced=true              # только namespaced
kubectl api-resources --namespaced=false             # только cluster-scoped
kubectl api-resources --api-group=apps               # только apps group
kubectl api-resources --api-group=batch              # только batch group
kubectl api-resources -o wide                        # + verbs (verbs apiserver-а)
kubectl api-resources --verbs=list,watch             # ресурсы, которые можно list/watch

-o wide показывает verbs — что можно делать с ресурсом:

kubectl api-resources -o wide | head -3
# NAME    SHORTNAMES   APIVERSION   NAMESPACED   KIND   VERBS
# pods    po           v1           true         Pod    [create delete deletecollection get list patch update watch]

Если у ресурса нет verb update — значит, его нельзя править через PUT (он immutable после создания, как Pod в большей части).


kubectl api-versions: какие API groups доступны

api-resources показывает ресурсы; api-versions — какие API groups + versions активны:

kubectl api-versions
# admissionregistration.k8s.io/v1
# apiextensions.k8s.io/v1
# apps/v1
# authentication.k8s.io/v1
# authorization.k8s.io/v1
# autoscaling/v1
# autoscaling/v2
# batch/v1
# certificates.k8s.io/v1
# coordination.k8s.io/v1
# discovery.k8s.io/v1
# events.k8s.io/v1
# networking.k8s.io/v1
# node.k8s.io/v1
# policy/v1
# rbac.authorization.k8s.io/v1
# scheduling.k8s.io/v1
# storage.k8s.io/v1
# v1

API groups — это разделение Kubernetes API на части. Core (v1) — самые ранние ресурсы (Pod, Service, ConfigMap, Secret, Namespace, Node). Всё остальное — отдельные groups, чтобы апдейтиться независимо.

apps/v1 — Deployment, StatefulSet, DaemonSet, ReplicaSet. batch/v1 — Job, CronJob. networking.k8s.io/v1 — Ingress, NetworkPolicy, IngressClass. rbac.authorization.k8s.io/v1 — Role, RoleBinding, ClusterRole, ClusterRoleBinding.

URL endpoints следуют структуре:

/api/v1/...                                  # core group
/apis/<group>/<version>/...                  # named group
/apis/apps/v1/namespaces/default/deployments
/apis/networking.k8s.io/v1/networkpolicies

Core group уникален тем, что у него /api, а не /apis. Это исторический след — core был первым, остальные группы появились позже.


kubectl explain: документация прямо в кластере

Это самый используемый инструмент в CKAD-арсенале. kubectl explain <resource>[.<field>] показывает структуру объекта без открытия документации:

# Корневая структура Pod
kubectl explain pod
# KIND:     Pod
# VERSION:  v1
#
# DESCRIPTION:
#      Pod is a collection of containers that can run on a host...
#
# FIELDS:
#    apiVersion   <string>
#    kind         <string>
#    metadata     <Object>
#    spec         <PodSpec>
#    status       <PodStatus>

# Углубиться в spec
kubectl explain pod.spec
# FIELDS:
#    activeDeadlineSeconds  <integer>
#    affinity               <Object>
#    automountServiceAccountToken <boolean>
#    containers             <[]Object>      -required-
#    ...

# В container
kubectl explain pod.spec.containers
# FIELDS:
#    args         <[]string>
#    command      <[]string>
#    env          <[]Object>
#    image        <string>
#    ...

# В env конкретного контейнера
kubectl explain pod.spec.containers.env

Главный флаг — --recursive:

kubectl explain pod.spec.containers --recursive
# FIELDS:
#    args           <[]string>
#    command        <[]string>
#    env            <[]Object>
#       name        <string>
#       value       <string>
#       valueFrom   <Object>
#          configMapKeyRef   <Object>
#             key             <string>
#             name            <string>
#             optional        <boolean>
#          fieldRef          <Object>
#          ...

Это разворачивает всё дерево. Когда вы забыли точное имя поля (securityContext.capabilities.drop или capabilities.drops?), kubectl explain --recursive за 2 секунды показывает правильное имя.

TIP

CKAD-killer move: вместо «открыть документацию kubernetes.io», набирайте k explain <resource>.<field> --recursive. На экзамене документация открыта в браузере, но переключаться + поиск занимает 30 секунд. explain — 2 секунды и в том же терминале.

Откуда explain берёт данные? Из OpenAPI schema, которую apiserver отдаёт по /openapi/v3/.... kubectl скачивает её при первом запросе, кэширует, потом отвечает локально.

# Сырая OpenAPI v3 schema (огромный JSON)
kubectl get --raw '/openapi/v3' | head -20
kubectl get --raw '/openapi/v3/apis/apps/v1' | jq '.components.schemas | keys'

Это значит: explain работает для любого ресурса, включая CRD. Установили оператор → его CRD автоматически появляется в api-resources, и kubectl explain <crd-kind> --recursive показывает всю спеку.


Сырые HTTP-запросы: kubectl get —raw

Когда стандартный kubectl get неудобен, можно сделать чистый HTTP:

# Список Pod-ов в namespace default — JSON напрямую
kubectl get --raw '/api/v1/namespaces/default/pods' | jq

# Список Deployments в default
kubectl get --raw '/apis/apps/v1/namespaces/default/deployments' | jq

# Получить один Pod
kubectl get --raw '/api/v1/namespaces/default/pods/web-0'

# Health эндпоинт apiserver
kubectl get --raw '/healthz'
# ok
kubectl get --raw '/livez?verbose'
kubectl get --raw '/readyz?verbose'

# Метрики
kubectl get --raw '/metrics' | head -50

# Версия API
kubectl get --raw '/version'

--raw использует те же credentials, что обычные kubectl-команды (через kubeconfig), но не делает никакой постобработки. Полезно для:

  • Диагностики (вы видите точный JSON, который apiserver вернул).
  • Доступа к нестандартным endpoints (/metrics, /livez, custom subresources).
  • Работы с custom controllers, которые слушают watch-streams.

kubectl proxy: локальный proxy на apiserver

Альтернативный способ работать с raw API:

# В одном терминале
kubectl proxy --port=8001
# Starting to serve on 127.0.0.1:8001

# В другом — curl на localhost, БЕЗ auth
curl http://localhost:8001/api/v1/namespaces/default/pods | jq
curl http://localhost:8001/version
curl http://localhost:8001/openapi/v3

kubectl proxy поднимает локальный HTTP-прокси, который проксирует запросы на apiserver, добавляя auth headers сам. Удобно:

  • Если нужно curl-ом исследовать API — не надо в каждый curl вставлять --cacert и --token.
  • Веб-инструменты (Kubernetes Dashboard) подключаются через proxy.
  • В dev-скриптах: один раз стартанул proxy, дальше curl на localhost.

kubectl -v: verbose logging

Уровни verbosity для отладки:

-v=NЧто выводит
0 (default)Только output
1Минимальная диагностика
2Status и общая информация
4Debug — что kubectl делает шагами
6HTTP requests на apiserver (URLs, методы)
7+ headers запросов
8+ bodies запросов и ответов
9+ curl-команды для воспроизведения вне kubectl

Это и есть killer-инструмент, обещанный в начале:

kubectl -v=8 get pods
# I0513 ... loaded kubeconfig from "/home/user/.kube/config"
# I0513 ... GET https://10.0.0.1:6443/api/v1/namespaces/default/pods?limit=500
# I0513 ... Request Headers:
#     Accept: application/json;as=Table;...
#     Authorization: Bearer <masked>
#     User-Agent: kubectl/v1.35.0 ...
# I0513 ... Response Status: 200 OK in 12 milliseconds
# I0513 ... Response Body: {"kind":"Table","apiVersion":"meta.k8s.io/v1",...

Видно реальный URL, реальные заголовки (token замаскирован), реальный JSON ответа. Любой раз, когда «kubectl делает что-то странное», начинать с -v=6 или -v=8.

-v=9 пишет equivalent curl-команды:

kubectl -v=9 get pod web-0 2>&1 | grep curl
# I0513 ... curl -v -XGET  -H "Accept: application/json" \
#   -H "Authorization: Bearer <token>" \
#   'https://10.0.0.1:6443/api/v1/namespaces/default/pods/web-0'

Можно скопировать и запустить отдельно, в curl. Если curl работает, а kubectl — нет, проблема в kubectl. Если оба не работают — проблема в auth/network.


Watch streams: stream events from API

Все controllers Kubernetes используют watch — long-polling-стрим изменений. kubectl тоже умеет:

kubectl get pods --watch
# Открывает long-running запрос с ?watch=true
# Каждое изменение → новая строка вывода

Под капотом:

GET /api/v1/namespaces/default/pods?watch=true HTTP/1.1
# apiserver держит соединение открытым, шлёт chunks при каждом событии
{"type":"ADDED","object":{...}}
{"type":"MODIFIED","object":{...}}
{"type":"DELETED","object":{...}}

Это позволяет controllers реагировать на изменения в реальном времени, не делая постоянный GET. kubectl —watch — то же самое, только выводит в терминал.

# Следить за Pod-ами в реальном времени
kubectl get pods --watch
kubectl get pods --watch-only      # без начального дампа, только новые события
kubectl get events --watch         # все события cluster

Resource discovery в скриптах

В скриптах часто нужно узнать: «есть ли в этом кластере CRD foo.bar.io?» Через api-resources:

# Проверка наличия CRD
if kubectl api-resources --api-group=cert-manager.io 2>/dev/null | grep -q certificates; then
  echo "cert-manager установлен"
fi

# Все CRD
kubectl get crd

# Что внутри одного CRD
kubectl get crd certificates.cert-manager.io -o yaml

Что дальше

В следующем уроке — поднимаем local cluster через kind для labs. Установка, multi-node setup, alias и autocomplete — всё, что нужно, чтобы остальные модули шли с реальными командами на живом кластере, а не с теорией. И — финальный CKAD-toolkit, который пригодится на экзамене.


Проверка знанийKnowledge check
На CKAD вам нужно создать Pod с securityContext, где запрещён privilege escalation, root запрещён, runAsUser=1000, и для контейнера дропнут capability NET_RAW. Документация недоступна. Опишите по шагам, как через kubectl explain быстро узнать точные имена полей.
ОтветAnswer
Шаги: (1) `kubectl explain pod.spec.securityContext --recursive` — покажет все поля Pod-level SC: runAsUser, runAsGroup, runAsNonRoot, fsGroup, и т.д. Видим runAsUser и runAsNonRoot. (2) `kubectl explain pod.spec.containers.securityContext --recursive` — container-level SC: allowPrivilegeEscalation, capabilities (с add/drop), privileged, readOnlyRootFilesystem. Видим allowPrivilegeEscalation (с большой E в одном из слов) и capabilities.drop. (3) Теперь точные имена есть: pod.spec.securityContext.runAsUser=1000, pod.spec.securityContext.runAsNonRoot=true, container.securityContext.allowPrivilegeEscalation=false, container.securityContext.capabilities.drop=[NET_RAW]. (4) Бонус: можно проверить — заготовить YAML, прогнать `kubectl apply --dry-run=server -f pod.yaml`, apiserver проверит схему и сообщит, если имя поля неправильное. Весь цикл — 30 секунд против минут поиска в документации, и без переключения окон.

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Команда `kubectl get pods` — что физически уходит на apiserver?

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

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

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

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