Архитектура кластера Kubernetes
В Docker на одной VM контейнеры запускал Docker Engine. Kubernetes решает задачу шире: нужно управлять контейнерами на нескольких машинах, следить за их состоянием, пересоздавать упавшие Pod'ы, выдавать им сеть и принимать команды от пользователя или CI.
В этом курсе мы не будем глубоко заниматься администрированием Kubernetes-кластера: установкой control plane, настройкой etcd, сертификатами, апгрейдами, резервным копированием и ремонтом системных компонентов. Это отдельная большая тема для администраторов платформы.
Но для прикладной работы всё равно важно понимать, из чего состоит кластер. Kubernetes - это не одна программа, которую просто запустили на сервере. Грубо говоря, это несколько программ, которые работают вместе: одна принимает запросы, другая хранит состояние, третья выбирает node для Pod'а, четвёртая запускает контейнеры на конкретной node.
Манифесты, Deployment, Service, ConfigMap и описание приложений - это прикладной слой работы с кластером. Именно с ним мы будем работать в этом курсе чаще всего. А архитектура ниже нужна как карта: чтобы понимать, куда попадает команда kubectl apply, почему Pod не появляется мгновенно и какие компоненты участвуют в поддержании желаемого состояния.
Чтобы не воспринимать Kubernetes как “большую чёрную коробку”, сначала разберём роли компонентов. Когда ты выполняешь kubectl apply, запрос проходит через API Server, сохраняется как желаемое состояние, а дальше контроллеры и kubelet постепенно приводят кластер к этому состоянию.
Кластер
Kubernetes-кластер — набор машин (серверов или VM), которые работают вместе. Каждая машина называется Node (узел). Узлы делятся на два типа:
Kubernetes Cluster
├── Control Plane (мозг кластера)
│ ├── API Server — единая точка входа
│ ├── etcd — база данных состояния
│ ├── Scheduler — распределяет Pod'ы по узлам
│ └── Controller Manager — поддерживает желаемое состояние
└── Worker Nodes (рабочие лошадки)
├── kubelet — агент на каждом узле
├── kube-proxy — сетевые правила
└── Container Runtime — запускает контейнеры (containerd)
Control Plane (Плоскость управления)
API Server
Единственная точка взаимодействия со всем кластером. Все команды (kubectl, CI/CD, другие компоненты) идут через него.
# Ты выполняешь:
kubectl apply -f deployment.yaml
# На самом деле:
# kubectl → HTTP POST → API Server → etcd → Scheduler → kubelet
API Server валидирует запросы, применяет политики авторизации и сохраняет изменения в etcd.
etcd
Распределённая key-value база данных — хранилище всего состояния кластера. Если etcd умрёт — кластер потеряет своё состояние.
etcd хранит:
├── Все Pod'ы и их состояния
├── Все Deployment'ы, Services, ConfigMaps...
├── Токены авторизации
└── Настройки сети
Это объясняет почему бэкап etcd — критически важная операция при администрировании production-кластера.
Scheduler
Смотрит на новые Pod'ы без назначенного Node и выбирает подходящий Node:
Новый Pod без Node
↓
Scheduler проверяет:
- Есть ли ресурсы (CPU, RAM)?
- Выполнены ли nodeSelector и affinity?
- Применимы ли taints/tolerations?
↓
Назначает Pod на Node
Controller Manager
Запускает контроллеры — циклы, которые следят за состоянием:
- ReplicaSet Controller: "Нужно 3 Pod'а, сейчас 2 → создать ещё один"
- Deployment Controller: управляет rolling updates
- Node Controller: следит за доступностью узлов
- Job Controller: запускает одноразовые задачи
Worker Nodes
kubelet
Агент на каждом Worker Node. Получает задания от API Server и запускает контейнеры. Следит за состоянием Pod'ов и репортит обратно.
API Server: "На этом узле должен работать Pod nginx"
↓
kubelet → Container Runtime → запускает контейнер
kubelet → API Server: "Pod nginx Running, IP: 10.0.0.5"
kube-proxy
Сетевой proxy на каждом узле. Поддерживает сетевые правила (iptables/ipvs) для доступа к Service.
Container Runtime
Рантайм контейнеров — обычно containerd (раньше был Docker). Kubelet говорит "запусти этот образ" → containerd запускает контейнер.
Объекты Kubernetes
Всё в Kubernetes описывается объектами. У каждого объекта:
- apiVersion — версия API
- kind — тип объекта (Pod, Deployment, Service...)
- metadata — имя, namespace, labels
- spec — желаемое состояние
- status — текущее состояние (заполняется кластером)
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
namespace: default
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
Namespace — логическая изоляция
Кластер разделяется на namespace — логические пространства имён:
kubectl get namespaces
# default — объекты без явного namespace
# kube-system — системные компоненты k8s
# kube-public — публично доступные ресурсы
# kube-node-lease — keepalive от узлов
В этом курсе ты работаешь в своём изолированном namespace. Ты не видишь Pod'ы других пользователей и не можешь изменить системные настройки.
kubectl: как мы общаемся с кластером
С Kubernetes обычно работают через специальную утилиту kubectl. Это CLI-клиент: ты вводишь команду в терминале, а kubectl формирует запрос к Kubernetes API Server.
kubectl не запускает контейнеры сам и не ходит напрямую на worker node. Его задача - обратиться к API Server:
kubectl get podsотправляет запрос "покажи Pod'ы";kubectl apply -f deployment.yamlчитает YAML-манифест и отправляет описание объекта;kubectl delete pod webотправляет запрос на удаление объекта.
API Server уже делает следующую часть работы: проверяет права, сохраняет состояние в etcd и передаёт изменения дальше через контроллеры, scheduler и kubelet.
kubectl -> API Server -> etcd / controllers / scheduler / kubelet
Упрощённый путь запроса:
kubectlчитает kubeconfig.- Находит адрес API Server и credentials.
- Отправляет HTTP-запрос в API Server.
- API Server проверяет аутентификацию: кто ты.
- API Server проверяет авторизацию через RBAC: что тебе можно делать.
- API Server читает или меняет состояние кластера.
kubectlпоказывает ответ в терминале.
Kubeconfig
Чтобы kubectl знал, к какому кластеру подключаться и с какими правами, ему нужен kubeconfig.
Обычно файл лежит здесь:
~/.kube/config
Путь можно переопределить переменной окружения:
echo $KUBECONFIG
В учебной VM kubeconfig уже подготовлен. В реальной работе его обычно выдаёт администратор платформы, облачный провайдер или команда, которая управляет кластером. Например, в облаках kubeconfig часто создаётся командой CLI провайдера, а в корпоративной инфраструктуре его могут выдать через внутренний портал или секретное хранилище.
Kubeconfig не создаёт кластер. Это файл доступа: куда подключаться, каким пользователем и в какой namespace отправлять команды.
В kubeconfig обычно есть четыре важные части:
| Поле | Что означает |
|---|---|
clusters |
адреса Kubernetes API Server и настройки доверия к сертификату |
users |
данные пользователя: token, client certificate или другой способ входа |
contexts |
связка cluster + user + namespace |
current-context |
какой context используется сейчас |
Упрощённо это выглядит так:
clusters:
- name: dev-cluster
cluster:
server: https://k8s.example.com
users:
- name: student
user:
token: ...
contexts:
- name: student@dev-cluster
context:
cluster: dev-cluster
user: student
namespace: default
current-context: student@dev-cluster
Context особенно важен. Он отвечает на вопрос: "в какой кластер, каким пользователем и в какой namespace сейчас пойдут команды".
Посмотреть текущие настройки можно так:
kubectl config current-context
kubectl config get-contexts
kubectl config view --minify
Если kubectl "ничего не видит", часто проблема не в Pod'ах, а в context или namespace. Поэтому перед диагностикой полезно проверить:
kubectl config view --minify --output 'jsonpath={..namespace}'
kubectl get pods
kubectl get pods -A
kubectl get pods -A — cluster-wide просмотр. Для прикладной диагностики обычно начинают с текущего namespace, а cluster-wide команды чаще относятся к platform/admin уровню.
get, describe, logs: базовый порядок просмотра
get даёт краткую таблицу:
kubectl get pods
kubectl get pods -o wide
kubectl get deployment,svc
-o wide добавляет больше полей: IP Pod'а, node, иногда дополнительные детали.
describe показывает подробности объекта и связанные Events:
kubectl describe pod web
logs показывает stdout/stderr контейнера:
kubectl logs pod/web --tail=50
kubectl logs -l app=web --tail=50
kubectl logs pod/web --previous
Перед лабами запомни порядок: сначала get, если статус непонятен - describe, если контейнер стартовал - logs.
Events - дополнительный источник диагностики. Они часто объясняют причину проблемы: image не скачался, не хватает ресурсов, probe падает, selector не находит Pod. Для отдельного просмотра событий:
kubectl get events --sort-by=.lastTimestamp
Namespace в командах
Команду можно выполнить в явном namespace:
kubectl get pods -n dev
kubectl config set-context --current --namespace=dev
Первый вариант меняет только одну команду. Второй меняет текущий namespace в context. В учебных задачах это полезно, но после изменения контекста всегда проверяй:
kubectl config view --minify --output 'jsonpath={..namespace}'
Так ты не создашь ресурсы “не там”.
API resources и сокращения
Kubernetes API содержит много типов объектов. Посмотреть их можно так:
kubectl api-resources
kubectl explain pod
kubectl explain deployment.spec.replicas
kubectl explain полезен, когда ты пишешь YAML и не помнишь структуру поля. Он показывает схему ресурса из API Server.
Сокращения:
| Полное имя | Сокращение |
|---|---|
| pods | po |
| deployments | deploy |
| services | svc |
| namespaces | ns |
| configmaps | cm |
| secrets | secret |
Примеры:
kubectl get po
kubectl get deploy,svc
kubectl describe svc web
Сокращения удобны в терминале, но в учебных объяснениях часто лучше писать полное имя, чтобы не терять смысл.
YAML из существующего объекта
Для изучения можно экспортировать объект:
kubectl get pod nginx-pod -o yaml
kubectl get deployment web -o yaml > web.yaml
Экспорт показывает и желаемую спецификацию, и runtime-поля. В Git обычно не коммитят status, uid, resourceVersion, managedFields, но для лабораторного анализа такой YAML полезен: он показывает, как Kubernetes дополнил объект defaults.
