ilyamak04 6407e09f14
All checks were successful
Build MkDocs / build-and-deploy (push) Successful in 14s
refactor k8s note
2025-07-31 10:38:53 +03:00

40 KiB
Raw Blame History

YAML Синтаксис

Основные сущности

  • Скалярные значения
string_value: hello
number_value: 42
float_value: 3.14
boolean_true: true
boolean_false: false
  • Списки (массивы)
servers:
  - web01
  - web02
  - db01

или

servers: [web01, web02, db01]
  • Словари
user:
  name: "ivan"
  age: 30
  admin: true

или

user: {name: ivan, age: 30, admin: true}
  • Многострочные строки
description: |
  Это многострочный текст.
  Он сохраняет переносы строк.
  Полезно для документации.

command: >
  Это тоже многострочный текст,
  но переносы будут заменены пробелами.
  • | - сохраняет всё как есть, включая \n
  • > - склеивает строки в одну с пробелами

Расширенные возможности

  • Ссылки и якори ($, *)
defaults: &default_settings
  retries: 3
  timeout: 30

server1:
  <<: *default_settings
  timeout: 10  # переопределено

server2:
  <<: *default_settings
  • Линтер
yamllint fine_name.yml

Разное

  • Null
empty1: null
empty2: ~
empty3:
  • Boolean
bool1: yes   # интерпретируется как true
bool2: no    # false
bool3: on    # true
bool4: off   # false

чтобы явно задать строку, необходимо использовать кавычки

literal_string: "yes"   # не будет true

Разворот кластера

Буду поднимать 1 мастер ноду, 2 воркер ноды, 1 вспомогательную (DNS, etc)

Поднимаем ВМ для кластера

!!! info "Я делаю всё от рута"

  • apt update && apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils - устанавливаем гипервизор

  • Создаём ВМ

virt-install \
  --name k8s-master \
  --ram 4096 \
  --vcpus 3 \
  --disk path=/var/lib/libvirt/images/k8s-master.qcow2,size=20 \
  --os-variant ubuntu24.04 \         
  --network network=default \
  --graphics vnc,listen=127.0.0.1 \  
  --cdrom /var/lib/libvirt/images/ubuntu-24.04.2-live-server-amd64.iso \
  --noautoconsole
  • virsh vncdisplay k8s-master - выводит VNC-дисплей, к которому привязан указанная гостевая ОС, если запущена

Пример вывода

127.0.0.1:0

Значит порт: 5900 + 0

  • remote-viewer vnc://localhost:5900 - конфигурируем, устанвливаем ВМ
  • virsh list --all - список запущенных ВМ
  • virsh start k8s-master - запуск созданонй ВМ
  • virsh domifaddr k8s-master - узнаём адрес ВМ
  • ssh ilyamak04@192.168.122.157 - ну и подключаемся по ssh

Аналогично поднимаем 2 воркер ноды, и 1 вспомогательную, не забываем менять выделяемые ресурсы для ВМ

??? info "Дополнительные команды для управления ВМ" - virsh shutdown <vm-name> - штатное выключение ВМ - virsh destroy <vm-name> - жёсткое выключение, например, если ВМ зависла, НЕ УДАЛЯЕТ ВМ - virsh list --all - показать список всех виртуальных машин (включая выключенные) - virsh start <vm-name> - запустить виртуальную машину - virsh undefine <vm-name> - удалить ВМ из libvirt (не удаляет диск в /var/lib/libvirt/images/) - virsh domifaddr <vm-name> - показать IP-адрес ВМ (если доступен) - virsh dumpxml <vm-name> - вывести XML-конфигурацию ВМ - virsh console <vm-name> - подключиться к консоли ВМ (если настроен serial-порт) - virsh domstate <vm-name> - показать текущее состояние ВМ - virsh autostart <vm-name> - включить автозапуск ВМ при старте хоста - virsh autostart --disable <vm-name> - отключить автозапуск ВМ - virsh net-list - список виртуальных сетей libvirt - virsh net-dumpxml default - показать XML-конфигурацию сети default - virsh dumpxml <vm-name> - посмотреть XML-конфиг ВМ - virsh net-edit default - отредактировать настройки сети (например, static DHCP) - Клонировать ВМ bash # hostname на клонированной вм нужно менять вручную virt-clone \ --original k8s-worker1 \ --name k8s-worker2 \ --file /var/lib/libvirt/images/k8s-worker2.qcow2

Подготовка ВМ

  • Откючаем swap, k8s требует отключенный swap для корректной работы планировщика
swapoff -a

!!! warn "Не забыть убрать запись из /etc/fstab"

Kubernetes использует cgroups для управления CPU и памятью контейнеров. Если включен swap, ядро может игнорировать лимит памяти, потому что будет сбрасывать часть данных в swap. Это нарушает работу OOM (Out Of Memory) killer и других механизмов kubelet'а. Когда swap включён, kubelet может не "увидеть", что контейнер превысил лимит памяти. Kubelet считает, что вся доступная память — это только RAM.

  • Включаем модули ядра для корректной сетевой работы подов
tee /etc/modules-load.d/k8s.conf <<EOF 
overlay 
br_netfilter 
EOF
modprobe overlay 
modprobe br_netfilter 
  • Для корректной маршрутизации сетевого трафика
tee /etc/sysctl.d/k8s.conf <<EOF 
net.bridge.bridge-nf-call-ip6tables = 1 
net.bridge.bridge-nf-call-iptables = 1 
net.ipv4.ip_forward = 1 
EOF
# перечитываем конфигурации, применяем
sysctl --system
  • Время на узлах должно быть синхронизировано, чтобы избежать проблем с сертификатами или ещё чего-нибудь
apt install -y chrony
  • Проверить что ssh-сервис запущен
systemctl enable --now ssh
  • Фаервол для простоты настройки можно отключить, но выставлять весь кластер в интернет очевидно плохая идея

  • Добавим репозиторий docker для установки containerd, Kubernetes не запускает контейнеры напрямую, он использует Container Runtime Interface (CRI), который реализует containerd

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y containerd.io
  • Kubernetes требует, чтобы containerd использовал systemd как управляющий механизм cgroups, т.е. структуру контроля ресурсов (CPU, память и т.п.)
containerd config default | tee /etc/containerd/config.toml  
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd
systemctl enable containerd
  • Добавим репозиторий k8s, установим необходимые компоненты k8s
# Добавить GPG-ключ
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# Добавить репозиторий Kubernetes
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

# Обновить список пакетов
apt update

# Установить kubeadm, kubelet, kubectl
apt install -y kubelet kubeadm kubectl

# Заблокировать от автоматического обновления
apt-mark hold kubelet kubeadm kubectl

###
# Проверка
###
kubeadm version
kubelet --version
kubectl version --client
  • Установим crictl для взаимодействия с containerd (удобно для отладки)
VERSION="v1.30.0"
curl -LO https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar -C /usr/local/bin -xzf crictl-$VERSION-linux-amd64.tar.gz
rm crictl-$VERSION-linux-amd64.tar.gz
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: "unix:///run/containerd/containerd.sock"
timeout: 0
debug: false
pull-image-on-create: false
disable-pull-on-run: false
EOF
  • Добавим алиас для команды kubectl
echo "alias k='kubectl'" >> ~/.bashrc
source ~/.bashrc
  • Базовые команды
crictl info                      # информация о рантайме
crictl ps -a                    # список всех контейнеров
crictl images                   # список всех образов
crictl pods                     # список подов
crictl logs <container_id>      # логи контейнера
  • Автодополнение для kubectl
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

DNS-сервер

Данный DNS-сервре настраивается для коммуникации между нодами (серверами), для организации резолва имен между сущностями кубера, кубер использует свой ДНС (CoreDNS)

  • Установка BIND9
apt update
apt install -y bind9 bind9utils bind9-doc
  • vi /etc/bind/named.conf.options
//
// ------------------------------------------------------------
//  Глобальные параметры BIND 9
// ------------------------------------------------------------
options {
    // Где BIND хранит кэш и служебные файлы
    directory "/var/cache/bind";

    // Разрешаем рекурсивные запросы 
    recursion yes;

    // Кому разрешена рекурсия. В лаборатории можно any,
    // в проде указать свою подсеть.
    allow-recursion { any; };

    // На каких интерфейсах слушать DNS-запросы
    listen-on  { 192.168.122.66; 127.0.0.1; };
    listen-on-v6 { none; };          // IPv6 не используем

    // Куда пересылать внешние запросы
    forwarders { 8.8.8.8; 1.1.1.1; };

    // Включаем автоматическую проверку DNSSEC-подписей
    dnssec-validation auto;
};
  • vi /etc/bind/named.conf.local
// ------------------------------------------------------------
//  Авторитетные зоны
// ------------------------------------------------------------

// Прямая зона lab.local  (имя → IP)
zone "lab.local" IN {
    type master;                       // главный (= авторитет)
    file "/etc/bind/zones/db.lab.local";
    allow-update { none; };            // динамических правок не ждём
};

// Обратная зона 122.168.192.in-addr.arpa  (IP → имя)
zone "122.168.192.in-addr.arpa" IN {
    type master;
    file "/etc/bind/zones/db.192.168.122";
    allow-update { none; };
};
  • mkdir -p /etc/bind/zones

  • vi /etc/bind/zones/db.lab.local

$TTL 86400          ; время жизни записей по умолчанию (24 ч)

@   IN  SOA k8s-infra.lab.local. admin.lab.local. (
        2025062401 ; Serial  (YYYYMMDDnn) — увеличивайте при каждой правке
        1h         ; Refresh  — как часто slave (если бы был) проверяет SOA
        15m        ; Retry    — если refresh не удался
        7d         ; Expire   ; после этого зона считается устаревшей
        1h )       ; Negative TTL — кэш «NXDOMAIN»

        ; — NS-запись: кто авторитетен для зоны
        IN  NS  k8s-infra.lab.local.

; ---------- A-записи ----------
k8s-master   IN  A   192.168.122.157 ; control-plane
k8s-worker1  IN  A   192.168.122.141 ; worker-1
k8s-worker2  IN  A   192.168.122.192 ; worker-2
k8s-infra    IN  A   192.168.122.66  ; infra + DNS
  • vi /etc/bind/zones/db.192.168.122
$TTL 3600
@   IN  SOA k8s-infra.lab.local. admin.lab.local. (
        2025062401
        1h
        15m
        7d
        1h )

        IN  NS  k8s-infra.lab.local.

; ---------- PTR-записи (последний октет → FQDN) ----------
157  IN  PTR k8s-master.lab.local.
141  IN  PTR k8s-worker1.lab.local.
192  IN  PTR k8s-worker2.lab.local.
66   IN  PTR k8s-infra.lab.local.
  • Проверка синтаксиса
# Проверяем синтаксис конфигурации
named-checkconf

# Проверяем каждую зону
named-checkzone lab.local /etc/bind/zones/db.lab.local
named-checkzone 122.168.192.in-addr.arpa /etc/bind/zones/db.192.168.122
  • Перезапуск сервиса
systemctl restart named
systemctl enable named
  • Добавить на каждой ноде в конфиг netplan
nameservers:
  search: [lab.local]
  addresses: [192.168.122.66, 8.8.8.8]
  • Применить
netplan apply
# или, если нужен лог
sudo netplan apply --debug
  • Проверка работы DNS
dig +short k8s-worker2.lab.local
# prt-запись
dig -x 192.168.122.192 +short

Настройка NFS

Настройка NFS-сервера
  • Устанавливаем сервер
apt update
apt install -y nfs-kernel-server
  • Создаём каталог который будет экспортироваться
mkdir -p /srv/nfs/k8s
# пользователь без привилегий
chown nobody:nogroup /srv/nfs/k8s
chmod 0770 /srv/nfs/k8s
  • vi /etc/exports
/srv/nfs/k8s 192.168.122.0/24(rw,sync,no_subtree_check,root_squash,fsid=0)
  • rw - разрешает чтение и запись

  • sync - операции записи выполняются немедленно (безопасно)

  • no_subtree_check - ускоряет работу при экспорте подкаталогов

  • root_squash - если клиент заходит как root, он будет понижен до "nobody" (безопаснее)

  • fsid=0- нужен для корня экспортов в NFSv4 (в NFSv4 экспортируется только один корень)

  • 192.168.122.0/8 - сеть, которой разрешён доступ

  • Экспортировать каталог

exportfs -rav
# проверить
exportfs -v
Настройка NFS-клиента
apt install -y nfs-common
  • Проверить доступность сервера
# показывает доступные каталоги
showmount -e 192.168.122.157
  • Монтируем расшаренный каталог на клиент
mount -t nfs4 192.168.122.157:/ /mnt
  • Добавить в /etc/fstab, для автомонтирования при перезагрузке
echo "192.168.122.157:/ /mnt nfs4 defaults,_netdev 0 0" | tee -a /etc/fstab

Разворачиваем кластер

  • Версии api, которые поддерживает установленная версия kubeadm
kubeadm config print init-defaults | grep apiVersion
  • vi /etc/kubernetes/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
localAPIEndpoint:
  advertiseAddress: 192.168.122.157
  bindPort: 6443
nodeRegistration:
  criSocket: "unix:///var/run/containerd/containerd.sock"
  imagePullPolicy: IfNotPresent
  name: k8s-master.lab.local
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
certificatesDir: /etc/kubernetes/pki
clusterName: cluster.local
controllerManager: {}
dns: {}
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: "registry.k8s.io"
apiServer:
  timeoutForControlPlane: 4m0s
  extraArgs:
    authorization-mode: Node,RBAC
    bind-address: 0.0.0.0
    service-cluster-ip-range: "10.233.0.0/18"
    service-node-port-range: 30000-32767
kubernetesVersion: "1.30.14"
controlPlaneEndpoint: 192.168.122.157:6443
networking:
  dnsDomain: cluster.local
  podSubnet: "10.233.64.0/18"
  serviceSubnet: "10.233.0.0/18"
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
bindAddress: 0.0.0.0
clusterCIDR: "10.233.64.0/18"
ipvs:
  strictARP: True
mode: ipvs
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
clusterDNS:
- 169.254.25.10
systemReserved:
  memory: 512Mi
  cpu: 500m
  ephemeral-storage: 2Gi
# Default: "10Mi"
containerLogMaxSize: 10Mi
# Default: 5
containerLogMaxFiles: 3
  • Инициализация первой ноды
kubeadm init --config /etc/kubernetes/kubeadm-config.yaml
  • Если приложение долго не завершает свою работу, значит что-то пошло не так. Необходимо отменить все действия и запустить его ещё раз, но с большим уровнем отладки.
kubeadm reset
kubeadm init --config /etc/kubernetes/kubeadm-config.yaml -v5
  • Смотрим ip для доступа к кластеру
kubectl cluster-info
  • Установим драйвер сети (CNI Plugin), Cilium CNI с поддержкой multicast для разворота нод ROS2
CLI_VER=0.16.7
curl -L --remote-name-all \
  https://github.com/cilium/cilium-cli/releases/download/v${CLI_VER}/cilium-linux-amd64.tar.gz
tar xzvf cilium-linux-amd64.tar.gz
sudo mv cilium /usr/local/bin/
cilium version    

cilium install \
  --version 1.17.5 \
  --set ipam.mode=kubernetes \
  --set tunnel=vxlan \
  --set enable-multicast=true

# ждём OK
cilium status --wait   
  • Смотрим ноды в кластере
kubectl get nodes
  • Смотрим поды на ноде
kubectl get pods -A
  • Регистрируем воркер ноды в кластере (представленная команда выводится в стандартный вывод после инициализации первой контрол ноды)
kubeadm join 192.168.122.157:6443 --token xp77tx.kil97vo6tlfdqqr4 \
	--discovery-token-ca-cert-hash sha256:2bec2613d6f016eee60d9e7af7bf98ef44753cbd26f11cce8d71df694bcebddf 

Общее

  • kubectl explain <name> - дока (kubectl explain pod.spec)
  • kubectl edit deployment deployment_name (kubectl edit) - изменение манифеста на лету, нигде не версионируется (использовать только для дебага на тесте)
  • kubectl config get-contexts - информация о текущем контексте

Разное

Labels — структурированные данные для логики Kubernetes

  • для селекторов (matchLabels, labelSelector)
  • для группировки объектов (например, связать Pod с ReplicaSet, Service, Deployment)
  • участвуют в логике работы контроллеров, планировщика (scheduler), сервисов и т.д.
  • нужны для фильтрации: kubectl get pods -l app=nginx

Annotations — это метаданные, которые:

  • Используются для хранения произвольной информации
  • не участвуют в селекции
  • используются вспомогательными компонентами:
    • Ingress-контроллеры
    • cert-manager
    • kubectl
    • Helm
    • CSI (storage drivers)
    • операторы
  • аннотации часто используются для внутренней логики, дополнительных настроек, или даже инструкций для других систем, в том числе приложений внутри подов

POD

k8s - кластерная ОС

POD - одно запущенное приложение в кластере k8s, минимальная абстракция k8s (внутри пода может быть несколько контейнеров, и в поде всегда минимум 2 контейнера: приложение, сетевой неймспейс) (контейнер внутри пода, как отдельный процесс в ОС)

  • kubectl create -f pod.yml - создать под согласно конфигу из файла

  • kubectl get pod - список подов

  • kubectl describe pod <pod_name> - описание пода

  • kubectl describe pod <pod_name> -n <namespace> | less - описание пода в нс

  • kebectl delete pod <pod_name> или kubectl delete -f pod.yml - удаление пода

  • k -n <ns_name> delete pod <pod_name> - удалить под

  • k get pod <pod_name> -n <ns_name> -o yaml | less - посмотреть полный манифест пода

  • kubectl -n <ns_name> logs <pod_name> - логи пода

  • kubectl -n <ns_name> logs <pod_name> -c <container_name> - логи последнего контейнера

!!! info "Разница между create и apply" create создаёт ресурс только если его ещё нет, если ресурс уже существует — выдаёт ошибку

`apply` cоздаёт ресурс, если его нет,или обновляет, если он уже существует, поддерживает историю изменений, идемпотентен
# пример описания пода
---
apiVersion: v1 
kind: Pod # тип сущности
metadata:
  name: mypod # в рамках одного пространства имён имя уникально
spec: # описание объекта
  containers:
    - name: nginx
      image: nginx:latest
      ports:
        - containerPort: 80

Ресурсы (QoS)

Приоритет Pod'ов при выделении ресурсов и при давлении на узел

QoS не управляется напрямую, а автоматически присваивается каждому Pod'у в зависимости от указанных ресурсов (requests и limits) в манифесте.

куб определяет 3 уровня QoS

  • Guaranteed - requests == limits для всех контейнеров в Pod'е, высший приоритет, удаляется в последнюю очередь

  • Burstable - задан requests, но не равно limits, или не для всех

  • BestEffort - не указано ничего (ни requests, ни limits), если ресурсов на ноде не хватает, такие поды убиваются в первую очередь

  • Посмотреть QoS пода

kubectl get pod <pod-name> -o jsonpath='{.status.qosClass}'

Best practice для описания пода

Должны быть:

  • Метки
  • Задан образ контейнера
  • Ресурсы контейнера(ов) ограничены
  • Пробы

Namespace

  • Namespace используются для изоляции групп ресурсов в пределах одного кластера kubernetes. Имена ресурсов должны быть уникальными в пределах namespace.

  • kubectl get ns - вывести неймспейсы

  • kubectl create ns <name> - создать нс

  • kubectl delete ns <name> - удалить нс

  • k get ns <name>

  • kubectl config set-context --current --namespace=<имя-namespace> - сменить ns чтобы писать команды без флага -n

  • нс kube-system располагаются приложения control-plane

  • нс kube-public доступен для чтения всем клиентам

  • kubectl config get-contexts - узнать в каком нс находишься

Repcicaset

Задача Replicaset - обеспечить работу заданного количества реплик Pod'ов, описываемых Deployment

  • kubectl get rs - вывести репликасеты

  • kubectl delete rs <name>-rs - удалить rs

  • k delete replicaset --all - удалить все rs в ns

  • k describe replicaset <name>

  • k scale --replicas 3 replicaset <name> - заскейлисть репликасет

  • k set image replicaset <name> <container_name>=<new_image_name> - обновить образ контейнера (но нужно пересоздать поды, replicaset не решает проблему обновления приложения, rs просто поддерживает заданное количество подов, задачу обновления решает абстрацкия deployment)

  • Пример конфигурации

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp-container
          image: nginx

Deployment

Абстракция, которая управляте replicasetами и podами

Deployment предназначен для stateless приложений

  • создаёт и управляет ReplicaSet'ом

  • Rolling updates — обновляет приложения без простоя

  • Откат (rollback) к предыдущей версии

  • Масштабирование (scale up/down)

  • Самовосстановление (если Pod удалён или упал)

  • Пример deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp-container
        image: nginx:1.25
        ports:
        - containerPort: 80
  • spec.selector - определяет за какие поды отвечает Deployment

  • kubectl rollout restart - перезапуск Deployment

Обновление

  • создаваёт новый ReplicaSet с новой версией образа

  • постепенно увеличивает количество новых Pod'ов и уменьшает старые

  • следит, чтобы всегда было достаточно доступных реплик

  • Пример обновления образа

kubectl set image deployment/myapp myapp-container=nginx:1.26
  • Откат на предыдущую версию deployment (на ту версию, которая была применена до последнего успешного обновления)
kubectl rollout undo deployment myapp
  • Проверка состояния
kubectl rollout status deployment myapp
kubectl get deployment  
kubectl describe deployment myapp
  • При каждом изменении (kubectl apply, set image, scale, и т.п.) создаётся новая ревизия, по умолчанию куб хранит 10 ревизий
# посмотреть историю ревизий
kubectl rollout history deployment myapp
# откатиться к ревизии
kubectl rollout undo deployment myapp --to-revision=3

Service

Сущность, которая предоставляет постоянную сетевую точку доступа к группе Pod'ов

  • kubectl get endpoints my-service - оказывает IP-адреса Pod'ов, к которым направляет трафик Service my-service
  • k get EndpointSlice

Service headless

Не обеспечивает балансировку трафика к подам (нет ClusterIP), позволяет обращаться к поду по его доменному имени, используется с Statefulset, т.к. поды "статичны"

Statefulset

Крнтроллер, похожий на Deployment гарантирует уникальность имени пода, порядок запуска, рестарта, удаления пода, постоянство ip-адреса, томов

Тома

emptyDir

Обычно используется для:

  • размещения кэша файлов
  • данные которые необходимо хранить при сбоях в работе контейнера
  • обмена файлами между несколькими контейнерами в поде

!!! info "При удалении пода (например, при перезапуске, обновлении, сбое узла и т.д.) — данные из emptyDir удаляются безвозвратно"

  • Кусочек конфига
  volumeMounts:
      - name: empty-volume
        mountPath: /empty
volumes:
- name: empty-volume
    emptyDir: {}

hostPath

!!! warning "Изпользовать hostPath небезопасно!!!" Контейнер получает прямой доступ к файловой системе хоста

  • Пример
volumes:
  - name: host-logs
    hostPath:
      path: /var/log/nginx
      type: Directory
  • Kubernetes может проверять, существует ли путь, и что он из себя представляет
type: Directory          # Должен быть каталог
type: DirectoryOrCreate  # Создает каталог, если его нет
type: File               # Должен быть файл
type: FileOrCreate       # Создает файл, если его нет
type: Socket             # Должен быть сокет
type: CharDevice         # Символьное устройство
type: BlockDevice        # Блочное устройство

ConfigMap

ConfigMap - сущность, предназначенная для хранения нечувствительных данных конфигурации в виде пар ключ: значение, позволяет отделить конфигурацию от кода и применять её к контейнерам без необходимости пересборки образа.

  • k get cm

  • Пример

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    envFrom:
    - configMapRef:
        name: my-config

  • Пример
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  APP_MODE: production
  LOG_LEVEL: debug
  • Передача переменных окружения из ConfigMap в Pod
apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo
spec:
  containers:
  - name: app
    image: busybox
    command: ["sh", "-c", "env"]
    env:
    - name: APP_MODE
      valueFrom:
        configMapKeyRef:
          name: my-config
          key: APP_MODE
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: my-config
          key: LOG_LEVEL
  • Если переменная уже определена через env, она не будет перезаписана envFrom.
  • Можно использовать сразу несколько envFrom (например, ConfigMap и Secret).
  • Если переменная в ConfigMap содержит недопустимые символы (например, точки или тире), она не будет импортирована как env.

Secret

Секрет - это объект, который содержит небольшое количетсво конфиденциальных даннх

  • k get secret

  • k get secret <name> -o yaml

  • Типы секрета

    • generic (Opaque) - пароли/токены для приложений
    • docker-registry - данные авторизации в docker registry
    • tls - TLS сертификаты
  • Пример

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: YWRtaW4=     # base64 от 'admin'
  password: MWYyZDFlMmU2N2Rm   # base64 от '1f2d1e2e67df'
  • Для удобства админитратора есть поле strigData, когда манифест примениться содержимое будет закодировано в base64
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
stringData:
  username: admin
  password: s3cr3t
  • Так подключается в манифест
    env:
    - name: username
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: username

!!! warning "" При добавлении новых секретов, необходимо помнить про правила мерджа манифестов, аннотацию kubectl.kubernetes.io/last-applied-configuration

  • Добавление секретов в контейнер в виде тома
apiVersion: v1
kind: Pod
metadata:
  name: secret-volume-pod
spec:
  containers:
  - name: app
    image: alpine
    command: ["/bin/sh", "-c", "cat /etc/secret/* && sleep 3600"]
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: my-secret
# внутри контейнера
cat /etc/secret/username     # выведет: user
cat /etc/secret/password     # выведет: password

downwardAPI

downwardAPI позволяет передать метаданные Pod'а(например, имя пода, namespace, labels, annotations, ресурсы) в контейнер через переменные окружения или файлы.

  • Пример (как том (файлы))
          volumeMounts:
            - mountPath: "/etc/pod-info"
              name: pod-info
              readOnly: true
      volumes:
        - name: pod-info
          downwardAPI:
            items:
              - path: limit-cpu-millicores
                resourceFieldRef:
                  containerName: openresty
                  resource: limits.cpu
                  divisor: 1m
              - path: limit-memory-kibibytes
                resourceFieldRef:
                  containerName: openresty
                  resource: limits.memory
                  divisor: 1Ki
              - path: labels
                fieldRef:
                  fieldPath: metadata.labels
  • Пример (как переменные окружения)
env:
- name: MY_POD_NAME
  valueFrom:
    fieldRef:
      fieldPath: metadata.name

- name: MY_CPU_LIMIT
  valueFrom:
    resourceFieldRef:
      resource: limits.cpu

projected

projected - это том, который объединяет несколько источников данных в одну директорию

  • secret

  • configMap

  • downwardAPI

  • serviceAccountToken

  • Пример

          volumeMounts:
            - mountPath: "/etc/pod-data"
              name: all-values
              readOnly: true
      volumes:
        - name: all-values
          projected:
            sources:
              - downwardAPI:
                  items:
                    - path: limits/cpu-millicore
                      resourceFieldRef:
                        containerName: openresty
                        resource: limits.cpu
                        divisor: 1m
                    - path: limits/memory-kibibytes
                      resourceFieldRef:
                        containerName: openresty
                        resource: limits.memory
                        divisor: 1Ki
                    - path: labels
                      fieldRef:
                        fieldPath: metadata.labels
              - secret:
                  name: user-password-secret
                  items:
                    - key: user
                      path: secret/user
                    - key: password
                      path: secret/password
              - configMap:
                  name: example-txt
                  items:
                    - key: example.txt
                      path: configs/example.txt
                    - key: config.yaml
                      path: configs/config.yaml

PV, PVC

  • k get pv

PersistentVolume (PV) - это объект, который предоставляет долговременное хранилище для Pod'ов, независимое от их жизненного цикла, под подключается к хранилищу не напрямую, а через PersistentVolumeClaim (PVC)

!!! info "PVC работает только внутри одного namespace, а PV - кластерный объект"

  • Архитектура

    • PersistentVolume (PV) - описывает конкретный ресурс хранилища (например, NFS, iSCSI, Ceph, диск в облаке, локальный диск)
    • PersistentVolumeClaim (PVC) - это запрос от Pod-а: «Хочу хранилище с такими-то параметрами»
    • Kubernetes связывает PVC с подходящим PV (если типы и параметры совместимы)
  • accessModes (способы доступа)

    • ReadWriteOnce (RWO): один Pod может писать (самый частый случай)
    • ReadOnlyMany (ROX): много Pod-ов читают
    • ReadWriteMany (RWX): несколько Pod-ов могут читать и писать (например, NFS)
  • persistentVolumeReclaimPolicy — что делать после удаления PVC

    • Retain - PV остаётся, данные сохраняются (нужно вручную очистить/перепривязать)
    • Delete - PV и данные удаляются автоматически
    • Recycle - устаревший способ (удаляет файлы, оставляет PV)
  • (Связывание PVC c PV) Куб находит подходящий PV по:

    • storage (размер — должен быть ≥ запроса)
    • accessModes (PV должен удовлетворять запрошенному)
    • StorageClass (если указан)

!!! info "Если нет подходящего PV - PVC останется в состоянии Pending"