Kubernetes основы
Kubernetes (K8s) — платформа оркестрации контейнеров, которая автоматизирует их развёртывание, масштабирование, сетевое взаимодействие и восстановление после сбоев.
В Kubernetes обычно описывают желаемое состояние системы в YAML-манифестах. Контроллеры кластера сравнивают его с фактическим состоянием и стараются устранить различия.
Пример минимального Pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80Создание объекта:
kubectl apply -f pod.yamlПроверка:
kubectl get pods
kubectl describe pod nginxСодержание
- Основные понятия Kubernetes
- Архитектура Kubernetes
- Манифесты Kubernetes
- Labels, selectors и annotations
- Pod
- ReplicaSet
- Deployment
- Service
- ClusterIP
- NodePort
- ConfigMap
- Secret
- Namespaces
- kubectl — основные команды
- Общий пример приложения
- Диагностика
- Рекомендации
Основные понятия Kubernetes
Kubernetes управляет приложениями через объекты API. Каждый объект описывает часть состояния кластера: контейнеры, сетевой доступ, конфигурацию, секреты или правила масштабирования.
| Понятие | Назначение |
|---|---|
| Cluster | Совокупность control plane и рабочих узлов |
| Node | Сервер или виртуальная машина, на которой запускаются Pod |
| Pod | Минимальная единица запуска одного или нескольких контейнеров |
| Controller | Компонент, приводящий объект к желаемому состоянию |
| Deployment | Управляет обновлением и количеством экземпляров приложения |
| Service | Предоставляет стабильную сетевую точку доступа к группе Pod |
| Namespace | Логически разделяет объекты внутри кластера |
| ConfigMap | Хранит несекретную конфигурацию |
| Secret | Хранит конфиденциальные значения |
Kubernetes использует декларативный подход. Вместо последовательности команд запуска описывается конечное состояние:
spec:
replicas: 3Это означает, что система должна поддерживать три экземпляра приложения. Если один Pod завершится, контроллер создаст новый.
Типичный цикл работы:
- Пользователь отправляет манифест через
kubectl. - API server проверяет запрос и сохраняет состояние.
- Контроллер обнаруживает новый или изменённый объект.
- Scheduler выбирает подходящий узел для Pod.
- Kubelet на узле запускает контейнеры.
- Контроллеры продолжают проверять соответствие фактического состояния желаемому.
Архитектура Kubernetes
Кластер Kubernetes состоит из control plane и одного или нескольких worker nodes.
Пользователь / CI/CD
|
v
API Server
|
+-----+--------------------+
| Control Plane |
| etcd |
| Scheduler |
| Controller Manager |
+--------------------------+
|
v
+--------------------------+
| Worker Node |
| kubelet |
| container runtime |
| kube-proxy / CNI |
| Pods |
+--------------------------+Control plane
Control plane управляет состоянием всего кластера. Его компоненты принимают запросы, хранят конфигурацию, планируют Pod и запускают циклы согласования.
kube-apiserver
API server — центральная точка взаимодействия с Kubernetes API. Через него работают kubectl, контроллеры, операторы и внешние системы.
Основные задачи:
- принимает REST-запросы;
- проверяет аутентификацию и авторизацию;
- выполняет валидацию объектов;
- применяет admission-контроллеры;
- читает и записывает состояние кластера;
- предоставляет watch-механизм для наблюдения за изменениями.
Команда:
kubectl get podsне обращается к узлам напрямую. Она отправляет запрос API server.
etcd
etcd — распределённое key-value-хранилище, в котором сохраняется состояние Kubernetes.
В нём находятся сведения об объектах кластера, включая:
- Deployments;
- Pods;
- Services;
- ConfigMaps;
- Secrets;
- Namespaces;
- служебные данные control plane.
Резервное копирование etcd критично для самостоятельного кластера. Потеря etcd означает потерю сохранённого состояния control plane.
kube-scheduler
Scheduler выбирает worker node для Pod, у которого ещё не назначен узел.
При выборе учитываются:
- запрошенные CPU и память;
- доступные ресурсы узлов;
- ограничения
nodeSelectorи node affinity; - taints и tolerations;
- anti-affinity;
- топология и другие правила планирования.
Scheduler выбирает узел, но не запускает контейнеры самостоятельно.
kube-controller-manager
Controller Manager запускает встроенные контроллеры Kubernetes.
Примеры:
- Deployment Controller;
- ReplicaSet Controller;
- Node Controller;
- Job Controller;
- EndpointSlice Controller;
- ServiceAccount Controller.
Контроллер выполняет цикл согласования:
желаемое состояние -> сравнение -> действие -> новое фактическое состояниеНапример, если Deployment требует три реплики, а работает только две, соответствующий контроллер инициирует создание ещё одного Pod.
cloud-controller-manager
В облачной среде Cloud Controller Manager интегрирует Kubernetes с API облачного провайдера.
В зависимости от платформы он может участвовать в:
- создании облачных балансировщиков;
- работе с адресами узлов;
- управлении маршрутами;
- обработке жизненного цикла облачных виртуальных машин.
В локальном кластере этот компонент может отсутствовать.
Worker node
Worker node — сервер или виртуальная машина, на которой работают прикладные Pod.
На узле обычно находятся:
kubelet;- container runtime;
- сетевые компоненты;
- Pod приложения.
kubelet
Kubelet — агент Kubernetes на каждом worker node.
Он:
- получает PodSpec через API server;
- обращается к container runtime;
- запускает и останавливает контейнеры;
- выполняет probes;
- сообщает статус Pod и узла;
- подключает необходимые тома.
Container runtime
Container runtime непосредственно управляет контейнерами. Kubernetes взаимодействует с ним через CRI — Container Runtime Interface.
Распространённые реализации:
- containerd;
- CRI-O.
Kubernetes управляет контейнерами через CRI, поэтому команды Docker не являются основным интерфейсом управления объектами кластера.
Сеть кластера
Сетевую связность Pod обычно обеспечивает CNI-плагин. Конкретная реализация зависит от дистрибутива и конфигурации кластера.
Базовая модель Kubernetes предполагает:
- каждый Pod получает IP-адрес;
- Pod могут обращаться друг к другу по сети;
- контейнеры одного Pod используют общий сетевой namespace;
- Service предоставляет устойчивую точку доступа, даже если Pod заменяются.
Манифесты Kubernetes
Объекты Kubernetes обычно описываются в YAML.
Базовая структура:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: demo
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27Основные поля:
| Поле | Назначение |
|---|---|
apiVersion |
Версия API объекта |
kind |
Тип объекта |
metadata |
Имя, namespace, labels, annotations и другие метаданные |
spec |
Желаемое состояние объекта |
status |
Фактическое состояние, которое заполняет Kubernetes |
status обычно не записывают в исходный манифест. Это поле обновляется компонентами кластера.
Просмотр структуры ресурса:
kubectl explain deployment
kubectl explain deployment.spec
kubectl explain deployment.spec.template.spec.containersИмперативный и декларативный подходы
Императивная команда сразу создаёт или изменяет ресурс:
kubectl create deployment web --image=nginx:1.27
kubectl scale deployment web --replicas=3Декларативный подход использует файлы:
kubectl apply -f deployment.yamlДля инфраструктуры и CI/CD обычно предпочтителен декларативный подход, потому что манифесты можно хранить в Git, проверять и повторно применять.
Проверка без сохранения
Клиентская проверка и вывод результата:
kubectl apply --dry-run=client -f deployment.yamlСоздание шаблона YAML:
kubectl create deployment web \
--image=nginx:1.27 \
--dry-run=client \
-o yamlСерверная проверка использует API текущего кластера:
kubectl apply --dry-run=server -f deployment.yamlLabels, selectors и annotations
Labels
Labels — пары ключ-значение для классификации и выбора объектов.
metadata:
labels:
app: shop
component: backend
environment: productionПоиск по label:
kubectl get pods -l app=shop
kubectl get pods -l 'environment in (staging,production)'Labels используются Service, Deployment и другими объектами для выбора связанных ресурсов.
Selectors
Selector выбирает объекты по labels.
Пример селектора Deployment:
selector:
matchLabels:
app: webLabels шаблона Pod должны соответствовать селектору:
template:
metadata:
labels:
app: webЕсли Service выбирает app: web, трафик будет направляться на подходящие готовые Pod.
Annotations
Annotations содержат дополнительные метаданные, которые не используются для обычной выборки объектов.
metadata:
annotations:
description: "Публичный веб-сервис"
owner: "platform-team"В annotations могут храниться:
- описание;
- контакт владельца;
- идентификатор внешней системы;
- настройки ingress-контроллера;
- служебные данные инструментов развёртывания.
Pod
Pod — минимальная единица, которую Kubernetes планирует на узел и запускает.
Pod содержит один или несколько контейнеров, которые совместно используют:
- IP-адрес;
- сетевой namespace;
- порты;
- подключённые тома;
- жизненный цикл Pod.
Обычно один Pod содержит один основной контейнер приложения. Дополнительный sidecar-контейнер добавляется, если он тесно связан с основным процессом.
Простой Pod
apiVersion: v1
kind: Pod
metadata:
name: web
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- name: http
containerPort: 80Создание и проверка:
kubectl apply -f pod.yaml
kubectl get pod web -o wide
kubectl describe pod webУдаление:
kubectl delete pod webЕсли Pod был создан напрямую, после удаления он не восстановится. Для долгоживущих приложений обычно используют Deployment.
Несколько контейнеров в Pod
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
- name: content-writer
image: busybox:1.36
command:
- sh
- -c
- while true; do date > /data/index.html; sleep 10; done
volumeMounts:
- name: shared
mountPath: /data
volumes:
- name: shared
emptyDir: {}Контейнеры общаются через localhost, поскольку находятся в одном сетевом namespace.
Команды и аргументы контейнера
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c"]
args:
- while true; do echo working; sleep 30; doneВ Kubernetes:
commandпереопределяетENTRYPOINTобраза;argsпереопределяетCMDобраза.
Переменные окружения
containers:
- name: app
image: example/app:1.0
env:
- name: APP_ENV
value: production
- name: HTTP_PORT
value: "8080"Числовые и логические значения переменных окружения рекомендуется заключать в кавычки, потому что значение env.value является строкой.
Запросы и ограничения ресурсов
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mirequestsиспользуются Scheduler при размещении Pod.limitsограничивают потребление контейнера.- превышение лимита памяти обычно приводит к завершению контейнера с причиной
OOMKilled; - ограничение CPU обычно вызывает throttling, а не немедленное завершение.
100m CPU означает 0,1 ядра.
Probes
Проверки помогают Kubernetes определять состояние контейнера.
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30
periodSeconds: 2| Проверка | Назначение |
|---|---|
startupProbe |
Проверяет завершение запуска медленного приложения |
readinessProbe |
Определяет, можно ли направлять трафик в Pod |
livenessProbe |
Определяет, нужно ли перезапустить контейнер |
Ошибка readiness probe убирает Pod из готовых endpoints Service, но не обязательно перезапускает контейнер.
Жизненный цикл Pod
Часто встречаются фазы:
| Фаза | Значение |
|---|---|
Pending |
Pod принят, но контейнеры ещё не готовы к запуску |
Running |
Pod назначен узлу, хотя отдельные контейнеры ещё могут быть не готовы |
Succeeded |
Все контейнеры успешно завершились и не перезапускаются |
Failed |
Хотя бы один контейнер завершился с ошибкой и не будет перезапущен |
Unknown |
Состояние Pod не удалось получить |
Фаза Pod и причина ожидания контейнера — разные вещи. Например, в выводе может встречаться CrashLoopBackOff или ImagePullBackOff; подробности следует смотреть через kubectl describe и kubectl logs.
ReplicaSet
ReplicaSet поддерживает заданное количество одинаковых Pod.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80Если один из трёх Pod исчезнет, ReplicaSet создаст замену.
Проверка:
kubectl get replicasets
kubectl get rs
kubectl describe rs webНа практике ReplicaSet редко создают напрямую. Обычно им управляет Deployment, который дополнительно предоставляет стратегию обновления и историю ревизий.
Связь объектов:
Deployment
|
+-- ReplicaSet текущей версии
| +-- Pod
| +-- Pod
| +-- Pod
|
+-- ReplicaSet предыдущей версииПри обновлении Deployment создаётся новый ReplicaSet. Старый обычно сохраняется с нулевым числом реплик для возможности отката.
Deployment
Deployment управляет ReplicaSet и предназначен для развёртывания stateless-приложений.
Он поддерживает:
- необходимое количество реплик;
- постепенное обновление;
- откат версии;
- масштабирование;
- паузу и продолжение rollout;
- восстановление Pod через ReplicaSet.
Манифест Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- name: http
containerPort: 80
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 3
periodSeconds: 5Применение:
kubectl apply -f deployment.yamlПроверка:
kubectl get deployments
kubectl get rs
kubectl get pods -l app=web
kubectl rollout status deployment/webОбновление образа
Декларативный вариант — изменить image в YAML и применить файл:
kubectl apply -f deployment.yamlИмперативный вариант:
kubectl set image deployment/web nginx=nginx:1.28Имя nginx перед знаком = должно совпадать с именем контейнера в Deployment.
История и откат
kubectl rollout history deployment/web
kubectl rollout history deployment/web --revision=2
kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=2Для осмысленной истории изменений можно записать описание:
kubectl annotate deployment web \
kubernetes.io/change-cause="Update nginx to 1.28"Масштабирование
kubectl scale deployment web --replicas=5Если реплики управляются другим механизмом, например Horizontal Pod Autoscaler, ручное значение впоследствии может быть изменено этим контроллером.
Стратегии обновления
RollingUpdate
Значение по умолчанию. Новые Pod постепенно заменяют старые.
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1maxUnavailable— сколько реплик может быть недоступно во время обновления;maxSurge— сколько дополнительных реплик можно временно создать.
Recreate
Старые Pod удаляются до создания новых:
strategy:
type: RecreateПодходит только тогда, когда одновременная работа старой и новой версий недопустима и приемлем перерыв в доступности.
Deployment не гарантирует готовность приложения сам по себе
Наличие запущенного процесса ещё не означает, что приложение готово принимать трафик. Для корректного rollout важно настроить readinessProbe.
Если новые Pod не становятся Ready, обновление может остановиться, а старые реплики продолжат обслуживать запросы в пределах стратегии.
Service
Pod являются временными: их IP-адреса могут изменяться после пересоздания. Service предоставляет стабильные DNS-имя и виртуальный IP для доступа к группе Pod.
Service выбирает Pod по labels:
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- name: http
port: 80
targetPort: 8080Здесь:
port— порт Service;targetPort— порт контейнера или именованный порт Pod;selector— labels целевых Pod.
Если selector Service не совпадает с labels Pod, Service будет существовать, но не получит готовых endpoints.
Проверка:
kubectl get services
kubectl get svc
kubectl describe service web
kubectl get endpointslices -l kubernetes.io/service-name=webDNS Service
Внутри того же namespace Service обычно доступен по короткому имени:
http://webПолное DNS-имя имеет вид:
web.demo.svc.cluster.localгде:
web— имя Service;demo— namespace;svc.cluster.localстандартный кластерный домен, который может быть изменён при настройке кластера.
Основные типы Service
| Тип | Назначение |
|---|---|
ClusterIP |
Доступ только через виртуальный IP внутри кластера |
NodePort |
Открывает одинаковый порт на узлах кластера |
LoadBalancer |
Запрашивает внешний балансировщик у поддерживаемой инфраструктуры |
ExternalName |
Возвращает DNS CNAME на внешнее имя |
В этой справке подробно рассматриваются ClusterIP и NodePort.
ClusterIP
ClusterIP — стандартный тип Service. Он предоставляет внутренний виртуальный IP, доступный в сети кластера.
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: demo
spec:
type: ClusterIP
selector:
app: backend
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080Схема:
Pod-клиент
|
v
backend:80 / ClusterIP
|
+--> backend Pod:8080
+--> backend Pod:8080
+--> backend Pod:8080Создание и проверка:
kubectl apply -f service.yaml
kubectl get svc -n demo
kubectl describe svc backend -n demoПроверка из временного Pod:
kubectl run curl \
--image=curlimages/curl \
--restart=Never \
-it --rm \
-- curl http://backend.demo.svc.cluster.localHeadless Service
Если указать:
spec:
clusterIP: NoneService становится headless и не получает обычный виртуальный IP. DNS может возвращать адреса отдельных Pod. Такой режим часто используется системами, которым нужна прямая адресация реплик.
NodePort
NodePort открывает порт на каждом узле кластера и перенаправляет трафик в Service.
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080Доступ:
http://<IP-узла>:30080По умолчанию NodePort обычно выделяется из диапазона 30000–32767. Конкретный диапазон может быть изменён в настройках API server.
Если nodePort не задан, Kubernetes выбирает свободный порт автоматически:
ports:
- port: 80
targetPort: 80Просмотр назначенного порта:
kubectl get svc web-nodeportNodePort часто используют:
- в учебных и локальных кластерах;
- как внутренний механизм для Service типа LoadBalancer;
- для простого доступа к приложению без отдельного ingress-контроллера.
Для production-доступа обычно дополнительно используют LoadBalancer или Ingress/Gateway API, TLS и контролируемую внешнюю точку входа.
Важно учитывать firewall и Security Groups инфраструктуры: открытый Kubernetes Service не гарантирует, что порт разрешён на сетевом уровне облака или узла.
ConfigMap
ConfigMap хранит несекретную конфигурацию отдельно от образа контейнера.
Подходящие данные:
- адреса сервисов;
- уровни логирования;
- feature flags;
- конфигурационные файлы;
- имена окружений.
Не следует хранить в ConfigMap пароли, токены и закрытые ключи.
ConfigMap с отдельными значениями
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: demo
data:
APP_ENV: production
LOG_LEVEL: info
HTTP_PORT: "8080"Создание:
kubectl apply -f configmap.yamlПросмотр:
kubectl get configmap app-config -n demo
kubectl describe configmap app-config -n demo
kubectl get configmap app-config -n demo -o yamlПередача одного значения в переменную окружения
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVELПередача всех значений
envFrom:
- configMapRef:
name: app-configПосле этого ключи ConfigMap становятся переменными окружения контейнера.
ConfigMap как файл
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
default.conf: |
server {
listen 80;
location /health {
access_log off;
return 200 "ok\n";
}
location / {
root /usr/share/nginx/html;
}
}Подключение:
volumes:
- name: nginx-config
configMap:
name: nginx-config
containers:
- name: nginx
image: nginx:1.27
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
readOnly: trueКаждый ключ становится именем файла, а значение — его содержимым.
Создание ConfigMap командой
Из литералов:
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=LOG_LEVEL=infoИз файла:
kubectl create configmap nginx-config \
--from-file=default.confСоздание YAML без отправки в кластер:
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--dry-run=client \
-o yamlОбновление ConfigMap
При использовании ConfigMap через переменные окружения уже запущенный контейнер не получает новое значение автоматически. Обычно требуется перезапуск Pod:
kubectl rollout restart deployment/app -n demoПри подключении ConfigMap как volume изменения могут появиться в файлах не мгновенно. Приложение при этом должно уметь перечитывать конфигурацию. Монтирование отдельного ключа через subPath обычно не получает автоматические обновления.
Secret
Secret предназначен для конфиденциальных данных:
- паролей;
- токенов;
- ключей API;
- TLS-сертификатов;
- данных доступа к container registry.
Пример:
apiVersion: v1
kind: Secret
metadata:
name: database-credentials
namespace: demo
type: Opaque
stringData:
username: app_user
password: change-meПоле stringData принимает обычные строки. API server преобразует их в содержимое поля data.
В data значения записываются в Base64:
apiVersion: v1
kind: Secret
metadata:
name: database-credentials
type: Opaque
data:
username: YXBwX3VzZXI=
password: Y2hhbmdlLW1lBase64 — это кодирование, а не шифрование. Любой, кто получил значение, может его декодировать:
echo 'YXBwX3VzZXI=' | base64 --decodeПоэтому Secret нельзя считать безопасным только из-за Base64.
Создание Secret командой
kubectl create secret generic database-credentials \
--from-literal=username=app_user \
--from-literal=password='strong-password'Из файлов:
kubectl create secret generic ssh-key \
--from-file=id_rsa=./id_rsaSecret в переменной окружения
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: database-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: database-credentials
key: passwordВсе ключи Secret:
envFrom:
- secretRef:
name: database-credentialsSecret как volume
volumes:
- name: database-credentials
secret:
secretName: database-credentials
containers:
- name: app
image: example/app:1.0
volumeMounts:
- name: database-credentials
mountPath: /var/run/secrets/database
readOnly: trueВ контейнере появятся файлы:
/var/run/secrets/database/username
/var/run/secrets/database/passwordПросмотр значения
kubectl get secret database-credentials \
-n demo \
-o jsonpath='{.data.username}' | base64 --decodeВывод секрета возможен только при наличии соответствующих прав RBAC.
Безопасная работа с Secret
Рекомендуется:
- не хранить открытые секреты в Git;
- ограничивать доступ через RBAC;
- включать шифрование данных Secret в etcd;
- использовать внешний secret manager, если это предусмотрено архитектурой;
- регулярно менять секреты;
- не передавать секреты через аргументы командной строки без необходимости;
- не выводить секреты в логи;
- учитывать, что пользователь с правом создавать Pod в namespace потенциально может подключить доступные этому Pod секреты.
Для GitOps применяют решения с зашифрованными манифестами или синхронизацией из внешнего хранилища. Обычный YAML с stringData не должен содержать production-пароли в репозитории.
Типы Secret
| Тип | Назначение |
|---|---|
Opaque |
Произвольные данные |
kubernetes.io/tls |
TLS-сертификат и закрытый ключ |
kubernetes.io/dockerconfigjson |
Доступ к container registry |
kubernetes.io/basic-auth |
Имя пользователя и пароль |
kubernetes.io/ssh-auth |
Закрытый SSH-ключ |
TLS Secret:
kubectl create secret tls web-tls \
--cert=tls.crt \
--key=tls.keyRegistry Secret:
kubectl create secret docker-registry registry-credentials \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password='password'Подключение registry Secret:
spec:
imagePullSecrets:
- name: registry-credentialsNamespaces
Namespace логически разделяет объекты внутри одного кластера.
Namespaces помогают:
- отделять окружения или команды;
- группировать ресурсы;
- разграничивать доступ через RBAC;
- применять ResourceQuota и LimitRange;
- сокращать количество объектов в одном пространстве имён.
Просмотр:
kubectl get namespaces
kubectl get nsЧасто встречаются системные namespaces:
| Namespace | Назначение |
|---|---|
default |
Пространство по умолчанию |
kube-system |
Компоненты и дополнения Kubernetes |
kube-public |
Ресурсы, которые могут быть доступны всем пользователям |
kube-node-lease |
Lease-объекты узлов для heartbeat |
Создание namespace
apiVersion: v1
kind: Namespace
metadata:
name: demokubectl apply -f namespace.yamlИли командой:
kubectl create namespace demoРабота с namespace
kubectl get pods -n demo
kubectl apply -f deployment.yaml -n demo
kubectl get all -n demoФлаг -A показывает объекты во всех namespaces:
kubectl get pods -AУстановка namespace по умолчанию для текущего context:
kubectl config set-context --current --namespace=demoПроверка:
kubectl config view --minify --output 'jsonpath={..namespace}'Namespace в манифесте
metadata:
name: web
namespace: demoЕсли namespace указан и в YAML, и через -n, значения должны быть согласованы.
Область имён объектов
Имена namespaced-объектов должны быть уникальны только внутри namespace. Например, Service с именем api может существовать одновременно в dev и prod.
Некоторые ресурсы являются кластерными и не принадлежат namespace. Например:
- Node;
- Namespace;
- PersistentVolume;
- ClusterRole;
- CustomResourceDefinition.
Проверить область ресурса:
kubectl api-resourcesВ колонке NAMESPACED указано, относится ли тип объекта к namespace.
Удаление namespace
kubectl delete namespace demoУдаление namespace запускает удаление всех namespaced-объектов внутри него. Эту команду следует использовать осторожно.
Namespace не является полной границей безопасности
Сам по себе namespace не изолирует сеть и не запрещает доступ пользователям. Для изоляции дополнительно используют:
- RBAC;
- NetworkPolicy;
- ResourceQuota;
- Pod Security Admission;
- отдельные кластеры для сред с жёсткими требованиями к изоляции.
kubectl — основные команды
kubectl — клиент командной строки для Kubernetes API.
Общий формат:
kubectl <действие> <тип-ресурса> <имя> [флаги]Примеры:
kubectl get pods
kubectl describe deployment web
kubectl delete service webКонтексты и конфигурация
Информация о конфигурации:
kubectl config viewСписок контекстов:
kubectl config get-contextsТекущий контекст:
kubectl config current-contextПереключение:
kubectl config use-context developmentПроверка доступности API:
kubectl cluster-infoПеред изменениями важно убедиться, что выбран правильный кластер и namespace.
Просмотр ресурсов
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get configmaps
kubectl get secrets
kubectl get nodesСокращения:
kubectl get po
kubectl get deploy
kubectl get rs
kubectl get svc
kubectl get cm
kubectl get nsРасширенная информация:
kubectl get pods -o wideНаблюдение за изменениями:
kubectl get pods --watch
kubectl get pods -wПо label:
kubectl get pods -l app=webИз определённого namespace:
kubectl get pods -n demoИз всех namespaces:
kubectl get pods -AФорматы вывода
YAML:
kubectl get deployment web -o yamlJSON:
kubectl get pod web -o jsonИмя ресурса:
kubectl get pods -o nameJSONPath:
kubectl get pods \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'Custom columns:
kubectl get pods \
-o custom-columns='NAME:.metadata.name,IMAGE:.spec.containers[*].image,PHASE:.status.phase'Создание и изменение
Применить один файл:
kubectl apply -f deployment.yamlПрименить каталог:
kubectl apply -f k8s/Создать ресурс без декларативного управления:
kubectl create -f namespace.yamlРедактировать объект:
kubectl edit deployment webИзменить число реплик:
kubectl scale deployment web --replicas=4Перезапустить Deployment:
kubectl rollout restart deployment/webДобавить label:
kubectl label pod web environment=devДобавить или изменить annotation:
kubectl annotate deployment web owner=platform-team --overwriteУдаление
По файлу:
kubectl delete -f deployment.yamlПо имени:
kubectl delete deployment webПо label:
kubectl delete pods -l app=webУдаление Pod, которым управляет Deployment, обычно приводит к созданию нового Pod.
Описание объекта и события
kubectl describe pod web
kubectl describe deployment web
kubectl describe node worker-1События:
kubectl get events --sort-by=.metadata.creationTimestampДля конкретного namespace:
kubectl get events -n demo --sort-by=.metadata.creationTimestampСобытия имеют ограниченное время хранения, поэтому их следует проверять вскоре после возникновения проблемы.
Логи
Логи Pod с одним контейнером:
kubectl logs webДля конкретного контейнера:
kubectl logs web -c nginxСледить за логами:
kubectl logs -f webПоследние строки:
kubectl logs web --tail=100Логи предыдущего экземпляра контейнера после перезапуска:
kubectl logs web --previousЛоги Pod Deployment по label:
kubectl logs -l app=web --all-containers=true --tail=100Выполнение команды в контейнере
Интерактивная оболочка:
kubectl exec -it web -- shЕсли доступен Bash:
kubectl exec -it web -- bashВ Pod с несколькими контейнерами:
kubectl exec -it web -c nginx -- shОдиночная команда:
kubectl exec web -- printenvРазделитель -- отделяет параметры kubectl от команды внутри контейнера.
Копирование файлов
Из локальной системы в Pod:
kubectl cp ./config.json demo/web:/tmp/config.jsonИз Pod:
kubectl cp demo/web:/var/log/app.log ./app.logДля работы kubectl cp в контейнере обычно требуется tar.
Port forwarding
Доступ к Pod:
kubectl port-forward pod/web 8080:80Доступ через Service:
kubectl port-forward service/web 8080:80После запуска:
http://localhost:8080Port forwarding удобен для локальной диагностики, но не заменяет постоянную публикацию сервиса.
Rollout
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web
kubectl rollout restart deployment/web
kubectl rollout pause deployment/web
kubectl rollout resume deployment/webВременный диагностический Pod
kubectl run debug \
--image=busybox:1.36 \
--restart=Never \
-it --rm \
-- shПроверка DNS:
nslookup webHTTP-проверка с образом curl:
kubectl run curl \
--image=curlimages/curl \
--restart=Never \
-it --rm \
-- curl -v http://webСправка API
kubectl api-resources
kubectl api-versions
kubectl explain pod
kubectl explain pod.spec.containers
kubectl explain service.spec.portsПроверка прав
kubectl auth can-i create deployments -n demo
kubectl auth can-i delete pods -n production
kubectl auth can-i --list -n demoПроверка от имени ServiceAccount при наличии прав на impersonation:
kubectl auth can-i get secrets \
--as=system:serviceaccount:demo:app \
-n demoМетрики
Если в кластере установлен Metrics Server:
kubectl top nodes
kubectl top pods
kubectl top pods -n demoОтсутствие данных в kubectl top не означает, что Pod не потребляет ресурсы: возможно, Metrics Server не установлен или недоступен.
Общий пример приложения
Пример включает:
- отдельный namespace;
- ConfigMap с HTML-страницей;
- Secret с демонстрационным значением;
- Deployment из двух реплик;
- ClusterIP Service;
- NodePort Service для учебного внешнего доступа.
Структура:
k8s-demo/
├── namespace.yaml
├── configmap.yaml
├── secret.yaml
├── deployment.yaml
├── service-clusterip.yaml
└── service-nodeport.yamlnamespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: k8s-democonfigmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: web-content
namespace: k8s-demo
data:
index.html: |
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Kubernetes Demo</title>
</head>
<body>
<h1>Приложение работает в Kubernetes</h1>
</body>
</html>secret.yaml
Учебный пример. Настоящие секреты не следует хранить в открытом виде в Git.
apiVersion: v1
kind: Secret
metadata:
name: web-secret
namespace: k8s-demo
type: Opaque
stringData:
APP_TOKEN: replace-in-real-environmentdeployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: k8s-demo
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- name: http
containerPort: 80
env:
- name: APP_TOKEN
valueFrom:
secretKeyRef:
name: web-secret
key: APP_TOKEN
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 250m
memory: 128Mi
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
readOnly: true
volumes:
- name: web-content
configMap:
name: web-contentservice-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: web
namespace: k8s-demo
spec:
type: ClusterIP
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: httptargetPort: http ссылается на именованный порт контейнера:
ports:
- name: http
containerPort: 80service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
namespace: k8s-demo
spec:
type: NodePort
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: http
nodePort: 30080Развёртывание
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service-clusterip.yaml
kubectl apply -f service-nodeport.yamlИли применить весь каталог:
kubectl apply -f k8s-demo/Если файлы применяются из одного каталога, namespace должен быть создан до namespaced-ресурсов. В автоматизации это можно делать отдельным шагом.
Проверка
kubectl get all -n k8s-demo
kubectl get configmap,secret -n k8s-demo
kubectl get pods -n k8s-demo -l app=web -o wide
kubectl rollout status deployment/web -n k8s-demo
kubectl get endpointslices -n k8s-demo \
-l kubernetes.io/service-name=webДоступ через port-forward:
kubectl port-forward service/web 8080:80 -n k8s-demoПосле этого приложение доступно по адресу:
http://localhost:8080В среде, где узлы доступны напрямую, NodePort может быть открыт по адресу:
http://<IP-узла>:30080Обновление
Изменить образ:
kubectl set image deployment/web \
nginx=nginx:1.28 \
-n k8s-demoСледить за обновлением:
kubectl rollout status deployment/web -n k8s-demoОткатить:
kubectl rollout undo deployment/web -n k8s-demoМасштабирование
kubectl scale deployment web \
--replicas=4 \
-n k8s-demoПроверка:
kubectl get pods -n k8s-demo -l app=webУдаление примера
Удаление всего namespace вместе с его объектами:
kubectl delete namespace k8s-demoДиагностика
Pod находится в Pending
Проверить:
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.metadata.creationTimestamp
kubectl get nodes
kubectl describe node <node>Возможные причины:
- недостаточно CPU или памяти;
- ограничения affinity или
nodeSelector; - taint без подходящего toleration;
- проблема с volume;
- недоступен подходящий узел.
ImagePullBackOff или ErrImagePull
Проверить:
kubectl describe pod <pod> -n <namespace>Возможные причины:
- неверное имя или tag образа;
- образ отсутствует;
- registry недоступен;
- требуется
imagePullSecrets; - неверные registry credentials.
CrashLoopBackOff
Проверить текущие и предыдущие логи:
kubectl logs <pod> -n <namespace>
kubectl logs <pod> -n <namespace> --previous
kubectl describe pod <pod> -n <namespace>Возможные причины:
- приложение завершается с ошибкой;
- неверная команда запуска;
- отсутствует конфигурация;
- liveness probe постоянно завершается ошибкой;
- нет подключения к зависимому сервису;
- превышен лимит памяти.
Pod работает, но Service недоступен
Проверить Service и endpoints:
kubectl get svc <service> -n <namespace> -o yaml
kubectl get endpointslices -n <namespace> \
-l kubernetes.io/service-name=<service>
kubectl get pods -n <namespace> --show-labelsПроверить:
- совпадает ли selector Service с labels Pod;
- являются ли Pod Ready;
- правильно ли указаны
portиtargetPort; - слушает ли приложение нужный адрес и порт;
- не блокирует ли трафик NetworkPolicy или внешняя сеть.
Если приложение слушает только 127.0.0.1 внутри контейнера, другие Pod обычно не смогут обратиться к нему по IP Pod. Серверу часто требуется слушать 0.0.0.0.
Deployment не завершает rollout
kubectl rollout status deployment/<name> -n <namespace>
kubectl describe deployment <name> -n <namespace>
kubectl get rs,pods -n <namespace>
kubectl describe pod <new-pod> -n <namespace>Частые причины:
- новая версия не проходит readiness probe;
- образ не загружается;
- недостаточно ресурсов для
maxSurge; - приложение завершается;
- отсутствуют ConfigMap или Secret.
Ошибка Forbidden
Проверить права:
kubectl auth can-i get pods -n <namespace>
kubectl auth can-i create deployments -n <namespace>Forbidden означает, что API server распознал пользователя, но авторизация не разрешает действие.
Проверка конфигурации внутри Pod
Переменные окружения:
kubectl exec <pod> -n <namespace> -- printenvФайлы:
kubectl exec <pod> -n <namespace> -- ls -la /path/to/config
kubectl exec <pod> -n <namespace> -- cat /path/to/config/fileНе выводите чувствительные данные Secret в общие терминальные логи или системы CI.
Рекомендации
Используйте Deployment вместо отдельных Pod
Прямой Pod удобен для обучения и диагностики, но не предоставляет полноценное управление обновлением и репликами. Для обычного stateless-приложения используйте Deployment.
Фиксируйте версии образов
Предпочтительно:
image: nginx:1.27.4Менее предсказуемо:
image: nginx:latestНеизменяемый digest обеспечивает ещё более точную фиксацию:
image: nginx@sha256:<digest>Настраивайте requests и limits
Без requests Scheduler не получает точной информации о потребностях приложения. Слишком низкие limits могут вызывать throttling и OOMKilled, а слишком высокие requests — мешать размещению Pod.
Добавляйте readiness и liveness probes осознанно
Readiness должна проверять готовность обслуживать трафик. Liveness должна определять зависшее состояние, которое можно исправить перезапуском. Слишком агрессивная liveness probe может создать цикл перезапусков.
Отделяйте конфигурацию от образа
Используйте:
- ConfigMap для обычной конфигурации;
- Secret для конфиденциальных значений;
- разные объекты конфигурации для разных окружений.
Не храните открытые секреты в Git
Base64 не защищает Secret. Используйте шифрование, внешние secret managers или специализированный GitOps-процесс.
Применяйте labels последовательно
Полезный набор:
metadata:
labels:
app.kubernetes.io/name: web
app.kubernetes.io/instance: web-production
app.kubernetes.io/component: frontend
app.kubernetes.io/managed-by: kubectlСогласованные labels упрощают поиск, мониторинг и автоматизацию.
Проверяйте контекст перед изменениями
kubectl config current-context
kubectl config view --minifyОсобенно важно перед удалением, масштабированием или изменением production-ресурсов.
Храните манифесты в системе контроля версий
Это позволяет:
- выполнять review;
- видеть историю изменений;
- воспроизводить окружение;
- запускать автоматическую валидацию;
- использовать GitOps или CI/CD.
Проверяйте манифесты до применения
kubectl apply --dry-run=client -f k8s/
kubectl apply --dry-run=server -f k8s/
kubectl diff -f k8s/kubectl diff показывает предполагаемые изменения и может возвращать ненулевой код, если различия найдены, что нужно учитывать в скриптах.
Помните об области видимости
Namespace помогает организовать ресурсы, но не заменяет сетевую и полномочную изоляцию. Используйте RBAC, NetworkPolicy и политики безопасности в соответствии с требованиями среды.
Краткая шпаргалка
# Кластер и контекст
kubectl cluster-info
kubectl config current-context
kubectl config get-contexts
kubectl config use-context <context>
# Ресурсы
kubectl get pods -A
kubectl get all -n <namespace>
kubectl get pod <pod> -o wide
kubectl describe pod <pod> -n <namespace>
# Применение и удаление
kubectl apply -f <file-or-directory>
kubectl diff -f <file-or-directory>
kubectl delete -f <file-or-directory>
# Логи и команды
kubectl logs <pod> -n <namespace>
kubectl logs <pod> --previous -n <namespace>
kubectl exec -it <pod> -n <namespace> -- sh
# Deployment
kubectl rollout status deployment/<name> -n <namespace>
kubectl rollout history deployment/<name> -n <namespace>
kubectl rollout undo deployment/<name> -n <namespace>
kubectl rollout restart deployment/<name> -n <namespace>
kubectl scale deployment <name> --replicas=3 -n <namespace>
# Сеть
kubectl get svc -n <namespace>
kubectl get endpointslices -n <namespace>
kubectl port-forward service/<name> 8080:80 -n <namespace>
# Конфигурация
kubectl get configmap <name> -o yaml -n <namespace>
kubectl get secret <name> -n <namespace>
# Диагностика
kubectl get events -n <namespace> --sort-by=.metadata.creationTimestamp
kubectl auth can-i <verb> <resource> -n <namespace>
kubectl top pods -n <namespace>