Навигация по 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» становится конкретной: «у меня 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 секунды показывает правильное имя.
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 | Минимальная диагностика |
| 2 | Status и общая информация |
| 4 | Debug — что kubectl делает шагами |
| 6 | HTTP 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, который пригодится на экзамене.