Справочник ключевых терминов курса Kubernetes (CKAD).
Наименьшая deployable unit в Kubernetes. Группа из одного или нескольких контейнеров, разделяющих linux namespaces (network, IPC, опционально PID) и volumes. Schedule together на один node, имеют общий Pod IP, выдаваемый CNI plugin. Контейнеры внутри Pod общаются через localhost. Жизненный цикл: Pending → Running → Succeeded/Failed. Pods считаются ephemeral — при перезапуске получают новый IP. В v1.35 поддерживается native sidecar (restartPolicy=Always на init containers). Pod описывает желаемое состояние через spec, а status отражает текущее. Прямое создание Pod в продакшене — антипаттерн: используют контроллеры (Deployment, Job, StatefulSet).
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80Изолированный процесс, запущенный из container image через container runtime (containerd, CRI-O). В Kubernetes контейнер всегда живёт внутри Pod. Container получает свой mount/UTS/PID namespace, но network и IPC разделяются с другими контейнерами в Pod. Имеет resources (requests/limits), securityContext, env, volumeMounts, probes. Типы: app container, init container (запускается до основных, должен завершиться успешно), sidecar (с v1.29 — init container с restartPolicy=Always). Container restartPolicy наследуется от Pod (Always/OnFailure/Never). Lifecycle hooks: postStart и preStop позволяют выполнить действия при старте и graceful shutdown.
containers:
- name: app
image: myapp:v1.2.3
imagePullPolicy: IfNotPresent
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { cpu: 500m, memory: 256Mi }
ports:
- containerPort: 8080Физическая или виртуальная машина, входящая в кластер Kubernetes и запускающая Pods. На каждом node работают: kubelet (агент, общающийся с control plane), kube-proxy (правила Service), container runtime (containerd/CRI-O). Node имеет статусы: Ready, NotReady, MemoryPressure, DiskPressure, PIDPressure, NetworkUnavailable. Capacity описывает физические ресурсы (cpu, memory, ephemeral-storage, pods), Allocatable — доступное для Pods после вычета system-reserved и kube-reserved. Node может иметь labels (для nodeSelector/affinity) и taints (для отталкивания Pods без toleration). Cordon делает node unschedulable, drain эвакуирует Pods.
kubectl get nodes -o wide
kubectl describe node worker-1
kubectl label node worker-1 disktype=ssd
kubectl taint node worker-1 gpu=true:NoSchedule
kubectl cordon worker-1
kubectl drain worker-1 --ignore-daemonsetsСовокупность control plane components и worker nodes, объединённых в единое целое. Control plane (kube-apiserver, etcd, scheduler, controller-manager, cloud-controller-manager) отвечает за глобальные решения и реакцию на события. Worker nodes запускают рабочую нагрузку. Cluster имеет единое API через kube-apiserver, единое хранилище состояния в etcd, единое DNS пространство через CoreDNS. Версия кластера определяется версией control plane; разница с kubelet до 3 minor versions (skew policy). Production clusters обычно имеют HA control plane (3+ узла, multi-master), etcd quorum, multiple AZ.
kubectl cluster-info
kubectl version
kubectl get componentstatuses
kubectl get nodes
kubectl get --raw /healthzЛогическое разделение ресурсов внутри одного кластера. Используется для multi-tenancy, изоляции окружений (dev/stage/prod), применения RBAC и ResourceQuota. Built-in namespaces: default, kube-system (системные компоненты), kube-public (читаемые всеми), kube-node-lease (heartbeat). Namespace scope: большинство ресурсов (Pod, Service, ConfigMap, Deployment) — namespaced; некоторые (Node, PersistentVolume, ClusterRole, StorageClass) — cluster-scoped. DNS внутри namespace: short name, между namespaces: service.namespace.svc.cluster.local. NetworkPolicy и ResourceQuota применяются на уровне namespace. При удалении namespace удаляются все namespaced ресурсы.
kubectl create namespace dev
kubectl get all -n dev
kubectl config set-context --current --namespace=dev
kubectl api-resources --namespaced=true | head
# Cross-namespace DNS
curl http://api.backend.svc.cluster.localКонтроллер, обеспечивающий что заданное количество Pod replicas постоянно работает. Selector (matchLabels/matchExpressions) определяет, какие Pods принадлежат ReplicaSet. Если Pod удалён или crash — ReplicaSet создаёт новый. Если Pods больше нужного — удаляет лишние. Напрямую ReplicaSet практически не создают: используют Deployment, который управляет ReplicaSets для rollout. При rolling update Deployment создаёт новый RS и постепенно скейлит вверх, старый — вниз. ReplicaSet identifies Pods по labels — adopt orphan Pods, matching selector. История версий хранится через старые RS (revisionHistoryLimit).
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels: { app: frontend }
template:
metadata:
labels: { app: frontend }
spec:
containers:
- name: nginx
image: nginx:1.27Высокоуровневый контроллер для stateless приложений. Управляет ReplicaSets, реализуя declarative rollouts. Стратегии: RollingUpdate (default, поэтапно заменяет старые Pods новыми, controlled by maxSurge/maxUnavailable) и Recreate (убивает все старые, потом создаёт новые — downtime). Поддерживает rollback на предыдущую revision (kubectl rollout undo). История: revisionHistoryLimit (default 10). Status: progressing, available, failure. progressDeadlineSeconds — таймаут для rollout. Deployment не подходит для stateful workloads (используй StatefulSet) и не гарантирует unique pod identity. Триггер нового rollout: изменение Pod template (image, env, resources), не — изменение replicas.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: app
image: nginx:1.27Контроллер, гарантирующий что Pod запущен на каждом (или подходящем по nodeSelector/affinity) Node. Используется для node-level агентов: log collectors (Fluent Bit, Vector), monitoring (node-exporter), CNI plugins (Calico, Cilium), storage drivers (CSI). При добавлении нового node — Pod автоматически создаётся. Tolerations часто включают node-role.kubernetes.io/control-plane:NoSchedule для запуска на master nodes. Update strategies: RollingUpdate (default) и OnDelete. DaemonSet не учитывает replicas — количество определяется числом подходящих nodes.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
spec:
selector:
matchLabels: { app: fluent-bit }
template:
metadata:
labels: { app: fluent-bit }
spec:
tolerations:
- operator: Exists
containers:
- name: fluent-bit
image: fluent/fluent-bit:3.0Контроллер для batch-задач: создаёт один или несколько Pods и ждёт их успешного завершения. Параметры: completions (сколько Pods должно успешно завершиться), parallelism (сколько работают одновременно), backoffLimit (число retry при failure), activeDeadlineSeconds (таймаут), ttlSecondsAfterFinished (auto-cleanup после завершения). Patterns: non-parallel (1 Pod), fixed completion count, work queue (parallelism>1, completions не задан). restartPolicy для Pod в Job: OnFailure или Never. Indexed Job (completionMode: Indexed) — каждый Pod получает уникальный JOB_COMPLETION_INDEX через env/annotation.
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
completions: 5
parallelism: 2
backoffLimit: 4
ttlSecondsAfterFinished: 100
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: migrate:v1
command: ['./run.sh']Контроллер для периодических задач — создаёт Jobs по расписанию (cron syntax). Поля: schedule (например '0 2 * * *'), jobTemplate (spec Job), concurrencyPolicy (Allow/Forbid/Replace), startingDeadlineSeconds (если Job не стартанул в окно — пропустить), successfulJobsHistoryLimit/failedJobsHistoryLimit (хранение завершённых Jobs), suspend (приостановить). Timezone начиная с v1.27 поддерживается через timeZone field (IANA name). Каждый запуск создаёт Job, который создаёт Pod(s). Проблемы: missed schedules (DST, paused cluster), overlapping runs (используй Forbid).
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup
spec:
schedule: '0 3 * * *'
timeZone: 'Europe/Moscow'
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: backup-tool:v2Контроллер для stateful приложений: databases, message brokers. В отличие от Deployment предоставляет: stable network identity (Pod name: <sts>-0, <sts>-1...), stable storage (PVC per Pod через volumeClaimTemplates), ordered deployment/scaling (0,1,2...), ordered rolling updates (от высшего индекса к 0). Headless Service (clusterIP: None) обязателен для DNS — каждый Pod получает <pod>.<svc>.<ns>.svc.cluster.local. Update strategies: RollingUpdate (default, с partition для canary) и OnDelete. При удалении StatefulSet PVC по умолчанию НЕ удаляются (защита данных). podManagementPolicy: OrderedReady (default) или Parallel.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels: { app: postgres }
template:
metadata:
labels: { app: postgres }
spec:
containers:
- name: postgres
image: postgres:16
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata: { name: data }
spec:
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 10Gi } }Центральный компонент control plane — REST API gateway для всего кластера. Принимает запросы (kubectl, controllers, kubelet), проходящие три фазы: authentication (кто), authorization (можно ли — RBAC), admission control (валидация и mutation через MutatingAdmissionWebhook/ValidatingAdmissionWebhook/Policy). Validates objects, сохраняет в etcd, обслуживает watch streams для контроллеров. Stateless, может быть scaled horizontally (HA через несколько replicas за LB). Версионирование API: stable (v1), beta, alpha. Все остальные компоненты (scheduler, controllers, kubelet) общаются ТОЛЬКО через API server.
kubectl get --raw /api/v1/namespaces/default/pods
kubectl get --raw /healthz
kubectl get --raw /metrics | head
kubectl auth can-i create pods --as=jane
kubectl explain pod.spec.containersDistributed key-value store на основе Raft consensus — единственный источник истины (source of truth) о состоянии кластера. Хранит всё: Pods, ConfigMaps, Secrets, Services, события. Только kube-apiserver обращается к etcd напрямую. Production setup: 3 или 5 nodes (нечётное для quorum). Производительность критична — нужен SSD и низкий latency. Регулярные backup (etcdctl snapshot save) обязательны. Шифрование at-rest через EncryptionConfiguration. При потере quorum кластер read-only (kube-apiserver не может писать). Размер etcd ~ 2GB, увеличение через --quota-backend-bytes.
# На control-plane node
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-$(date +%F).dbКомпонент control plane, выбирающий node для Pod, у которого spec.nodeName пустой. Алгоритм две фазы: filtering (отсеивает nodes, не подходящие — недостаточно ресурсов, taint без toleration, nodeSelector mismatch) и scoring (ранжирует подходящие — least requested, balanced allocation, image locality, affinity). Pod attributes, влияющие на scheduling: resources.requests, nodeSelector, affinity/anti-affinity, tolerations, topologySpreadConstraints, priorityClassName. После выбора kube-scheduler устанавливает spec.nodeName, и kubelet на этом node замечает и запускает Pod. Кастомизация через scheduling profiles, scheduler extenders или собственный scheduler.
kubectl get events --field-selector reason=Scheduled
kubectl describe pod my-pod | grep -A5 Events
# Spec влияющий на scheduling:
spec:
nodeSelector:
disktype: ssd
tolerations:
- key: dedicated
operator: Equal
value: gpuБинарь, объединяющий многие core controllers в одном процессе: Deployment controller, ReplicaSet controller, Node controller (мониторит health nodes), Endpoint controller, ServiceAccount controller, Job controller, CronJob controller, и другие. Каждый controller — это reconciliation loop: смотрит desired state (от API server через watch) и текущее состояние, выполняет действия для совпадения. Leader election (через Lease) гарантирует, что только один экземпляр активен. Failure controller-manager не убивает уже работающие Pods, но новые объекты не будут обработаны.
kubectl get pods -n kube-system | grep controller-manager
kubectl get lease -n kube-system kube-controller-manager
kubectl logs -n kube-system kube-controller-manager-master-1Компонент control plane для интеграции с cloud provider (AWS, GCP, Azure). Содержит controllers: Node controller (проверяет, существует ли VM в облаке), Route controller (настраивает сетевые маршруты), Service controller (создаёт cloud LoadBalancer для type: LoadBalancer). Отделён от kube-controller-manager, чтобы декомплексить обновления cloud-specific логики. На bare-metal / on-prem кластерах не используется (или используется minimal version). Каждый облачный провайдер поставляет свой CCM (например, aws-cloud-controller-manager). Включается флагом --cloud-provider=external на kubelet, чтобы он не делал cloud calls.
kubectl get pods -n kube-system | grep cloud-controller
# Service с type: LoadBalancer → CCM создаст AWS NLB/ALB
apiVersion: v1
kind: Service
metadata:
name: web
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
type: LoadBalancer
selector: { app: web }
ports: [{ port: 80, targetPort: 8080 }]Primary node agent, запускается на каждом node. Регистрирует node в кластере, watch'ит API server на предмет Pods, назначенных через spec.nodeName, и запускает контейнеры через CRI (Container Runtime Interface). Отвечает за: pulling images, создание/удаление контейнеров, mount volumes (CSI), запуск probes (liveness/readiness/startup), reporting node и pod status. Конфиг: /var/lib/kubelet/config.yaml (KubeletConfiguration). Запускает static pods из --pod-manifest-path (обычно /etc/kubernetes/manifests). Eviction policies — освобождает место при disk/memory pressure. Если kubelet umer — node переходит в NotReady через nodeMonitorGracePeriod (default 40s).
# На node
systemctl status kubelet
journalctl -u kubelet -f
cat /var/lib/kubelet/config.yaml
ls /etc/kubernetes/manifests/
# С control plane
kubectl describe node worker-1
kubectl get node worker-1 -o yaml | grep -A20 statusNetwork agent на каждом node, реализующий Services через настройку правил на host network stack. Modes: iptables (default, NAT rules), ipvs (более производительный для большого числа Services), nftables (новее, beta/GA в недавних версиях). Когда создаётся Service, kube-proxy watches Endpoints/EndpointSlices и обновляет правила: VIP (ClusterIP) → набор Pod IP с load balancing. Для NodePort — открывает порт на node и форвардит. kube-proxy не handles Pod-to-Pod traffic (это CNI). При замене kube-proxy на eBPF-based (Cilium) — модернизация data path. В v1.35 nftables mode стабилизируется.
kubectl get pods -n kube-system -l k8s-app=kube-proxy
kubectl logs -n kube-system kube-proxy-xxxxx
# На node
iptables-save | grep KUBE-SVC
ipvsadm -L -n # если ipvs modegRPC-based интерфейс между kubelet и container runtime. Позволяет kubelet работать с любым CRI-compatible runtime: containerd (default в большинстве кластеров с 2022), CRI-O (RedHat/OKD), Docker Engine больше не поддерживается напрямую с v1.24 (dockershim удалён). Runtime отвечает за: pulling images, lifecycle контейнеров (run/stop/remove), управление образами, mount volumes на уровне runtime. Под капотом runtime использует low-level OCI runtime (runc, crun, kata). На каждом node — /var/run/containerd/containerd.sock или /var/run/crio/crio.sock. Утилита crictl — CRI-аналог docker CLI для диагностики на node.
# На node
crictl ps
crictl images
crictl logs <container-id>
crictl inspect <container-id>
cat /etc/crictl.yaml
# Узнать runtime
kubectl get node -o wide # колонка CONTAINER-RUNTIMEАбстракция, обеспечивающая стабильный endpoint (DNS-имя и VIP) для группы Pods. Pods ephemeral — их IP меняются; Service решает это через selector (labels → выбор Pods) и автоматическое обновление Endpoints/EndpointSlices. Types: ClusterIP (default, внутренний VIP), NodePort (открывает порт на всех nodes), LoadBalancer (создаёт cloud LB), ExternalName (CNAME DNS). Service получает DNS-имя <name>.<namespace>.svc.cluster.local. Реализуется kube-proxy через iptables/ipvs/nftables правила на каждом node. Для headless service (clusterIP: None) DNS возвращает напрямую Pod IPs.
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
protocol: TCP
# Внутри кластера
curl http://web.default.svc.cluster.localDefault тип Service. Выделяет VIP из service CIDR (например 10.96.0.0/12), доступный только внутри кластера. Все запросы на VIP:port балансируются между Pod replicas по selector. Не доступен извне без Ingress или port-forward. Используется для внутрикластерного service-to-service communication. Если clusterIP: None — headless service: kube-proxy не создаёт правила, DNS возвращает A-records напрямую на Pod IPs (используется в StatefulSet для stable identity, или для service mesh).
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: ClusterIP
selector: { app: backend }
ports:
- port: 8080
targetPort: 8080
# Проверка
kubectl run -it --rm test --image=curlimages/curl -- sh
# curl http://backend:8080Service type, открывающий порт (default range 30000-32767) на ВСЕХ nodes кластера. Запрос на <any-node-ip>:nodePort → ClusterIP → Pod. Используется для внешнего доступа на bare-metal без LoadBalancer, для отладки, или за внешним L4 балансировщиком. Минусы: нестандартные порты, нужен LB перед всеми nodes для HA, неэффективная маршрутизация (request на node без Pod делает extra hop). externalTrafficPolicy: Cluster (default — все nodes, SNAT теряет client IP) или Local (только nodes с Pod, сохраняет client IP, но риск unbalanced load).
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: NodePort
selector: { app: web }
ports:
- port: 80
targetPort: 8080
nodePort: 30080
externalTrafficPolicy: Local
# Доступ
curl http://<node-ip>:30080Service type, создающий внешний load balancer через cloud provider (AWS NLB/ALB, GCP, Azure LB) или MetalLB на bare-metal. Под капотом extends NodePort: cloud LB форвардит traffic на NodePort всех nodes. Получает externalIP через cloud-controller-manager. Annotations настраивают cloud-specific: тип LB, SSL termination, health checks, target groups. loadBalancerSourceRanges — IP whitelist. На bare-metal без MetalLB type LoadBalancer остаётся Pending forever. Стоимость: каждый LB = отдельный cloud resource = $$$. Для HTTP/HTTPS — лучше Ingress (один LB на много services).
apiVersion: v1
kind: Service
metadata:
name: web
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
type: LoadBalancer
loadBalancerSourceRanges:
- 203.0.113.0/24
selector: { app: web }
ports:
- port: 443
targetPort: 8443Особый тип Service — CNAME DNS alias. Не имеет selector, не создаёт Endpoints. Поле externalName указывает на внешний DNS hostname. CoreDNS отдаёт CNAME при resolve <name>.<ns>.svc.cluster.local → externalName. Используется для абстрагирования внешних зависимостей: можно ссылаться на api.payment.svc.cluster.local, а под капотом — payments.example.com. При миграции внешнего сервиса внутрь кластера — поменять только Service, код приложения не трогать. Нет proxying или load balancing — kube-proxy не задействован.
apiVersion: v1
kind: Service
metadata:
name: payment-api
namespace: default
spec:
type: ExternalName
externalName: payments.example.com
# Из Pod
nslookup payment-api.default.svc.cluster.local
# → CNAME payments.example.com → real IPService с clusterIP: None. Не получает VIP, kube-proxy не настраивает правила. CoreDNS вместо одного A-record на VIP возвращает A-records на каждый Pod в Endpoints. Используется для: stateful workloads (StatefulSet требует headless service в spec.serviceName), client-side load balancing, service mesh, peer discovery (Kafka, Cassandra, etcd). Selector работает как обычно — на основе labels формируются EndpointSlices. Для StatefulSet headless service даёт каждому Pod стабильный DNS: <pod>.<service>.<namespace>.svc.cluster.local.
apiVersion: v1
kind: Service
metadata:
name: kafka
spec:
clusterIP: None
selector: { app: kafka }
ports:
- port: 9092
# DNS
nslookup kafka.default.svc.cluster.local
# → возвращает IP всех Kafka pods
nslookup kafka-0.kafka.default.svc.cluster.localСменили старые Endpoints (deprecated) — scalable модель хранения IP/port для Pods, выбранных Service selector. Один Service → несколько EndpointSlices (по умолчанию max 100 endpoints в slice). Это решает проблему: при изменении одного Pod не нужно переписывать гигантский Endpoints для big service. Каждый slice содержит endpoints (address, conditions: ready/serving/terminating, hostname, nodeName, zone). kube-proxy watch'ит EndpointSlices для построения правил. EndpointSlice controller автоматически создаёт slices когда Pod становится Ready (или passes readiness probe).
kubectl get endpointslices
kubectl get endpointslices -l kubernetes.io/service-name=web
kubectl describe endpointslice web-abc12
# Show conditions per endpoint
kubectl get endpointslice web-abc12 -o jsonpath='{.endpoints[*].conditions}'Стандарт plugin для настройки сети контейнеров (CNCF). В Kubernetes CNI plugin вызывается kubelet при создании/удалении Pod через CRI. Plugin assigns IP из Pod CIDR, настраивает veth/bridge/tunnel, обеспечивает Pod-to-Pod connectivity. Популярные: Calico (BGP/IPIP/VXLAN, NetworkPolicy), Cilium (eBPF-based, observability, NetworkPolicy L7), Flannel (простой VXLAN), Weave Net, AWS VPC CNI. CNI config на node: /etc/cni/net.d/. Без CNI plugin Pods запускаются как NotReady с error 'NetworkPluginNotReady'. CNI отвечает за L3 связность; Service routing — это kube-proxy.
ls /etc/cni/net.d/
cat /etc/cni/net.d/10-calico.conflist
# Установка Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
# Проверка
kubectl get pods -n kube-system -l k8s-app=calico-nodeNamespaced ресурс, определяющий разрешённый Ingress/Egress traffic на уровне Pods (firewall-as-code). По умолчанию в Kubernetes 'allow all' — все Pods могут говорить со всеми. NetworkPolicy с podSelector переключает указанные Pods в режим 'default deny' для указанных policyTypes (Ingress, Egress) и явно разрешает что-то. Поддерживается ТОЛЬКО если CNI это реализует (Calico, Cilium, Weave; default Flannel — нет). Правила: from/to с podSelector, namespaceSelector, ipBlock. Поддерживает порты и protocol. Не поддерживает L7 (HTTP path) — для этого нужен service mesh или L7 NetworkPolicy в Cilium.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow
namespace: prod
spec:
podSelector:
matchLabels: { app: api }
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector:
matchLabels: { app: web }
ports:
- port: 8080
egress:
- to:
- podSelector:
matchLabels: { app: db }
ports:
- port: 5432Объект API, описывающий L7 (HTTP/HTTPS) routing rules: host/path → backend Service. Реализуется Ingress Controller (NGINX, Traefik, HAProxy, AWS ALB, GCE), который наблюдает Ingress и Service и настраивает свой прокси/LB. Один LB на много Services вместо отдельного LoadBalancer на каждый. Возможности: virtual hosting (по Host header), path-based routing, TLS termination через Secret типа kubernetes.io/tls, rewrite/redirect через annotations (controller-specific). IngressClass указывает контроллер. С развитием Gateway API Ingress постепенно legacy для сложных сценариев, но остаётся стандартом для простых cases.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts: [app.example.com]
secretName: tls-cert
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port: { number: 80 }Эволюция Ingress, GA с v1.33. Новая модель: GatewayClass (тип шлюза, аналог IngressClass), Gateway (instance — listener на port/protocol/TLS), HTTPRoute/GRPCRoute/TLSRoute/TCPRoute (правила маршрутизации). Решает проблемы Ingress: role-oriented design (cluster admin → app developer), expressive routing (header/query matching, weighted traffic для canary), protocol support (gRPC, TCP, UDP), portable (без annotations-zoo). Один Gateway может обслуживать несколько Routes из разных namespaces (с ReferenceGrant для cross-namespace). Реализуется через те же контроллеры (Envoy Gateway, Istio, Cilium, NGINX Gateway Fabric, GKE Gateway).
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
spec:
parentRefs:
- name: external-gateway
hostnames: [app.example.com]
rules:
- matches:
- path: { type: PathPrefix, value: /api/v2 }
backendRefs:
- name: api-v2
port: 8080
weight: 90
- name: api-v1
port: 8080
weight: 10DNS server, deployed в kube-system namespace, обслуживающий имена внутри кластера. Pods получают /etc/resolv.conf с nameserver = ClusterIP сервиса kube-dns (обычно 10.96.0.10), search domains <ns>.svc.cluster.local svc.cluster.local cluster.local. Резолвит: <service>.<namespace>.svc.cluster.local → ClusterIP, headless service → multiple Pod IPs, <pod>.<service>.<ns>.svc.cluster.local для StatefulSet, ExternalName → CNAME. Конфиг в ConfigMap coredns в kube-system. Плагины: kubernetes, forward (upstream resolve), cache, prometheus (metrics). Проблемы DNS — частая причина flaky приложений (timeout, slow lookup): использовать ndots: 2, podDNSConfig.
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get cm coredns -n kube-system -o yaml
kubectl run -it --rm dns --image=busybox -- sh
# nslookup kubernetes
# nslookup web.prod.svc.cluster.local
# cat /etc/resolv.confСпособ предоставить контейнерам persistent или shared storage внутри Pod. В отличие от Docker volume — определяется в spec.volumes, монтируется в каждый контейнер через volumeMounts. Типы: ephemeral (emptyDir — живёт с Pod, hostPath — папка на node), projected (configMap, secret, downwardAPI, serviceAccountToken — собирает несколько источников в одну директорию), persistent (persistentVolumeClaim — связь с PV). CSI ephemeral volumes — драйвер создаёт volume inline в Pod spec. Lifetime: ephemeral — Pod lifetime; PVC — независимый от Pod.
apiVersion: v1
kind: Pod
metadata:
name: vol-demo
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: cache
mountPath: /cache
- name: config
mountPath: /etc/config
volumes:
- name: cache
emptyDir: {}
- name: config
configMap:
name: app-configЭпhemeral volume, создаваемый когда Pod assigned на node, и удаляемый когда Pod удалён (НЕ при container restart). Используется для: scratch space, shared filesystem между контейнерами в Pod (классический use-case sidecar), кэширования. Хранится на node disk (/var/lib/kubelet/pods/<pod-uid>/volumes/...), может быть на memory (medium: Memory — RAM tmpfs, считается против memory limit Pod). sizeLimit ограничивает размер; превышение → eviction Pod из-за DiskPressure или OOM.
apiVersion: v1
kind: Pod
metadata:
name: shared-data
spec:
containers:
- name: writer
image: busybox
command: ['sh', '-c', 'echo data > /shared/file; sleep 3600']
volumeMounts: [{ name: shared, mountPath: /shared }]
- name: reader
image: busybox
command: ['sh', '-c', 'cat /shared/file; sleep 3600']
volumeMounts: [{ name: shared, mountPath: /shared }]
volumes:
- name: shared
emptyDir:
medium: Memory
sizeLimit: 100MiМонтирует файл или директорию с host (node) filesystem в Pod. Опасно: ломает изоляцию, привязывает Pod к конкретному node (state не переедет), даёт доступ к данным node (security risk). Use cases: node-level агенты (мониторинг — /proc, /sys, log collectors — /var/log/containers), CSI drivers, dev/test. type: DirectoryOrCreate, FileOrCreate, Directory, File, Socket, etc. Pod Security Standards Baseline/Restricted запрещают hostPath. Для обычных workloads — используй emptyDir, PVC, CSI ephemeral, projected — никогда hostPath.
apiVersion: v1
kind: Pod
metadata:
name: log-reader
spec:
containers:
- name: app
image: busybox
command: ['sh', '-c', 'tail -f /host-logs/syslog']
volumeMounts:
- name: logs
mountPath: /host-logs
readOnly: true
volumes:
- name: logs
hostPath:
path: /var/log
type: DirectoryCluster-scoped ресурс, представляющий физический storage (NFS share, EBS volume, Ceph RBD, vSphere disk). Создаётся cluster admin (static provisioning) или dynamically через StorageClass. Имеет: capacity, accessModes (RWO/ROX/RWX/RWOP), persistentVolumeReclaimPolicy (Retain/Delete; Recycle deprecated), storageClassName, volumeMode (Filesystem/Block), и driver-specific spec (nfs/csi/awsElasticBlockStore). Связывается с PVC через binding controller — match по storageClass, size, accessModes. Phases: Available → Bound → Released → Failed.
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-1
spec:
capacity:
storage: 10Gi
accessModes: [ReadWriteMany]
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-manual
nfs:
server: nfs.internal
path: /exports/dataNamespaced request на storage, который потом монтируется в Pod. Указывает: storageClassName (если '' — static binding only; если nil — default StorageClass), accessModes, resources.requests.storage, optional volumeMode и selector. Binding controller matches PVC с PV: ищет available PV с подходящими параметрами или (если StorageClass) запускает provisioner для создания нового PV. PVC stays Bound while Pod использует его. Удаление PVC: если PV reclaimPolicy=Delete — PV и подложка удаляются; Retain — PV остаётся Released, требует manual cleanup.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
storageClassName: standard
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata: { name: app }
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: dataОписывает 'класс' storage для dynamic provisioning. Когда PVC ссылается на StorageClass, provisioner (CSI driver) автоматически создаёт PV нужного размера и параметров. Поля: provisioner (driver name, например ebs.csi.aws.com), parameters (driver-specific: type, fsType, encrypted), reclaimPolicy (Delete/Retain — default Delete), volumeBindingMode (Immediate — PV создаётся сразу; WaitForFirstConsumer — ждёт Pod, чтобы выбрать топологию), allowVolumeExpansion (можно ли расширить PVC). Default StorageClass помечен annotation storageclass.kubernetes.io/is-default-class=true.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: 'true'
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: '3000'
throughput: '125'
encrypted: 'true'
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: trueСтандарт plugin для storage в Kubernetes (и других orchestrators). Заменил in-tree volume plugins (EBS, GCE PD, vSphere — все переехали out-of-tree). CSI driver состоит из: controller plugin (StatefulSet/Deployment в kube-system — provisioning, attach, resize) и node plugin (DaemonSet — mount/unmount на node). External sidecars: external-provisioner, external-attacher, external-resizer, external-snapshotter. CSIDriver и CSINode объекты регистрируют driver. Features: dynamic provisioning, volume expansion online, snapshots/clones, raw block volumes, generic ephemeral volumes.
kubectl get csidrivers
kubectl get csinodes
kubectl get pods -n kube-system -l app=ebs-csi-controller
kubectl get pods -n kube-system -l app=ebs-csi-node
kubectl get volumeattachmentsAPI объект для point-in-time copy PVC. Часть snapshot.storage.k8s.io API group, реализуется через CSI driver с поддержкой snapshots. Объекты: VolumeSnapshotClass (как StorageClass — параметры), VolumeSnapshot (запрос пользователя), VolumeSnapshotContent (cluster-scoped, реальный snapshot). Из snapshot можно создать новый PVC (dataSource: VolumeSnapshot) — clone волума. Использование: backup, restore, dev/test data refresh. Snapshots обычно incremental на cloud (EBS), быстрые, но не replacement для off-site backup (живут в той же AZ/cloud).
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: data-snap-2026-05-13
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-restored
spec:
storageClassName: standard
dataSource:
name: data-snap-2026-05-13
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 5Gi } }Определяют, как volume может быть mounted nodes. ReadWriteOnce (RWO) — read/write одним node (Pod на этом node могут писать; classic для block storage EBS, GCE PD). ReadOnlyMany (ROX) — read-only многими nodes. ReadWriteMany (RWX) — read/write многими nodes (нужно для shared filesystem: NFS, CephFS, EFS, Azure Files). ReadWriteOncePod (RWOP, GA с v1.29) — read/write одним Pod (даже не node, новее RWO; useful для leader-election volumes). Поддержка зависит от driver: EBS — RWO only; EFS — RWO, ROX, RWX. accessMode не enforced строго — это hint, реальные ограничения у driver.
kubectl get pv -o custom-columns=NAME:.metadata.name,MODES:.spec.accessModes
# RWO — only one node at a time
# Если Pod на node A держит PVC, новый Pod на node B → 'Multi-Attach Error'
kubectl get events --field-selector reason=FailedAttachVolumeNamespaced API объект для non-confidential конфигурации в виде key-value pairs. Хранится в etcd в plaintext. Размер до 1 MiB на ConfigMap. Способы потребления в Pod: (1) env vars через valueFrom.configMapKeyRef или envFrom.configMapRef, (2) command args через $(VAR), (3) volume mount — каждый ключ становится файлом в директории. При update ConfigMap: env vars НЕ обновляются (нужен restart Pod), volume mount обновляется автоматически с задержкой (eventual через kubelet sync, ~1 minute), но subPath mount НЕ обновляется. Immutable ConfigMap (immutable: true) — оптимизация для статичных конфигов.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: info
config.yaml: |
server:
port: 8080
timeout: 30s
immutable: false
---
spec:
containers:
- name: app
image: app:v1
envFrom:
- configMapRef:
name: app-config
volumeMounts:
- name: cfg
mountPath: /etc/app
volumes:
- name: cfg
configMap: { name: app-config }Namespaced объект для конфиденциальных данных (passwords, tokens, certificates). Структура та же что ConfigMap, но values base64-encoded. ВНИМАНИЕ: base64 — это НЕ encryption, это encoding. Real protection — encryption at rest etcd (EncryptionConfiguration), RBAC, не printing в logs/events. Types: Opaque (default, arbitrary key-value), kubernetes.io/tls (tls.crt + tls.key), kubernetes.io/dockerconfigjson (image pull), kubernetes.io/service-account-token (legacy, auto-mounted в SA), kubernetes.io/basic-auth, kubernetes.io/ssh-auth. Consumption: env vars (статичный) или volume mount (рекомендуется — обновляется). Размер до 1 MiB. Для динамичных secrets — External Secrets Operator + Vault/AWS Secrets Manager.
apiVersion: v1
kind: Secret
metadata:
name: db-creds
type: Opaque
data:
username: YWRtaW4=
password: czNjcjN0
---
# Использование
spec:
containers:
- name: app
image: app:v1
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-creds
key: usernameIdentity для процессов внутри Pods, used для аутентификации в API server. Каждый namespace имеет default ServiceAccount, auto-assigned Pods без явного указания. Pod получает projected token volume на /var/run/secrets/kubernetes.io/serviceaccount/token (с v1.22+ — это short-lived bound token через TokenRequest API, auto-rotated). Token используется для RBAC (RoleBinding к ServiceAccount). automountServiceAccountToken: false отключает mount, если Pod не нужно API. imagePullSecrets на ServiceAccount auto-attached к Pods, использующим этот SA.
apiVersion: v1
kind: ServiceAccount
metadata:
name: deploy-bot
namespace: ci
imagePullSecrets:
- name: regcred
automountServiceAccountToken: true
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deploy-bot-bind
namespace: ci
subjects:
- kind: ServiceAccount
name: deploy-bot
namespace: ci
roleRef:
kind: Role
name: deployer
apiGroup: rbac.authorization.k8s.ioVolume type, mounting несколько источников (ConfigMap, Secret, downwardAPI, serviceAccountToken) в одну директорию. Удобно когда приложение ожидает все конфиги в одном месте. Каждый источник имеет path внутри volume. Token sources поддерживают audience, expirationSeconds — current bound token mechanism (v1.22+), more secure чем static SA token. Используется автоматически kubelet для /var/run/secrets/kubernetes.io/serviceaccount.
apiVersion: v1
kind: Pod
metadata: { name: projected }
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: combined
mountPath: /etc/app
volumes:
- name: combined
projected:
sources:
- configMap: { name: app-config }
- secret: { name: db-creds }
- downwardAPI:
items:
- path: 'labels'
fieldRef: { fieldPath: metadata.labels }
- serviceAccountToken:
path: token
audience: vault
expirationSeconds: 3600Шифрование Secrets (и других ресурсов) в etcd. По умолчанию etcd хранит данные в plaintext на диске — root на etcd node может прочитать все Secrets. EncryptionConfiguration в kube-apiserver --encryption-provider-config указывает: какие resources шифровать (secrets, configmaps), какие providers использовать (aescbc, aesgcm, kms — для KMS интеграции с AWS/GCP/Azure/HashiCorp Vault), порядок providers (первый — для записи, все — для чтения, что позволяет rotate keys). После включения нужно перешифровать существующие данные: kubectl get secrets -A -o json | kubectl replace -f -.
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: [secrets]
providers:
- aescbc:
keys:
- name: key1
secret: <base64 32-byte key>
- identity: {}
# Re-encrypt existing
kubectl get secrets --all-namespaces -o json | kubectl replace -f -Secret типа kubernetes.io/dockerconfigjson, содержащий credentials для pulling images из private registry. Прикрепляется к Pod через spec.imagePullSecrets или к ServiceAccount (тогда auto-attached всем Pods c этим SA). Создаётся: kubectl create secret docker-registry NAME --docker-server=... --docker-username=... --docker-password=... --docker-email=... . Без него Pod из private registry получит ImagePullBackOff с 401/403. Multiple imagePullSecrets allowed (попробует все). Для big org — лучше один SA с pull secret на namespace, чем дублировать в каждом Pod.
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=ci \
--docker-password=$TOKEN \
[email protected]
---
apiVersion: v1
kind: Pod
metadata: { name: private-app }
spec:
containers:
- name: app
image: registry.example.com/team/app:v1
imagePullSecrets:
- name: regcredSpec для определения privilege и access control для Pod/Container. На Pod-level (spec.securityContext) применяется ко всем контейнерам: runAsUser, runAsGroup, runAsNonRoot, fsGroup (group ownership volumes), supplementalGroups, seLinuxOptions, seccompProfile, sysctls. На Container-level (containers[].securityContext) переопределяет: добавляет capabilities (add/drop), privileged, allowPrivilegeEscalation, readOnlyRootFilesystem, procMount. Best practices: runAsNonRoot: true, readOnlyRootFilesystem: true, drop ALL capabilities, seccompProfile: RuntimeDefault, allowPrivilegeEscalation: false — это минимум для Pod Security Standards Restricted.
apiVersion: v1
kind: Pod
metadata: { name: secure-app }
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
seccompProfile: { type: RuntimeDefault }
containers:
- name: app
image: app:v1
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: [ALL]Стандартный механизм авторизации в Kubernetes — кто может делать что на каких ресурсах. Объекты в rbac.authorization.k8s.io/v1: Role (namespaced — права на ресурсы в одном NS), ClusterRole (cluster-scoped — права на cluster-wide ресурсы или для использования в нескольких NS), RoleBinding (привязка Role или ClusterRole к Subject в namespace), ClusterRoleBinding (привязка ClusterRole к Subject cluster-wide). Subjects: User, Group, ServiceAccount. Rules: apiGroups, resources, verbs (get, list, watch, create, update, patch, delete), resourceNames (опционально). Aggregated ClusterRoles — combine roles by label.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: pod-reader
rules:
- apiGroups: ['']
resources: [pods, pods/log]
verbs: [get, list, watch]
---
kind: RoleBinding
metadata: { name: read-pods, namespace: dev }
subjects:
- kind: User
name: [email protected]
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
# Проверка
kubectl auth can-i list pods [email protected] -n devNamespaced RBAC объект, определяющий список разрешённых verbs на resources внутри ОДНОГО namespace. Например, Role 'developer' в namespace 'dev' даёт create/get/list/update Pods/Deployments/Services. Сама по себе Role ничего не даёт — нужна RoleBinding, привязывающая Role к Subject. Rules могут специфицировать resourceNames для гранулярного доступа (например, только Secret с именем 'my-secret'). Sub-resources (pods/log, pods/exec, pods/portforward) задаются отдельно — log не дают вместе с get pod автоматически.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: ci
name: deployer
rules:
- apiGroups: [apps]
resources: [deployments, replicasets]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: ['']
resources: [pods, pods/log]
verbs: [get, list]
- apiGroups: ['']
resources: [configmaps]
resourceNames: [app-config]
verbs: [get, update]Namespaced объект, привязывающий Role (или ClusterRole) к Subject (User, Group, ServiceAccount) внутри namespace. Subject получает permissions из roleRef в этом namespace. Можно binding ClusterRole в RoleBinding — тогда permissions ClusterRole применяются только к ресурсам этого namespace (удобно: один ClusterRole 'reader' + RoleBinding в каждом namespace). Subject ServiceAccount можно binding из другого namespace (указав subjects.namespace), но subject User/Group — глобальные сущности.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployer-bind
namespace: ci
subjects:
- kind: ServiceAccount
name: github-actions
namespace: ci
- kind: Group
name: 'devops-team'
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: deployer
apiGroup: rbac.authorization.k8s.ioCluster-scoped RBAC объект. В отличие от Role: (1) даёт доступ к cluster-scoped ресурсам (Nodes, PV, ClusterRoles, namespaces); (2) даёт доступ к non-resource URLs (/healthz, /metrics); (3) даёт доступ к namespaced ресурсам ACROSS ALL namespaces (через ClusterRoleBinding) или в одном namespace (через RoleBinding). Built-in ClusterRoles: cluster-admin, admin, edit, view. Aggregated ClusterRole — собирается из других ClusterRoles по aggregationRule (label selector), удобно для extensible permissions (CRDs, operators).
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata: { name: node-reader }
rules:
- apiGroups: ['']
resources: [nodes, nodes/status]
verbs: [get, list, watch]
- nonResourceURLs: ['/metrics', '/healthz']
verbs: [get]
---
# Built-ins
kubectl get clusterrole cluster-admin -o yaml
kubectl get clusterrole view -o yamlCluster-scoped binding: привязывает ClusterRole к Subject cluster-wide. Subject получает permissions ClusterRole на всех ресурсах (cluster-scoped и namespaced во всех NS). Используется осторожно — даёт wide permissions. Например, cluster-admin ClusterRoleBinding к user даёт full admin доступ. Default ClusterRoleBindings: system:masters (для kubeadm certs), cluster-admin, system:node, system:kube-controller-manager. Для большинства приложений — RoleBinding к ClusterRole в нужном NS, не ClusterRoleBinding.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata: { name: admin-bind }
subjects:
- kind: User
name: [email protected]
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
# Проверка
kubectl auth can-i '*' '*' [email protected]Три baseline policies для security защиты Pod: Privileged (no restrictions — wide-open для system workloads), Baseline (минимум restrictions — запрещает hostNetwork, hostPath, privileged containers, добавление capabilities, host ports etc), Restricted (heavily restricted — требует runAsNonRoot, dropping all capabilities, seccompProfile RuntimeDefault, allowPrivilegeEscalation: false, readOnlyRootFilesystem не required но рекомендован). PSS — это спецификация policies, реализуется Pod Security Admission (built-in admission controller, GA с v1.25) или внешним policy engine (Kyverno, OPA Gatekeeper).
# Применить PSS уровень к namespace
apiVersion: v1
kind: Namespace
metadata:
name: prod
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
# Test
kubectl run priv --image=nginx --privileged -n prod
# Error: violates PodSecurity 'restricted:latest'Built-in admission controller (GA v1.25), enforce'щий Pod Security Standards на уровне namespace через labels. Три mode: enforce (rejects non-compliant Pods), audit (logs violation в audit), warn (warning в kubectl/dashboard). Каждый mode имеет version label (latest, v1.30, etc — для постепенного rollout новых правил). Не покрывает: PSP-style mutation, fine-grained customisation, cluster-wide policies — для этого используются Kyverno или Gatekeeper. Заменил deprecated PodSecurityPolicy (PSP, удалён в v1.25). exemptions можно настроить в AdmissionConfiguration.
kubectl label ns app pod-security.kubernetes.io/enforce=baseline
kubectl label ns app pod-security.kubernetes.io/warn=restricted
# AdmissionConfiguration
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: baseline
enforce-version: latest
exemptions:
namespaces: [kube-system]Механизмы health-check контейнеров, выполняемые kubelet. Три типа: livenessProbe (если fail — kubelet перезапускает container), readinessProbe (если fail — Pod удаляется из EndpointSlices Service, traffic не идёт), startupProbe (для медленно стартующих apps — отключает другие probes, пока не пройдёт; защищает от убийства liveness'ом во время startup). Handlers: exec (cmd в container), httpGet (HTTP request на path:port), tcpSocket (open TCP), grpc (с v1.27 GA — gRPC health protocol). Параметры: initialDelaySeconds, periodSeconds, timeoutSeconds, successThreshold, failureThreshold.
containers:
- name: app
image: app:v1
startupProbe:
httpGet: { path: /healthz, port: 8080 }
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet: { path: /healthz, port: 8080 }
periodSeconds: 10
timeoutSeconds: 1
failureThreshold: 3
readinessProbe:
httpGet: { path: /ready, port: 8080 }
periodSeconds: 5
failureThreshold: 2Pod-level field, определяющий, перезапускается ли контейнер при exit. Always (default — для Deployment/StatefulSet, ВСЕГДА restart, exponential backoff: 10s, 20s, 40s, 80s, 160s, 300s cap), OnFailure (рестарт только если exit code != 0; используется для Job), Never (никогда; контейнер завершён → Pod в Succeeded/Failed). Применяется на Pod level (одинаковый для всех контейнеров). С v1.28+ (beta v1.29, GA v1.33) появилось container-level restartPolicy на init containers — это и определяет native sidecar (значение Always).
apiVersion: v1
kind: Pod
metadata: { name: batch }
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: worker:v1
# Native sidecar (GA v1.33)
spec:
initContainers:
- name: sidecar
image: log-shipper:v1
restartPolicy: Always # native sidecar
containers:
- name: app
image: app:v1Pod-level: время (sec), даваемое контейнерам для graceful shutdown после SIGTERM перед kubelet'овским SIGKILL. Default 30s. Процесс termination: (1) Pod помечается deletionTimestamp; (2) kubelet вызывает preStop hook (если есть) — синхронно; (3) SIGTERM сигнал процессу 1 в каждом контейнере; (4) ждёт grace period; (5) если контейнер ещё жив — SIGKILL. Параллельно: Pod удаляется из EndpointSlices, traffic перестаёт идти (но это асинхронно — нужно preStop sleep чтобы дать proxy time на обновление правил). Job/CronJob c длинной работой — увеличить до часов.
spec:
terminationGracePeriodSeconds: 60
containers:
- name: app
image: app:v1
lifecycle:
preStop:
exec:
command: ['/bin/sh', '-c', 'sleep 10 && ./drain.sh']
# При delete: SIGTERM → ждём 60s → SIGKILLLifecycle hook, вызываемый kubelet СИНХРОННО перед SIGTERM. Handler — exec (command в container) или httpGet (HTTP request на endpoint). Используется для: drain active connections (load balancer registration), finalize state, sleep чтобы дать time service mesh / kube-proxy обновить routes до того как процесс умрёт. SIGTERM не отправляется пока preStop running (но грейс period начинает течь). postStart hook — аналог для startup, но не блокирует Ready state (приложение может ответить до postStart).
lifecycle:
postStart:
exec:
command: ['/bin/sh', '-c', 'echo started > /tmp/started']
preStop:
httpGet:
path: /shutdown
port: 8080
# Или для zero-downtime — задержка перед SIGTERM
lifecycle:
preStop:
exec:
command: ['/bin/sh', '-c', 'sleep 15']Container, выполняющийся ДО основных containers Pod. Запускаются последовательно (один за другим), каждый должен exit 0 чтобы перейти к следующему. Используется для: pre-conditions (wait DB ready), data setup (download config, clone repo, generate certs), permission fixes (chown volume). Образ может быть отличным от app (busybox, alpine, sdk image). Resources подсчитываются: max(sum app containers, max init container). Logs: kubectl logs <pod> -c <init-container>. С v1.29+ можно сделать init container 'native sidecar' через restartPolicy: Always — он работает параллельно с app containers до конца Pod.
apiVersion: v1
kind: Pod
metadata: { name: init-demo }
spec:
initContainers:
- name: wait-db
image: busybox
command: ['sh', '-c', 'until nslookup postgres; do sleep 2; done']
- name: migrate
image: migrate:v1
command: ['./migrate.sh']
containers:
- name: app
image: app:v1Pattern: дополнительный container в Pod, расширяющий функциональность app (логирование, прокси, sync). Классически реализован как обычный container c shared volume — но проблема: при stop app sidecar не получает signal порядка, при init работа sidecar не доступна init containers. Native Sidecar (v1.28 beta, v1.29 stable) — init container c restartPolicy: Always: запускается до app containers (доступен init), не блокирует app start (когда startupProbe pass), shutdown в reverse order. Pattern uses: log shipper (Fluent Bit), service mesh proxy (Envoy sidecar — Istio, Linkerd), config reloader, monitoring.
# Native sidecar (GA v1.33)
apiVersion: v1
kind: Pod
metadata: { name: with-sidecar }
spec:
initContainers:
- name: log-shipper
image: fluent-bit:3.0
restartPolicy: Always # native sidecar
volumeMounts:
- { name: logs, mountPath: /var/log/app }
containers:
- name: app
image: app:v1
volumeMounts:
- { name: logs, mountPath: /var/log/app }
volumes:
- name: logs
emptyDir: {}Логическая группировка API ресурсов. URL формат: /apis/<group>/<version>/<resource>. Core group (пустая, legacy) — /api/v1/* для Pod, Service, ConfigMap, Secret, Node, PV. Named groups: apps/v1 (Deployment, StatefulSet, DaemonSet, ReplicaSet), batch/v1 (Job, CronJob), networking.k8s.io/v1 (NetworkPolicy, Ingress), rbac.authorization.k8s.io/v1 (Role, RoleBinding), storage.k8s.io/v1 (StorageClass), policy/v1 (PodDisruptionBudget). CRDs создают новые groups (cert-manager.io, etc). Versions per group: v1alpha1, v1beta1, v1 — указывает на stability.
kubectl api-versions
kubectl api-resources
kubectl api-resources --api-group=apps
kubectl get --raw /apis/apps/v1 | jq
kubectl explain deployment
kubectl explain deployment.spec.strategy --api-version=apps/v1Официальный CLI для взаимодействия с Kubernetes API. Команды: get/describe/logs (read), create/apply/edit/patch/replace (write), delete, exec/port-forward/attach (debug), rollout/scale/autoscale (workload management), auth/cluster-info/config/api-resources (meta). Imperative (create/run/expose) vs declarative (apply -f). Output formats: -o yaml/json/wide/jsonpath/custom-columns/go-template. Plugins via kubectl-<name> binaries (Krew package manager). Performance tip: --use-protocol-buffers, --as для impersonation. Aliases: k=kubectl, экзамене обязателен.
kubectl get pods -n prod -o wide
kubectl describe pod web-abc
kubectl logs -f web-abc -c app
kubectl exec -it web-abc -- sh
kubectl apply -f manifest.yaml
kubectl delete pod web-abc --grace-period=0 --force
kubectl rollout undo deployment web
kubectl get pod -o jsonpath='{.items[*].metadata.name}'
kubectl auth can-i create podsYAML файл (~/.kube/config или $KUBECONFIG path), хранящий credentials и connection details. Структура: clusters (apiserver URL + CA), users (auth: client cert, token, exec plugin для OIDC/IAM), contexts (cluster + user + namespace). current-context указывает default. Один kubeconfig может содержать много контекстов (multi-cluster setup). Переключение: kubectl config use-context. Утилиты: kubectx, kubens. Безопасность: содержит секреты, права 600. Merge нескольких файлов: KUBECONFIG=~/.kube/c1:~/.kube/c2 kubectl config view --flatten.
kubectl config view
kubectl config get-contexts
kubectl config current-context
kubectl config use-context prod
kubectl config set-context --current --namespace=app
kubectl config delete-context old-cluster
# Multiple files
export KUBECONFIG=~/.kube/dev:~/.kube/prod
kubectl config view --flatten > ~/.kube/mergedИменованная комбинация (cluster, user, namespace) в kubeconfig. Переключение контекстов меняет ВСЕ три атрибута одновременно. Контекст определяет какой кластер использует kubectl, как аутентифицируется, и какой namespace по умолчанию. Один user может работать с несколькими clusters; один cluster может иметь несколько users (с разным RBAC). Удобно для разделения dev/stage/prod. Тулзы вроде kubectx показывают контексты, fzf-style selection. На экзамене CKAD — переключение между namespaces намного чаще, чем контексты.
kubectl config get-contexts
# CURRENT NAME CLUSTER AUTHINFO NAMESPACE
# * dev-app dev jane app
kubectl config use-context prod-app
kubectl config set-context dev-app --namespace=dev
kubectl config rename-context old newМеханизм API server для подписки на изменения ресурсов в реальном времени. Клиент делает GET с параметром watch=true (или kubectl get --watch) — соединение остаётся открытым, server шлёт events (ADDED, MODIFIED, DELETED, ERROR, BOOKMARK) при изменениях. Контроллеры активно используют watch для reconciliation: kube-controller-manager, kubelet, kube-proxy watching API server. Optimization: resourceVersion (start from), label/field selectors, BOOKMARK events для re-establishing connection без re-list. Реализация — long polling over chunked HTTP или HTTP/2 streaming.
kubectl get pods --watch
kubectl get events --watch
kubectl get --raw '/api/v1/namespaces/default/pods?watch=true&timeoutSeconds=120'
# В клиентских библиотеках (client-go)
# informer pattern: List + Watch + local cache + reconcileCluster-scoped объект, расширяющий Kubernetes API новым типом ресурса. После apply CRD пользователи могут создавать инстансы Custom Resource (CR), работать с ним через kubectl. CRD задаёт: group, names (kind, plural, singular, shortNames), scope (Namespaced/Cluster), versions, schema (OpenAPI v3), validation, subresources (status, scale), printerColumns, conversion strategy (multi-version). CR сам по себе только хранит data — для логики нужен controller (operator), watching CR и reconciling реальное состояние. Examples: Prometheus, cert-manager, ArgoCD, Istio — все используют CRD.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: backups.storage.example.com
spec:
group: storage.example.com
scope: Namespaced
names:
plural: backups
singular: backup
kind: Backup
shortNames: [bk]
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
schedule: { type: string }Default strategy для Deployment. Постепенная замена старых Pods новыми: создаётся новый ReplicaSet, scaled up, старый scaled down. Параметры: maxSurge (default 25% — сколько Pods СВЕРХ replicas можно создать одновременно), maxUnavailable (default 25% — сколько Pods можно убрать одновременно). Можно задавать абсолютно (1) или в %. Безопасный update требует readiness probes — иначе balancer пошлёт traffic в not-ready Pod. progressDeadlineSeconds (default 600) — таймаут rollout. minReadySeconds — задержка перед марком Pod available после ready (sanity wait).
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 0 # zero-downtime
minReadySeconds: 10
progressDeadlineSeconds: 300
# Force rollout
kubectl rollout restart deployment web
kubectl rollout status deployment web
kubectl rollout history deployment webStrategy для Deployment, убивающая ВСЕ старые Pods перед созданием новых — это означает downtime. Используется когда: app не поддерживает running multiple versions одновременно (например, schema migration с breaking change на shared storage, singleton workloads, app использующий exclusive RWO PVC). maxSurge/maxUnavailable не применимы. Быстрее RollingUpdate (меньше overhead), но опасно для production. После Recreate Pods начинают одновременно — Storage / DB / cache могут не справиться с нагрузкой connection storm.
apiVersion: apps/v1
kind: Deployment
metadata: { name: legacy-app }
spec:
strategy:
type: Recreate
replicas: 3
selector:
matchLabels: { app: legacy }
template:
metadata:
labels: { app: legacy }
spec:
containers:
- name: app
image: legacy:v2Strategy: одновременно работают две полные версии приложения — Blue (current) и Green (new). Traffic переключается с Blue на Green одномоментно (switch Service selector или Ingress backend). Откат — мгновенный обратный switch. Pros: zero-downtime, instant rollback. Cons: 2x ресурсы во время transition. Реализация в native Kubernetes — два Deployments (web-blue, web-green) и Service с selector, который меняется через kubectl patch или label updates. Лучше реализуется через Argo Rollouts, Flagger, который автоматизирует переключение, smoke tests, rollback.
# Service переключает selector
apiVersion: v1
kind: Service
metadata: { name: web }
spec:
selector:
app: web
version: blue # переключить на green
ports: [{ port: 80, targetPort: 8080 }]
---
# Деплои blue и green parallel
kubectl get deploy -l app=web
# web-blue, web-green
kubectl patch svc web -p '{"spec":{"selector":{"version":"green"}}}'Strategy: новая версия деплоится постепенно — сначала на маленький % трафика (5-10%), мониторится, затем расширяется. Откат — уменьшить % обратно до 0. Pros: limited blast radius, real production data testing. Cons: сложнее реализация чем blue-green. Native реализация: два Deployments с разным replicas (web-stable 9, web-canary 1) — Service селектит обе по common label. Weighted traffic точнее через service mesh (Istio VirtualService) или Argo Rollouts / Flagger (auto-promote по metrics из Prometheus).
# Два Deployments, общий Service
apiVersion: apps/v1
kind: Deployment
metadata: { name: web-stable }
spec:
replicas: 9
selector: { matchLabels: { app: web } }
template:
metadata: { labels: { app: web, track: stable } }
spec: { containers: [{ name: app, image: app:v1 }] }
---
kind: Deployment
metadata: { name: web-canary }
spec:
replicas: 1 # 10% трафика
selector: { matchLabels: { app: web } }
template:
metadata: { labels: { app: web, track: canary } }
spec: { containers: [{ name: app, image: app:v2 }] }Объект (policy/v1), ограничивающий количество voluntary disruptions Pods приложения. Voluntary disruptions: drain node (kubectl drain), cluster autoscaler scale-down, manual delete. Involuntary (node crash, hardware failure) НЕ контролируется PDB. Поля: selector (какие Pods), minAvailable ИЛИ maxUnavailable (число или %). Eviction API проверяет PDB: если eviction нарушит budget — отказ. Without PDB кластер может вынести все Pods одновременно. Для HA: minAvailable: 2 или maxUnavailable: 1. unhealthyPodEvictionPolicy: IfHealthyBudget (default — не evict unhealthy) или AlwaysAllow (evict unhealthy всегда).
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2 # всегда минимум 2 Pod
selector:
matchLabels: { app: web }
unhealthyPodEvictionPolicy: AlwaysAllow
# Проверка
kubectl get pdb
kubectl describe pdb web-pdbPackage manager для Kubernetes (CNCF graduated). Управляет lifecycle 'release' — instance Chart, deployed в namespace. Команды: helm install <release> <chart>, helm upgrade, helm rollback, helm uninstall. Helm 3 — client-only (без Tiller на cluster), все state хранится как Secret в namespace release. Repositories — место хранения charts (Artifact Hub, OCI registries). Values flattening: default values.yaml + user values + --set CLI overrides. Hooks: pre-install, post-install, pre-upgrade и т.д. — для миграций, backup. Helm — стандарт для распространения K8s apps.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo redis
helm install my-redis bitnami/redis --namespace cache --create-namespace
helm upgrade my-redis bitnami/redis --set replica.replicaCount=3
helm list -A
helm rollback my-redis 1
helm uninstall my-redisHelm package — директория с templates, values, dependencies. Структура: Chart.yaml (metadata: name, version, appVersion, dependencies), values.yaml (default config), templates/ (Go-template манифесты с {{ .Values.foo }} interpolation), templates/_helpers.tpl (named templates, helpers), templates/NOTES.txt (post-install message), charts/ (sub-charts), crds/ (CRD installed before main install). Template engine — Go template + Sprig functions + Helm-specific (include, required, tpl, lookup). Packaging: helm package . — создаёт tgz. Publishing: chart repo (index.yaml) или OCI registry (helm push oci://...).
# Структура chart
mychart/
Chart.yaml # metadata
values.yaml # defaults
templates/
deployment.yaml # use {{ .Values.image.tag }}
service.yaml
_helpers.tpl
NOTES.txt
charts/ # subcharts
crds/
# Создание
helm create mychart
helm lint mychart
helm template mychart --debug
helm package mychartИнстанс Chart, deployed в namespace. Имеет уникальное имя (per namespace), revision (incremented с каждым upgrade), status (deployed, failed, pending-upgrade, uninstalled). State хранится в Secret в release namespace (sh.helm.release.v1.<release>.v<revision>) с base64-encoded manifests + values. Helm 3 поддерживает много releases одного chart в namespace. helm history <release> показывает все revisions. helm rollback <release> <revision> — откат на старый snapshot. При uninstall секреты удаляются (--keep-history оставляет).
helm install web ./mychart -n prod
helm upgrade web ./mychart --set replicas=5 -n prod
helm history web -n prod
# REVISION STATUS CHART DESCRIPTION
# 1 superseded mychart-1 Install complete
# 2 deployed mychart-1 Upgrade complete
helm rollback web 1 -n prod
helm get values web -n prod
helm get manifest web -n prodTool для template-free customization Kubernetes manifests. Интегрирован в kubectl (kubectl apply -k <dir>). Подход: base/ — manifest для общего, overlays/ — патчи для окружений (dev, stage, prod). kustomization.yaml декларирует resources, namePrefix, namespace, commonLabels, configMapGenerator, secretGenerator, patches (strategic merge, JSON 6902), replacements. Преимущество над Helm: нет template engine, плоский YAML, легко прочитать diff. Минус: меньше абстракции для shared configs. Часто используется в GitOps (ArgoCD, Flux).
# base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: web
---
# overlays/prod/kustomization.yaml
resources:
- ../../base
namespace: prod
namePrefix: prod-
replicas:
- name: web
count: 10
patches:
- path: replicas-patch.yaml
images:
- name: web
newTag: v2.0.0
# Применение
kubectl apply -k overlays/prod
kustomize build overlays/prodTool для запуска local Kubernetes cluster в Docker контейнерах (node = docker container). Использует kubeadm под капотом. Команды: kind create cluster (одно-нодовый по умолчанию), kind create cluster --config (multi-node, port-mappings, registries), kind get clusters, kind delete cluster, kind load docker-image (загрузить локальный image в cluster без registry). Идеально для local dev и CI (faster чем minikube для большинства). Alternatives: minikube (VM-based, multi-driver), k3d (K3s в Docker), Docker Desktop K8s.
kind create cluster --name dev --image kindest/node:v1.35.0
# Multi-node config
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
# Load local image
docker build -t myapp:dev .
kind load docker-image myapp:dev --name devПлатформа практических экзаменов и simulator'ов CKAD/CKA/CKS. Входит в стоимость экзамена CNCF — даёт 2 попытки полного simulator (36 часов session). Simulator идентичен реальному экзамену по UI (Linux Foundation), но СЛОЖНЕЕ по контенту (20-25 заданий vs ~15-20 на реальном). Включает: примеры YAML генерации, troubleshooting, kubectl forensics, RBAC tasks, debugging. Прохождение simulator'а на 100% = почти гарантированный pass реального. Стратегия: первая попытка без таймера (учиться), вторая — с таймером (тренировка темпа).
# Запуск simulator
# https://killer.sh — login через Linux Foundation
# Click 'Start' — получаешь 36-часовое окно
# В нём — 120-минутный simulator, можно перезапускать
# UI идентичен реальному экзамену:
# - Терминал Linux
# - Firefox для docs (kubernetes.io)
# - Notepad