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

1142 lines
40 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### YAML Синтаксис
#### Основные сущности
- Скалярные значения
```yml
string_value: hello
number_value: 42
float_value: 3.14
boolean_true: true
boolean_false: false
```
- Списки (массивы)
```yml
servers:
- web01
- web02
- db01
```
или
```yml
servers: [web01, web02, db01]
```
- Словари
```yml
user:
name: "ivan"
age: 30
admin: true
```
или
```yml
user: {name: ivan, age: 30, admin: true}
```
- Многострочные строки
```yml
description: |
Это многострочный текст.
Он сохраняет переносы строк.
Полезно для документации.
command: >
Это тоже многострочный текст,
но переносы будут заменены пробелами.
```
- `|` - сохраняет всё как есть, включая `\n`
- `>` - склеивает строки в одну с пробелами
#### Расширенные возможности
- Ссылки и якори ($, *)
```yml
defaults: &default_settings
retries: 3
timeout: 30
server1:
<<: *default_settings
timeout: 10 # переопределено
server2:
<<: *default_settings
```
- Линтер
```yml
yamllint fine_name.yml
```
#### Разное
- Null
```yml
empty1: null
empty2: ~
empty3:
```
- Boolean
```yml
bool1: yes # интерпретируется как true
bool2: no # false
bool3: on # true
bool4: off # false
```
чтобы явно задать строку, необходимо использовать кавычки
```yml
literal_string: "yes" # не будет true
```
### Разворот кластера
Буду поднимать 1 мастер ноду, 2 воркер ноды, 1 вспомогательную (DNS, etc)
#### Поднимаем ВМ для кластера
!!! info "Я делаю всё от рута"
- `apt update && apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils` - устанавливаем гипервизор
- Создаём ВМ
```bash
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-дисплей, к которому привязан указанная гостевая ОС, если запущена
Пример вывода
```bash
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 для корректной работы планировщика
```bash
swapoff -a
```
!!! warn "Не забыть убрать запись из /etc/fstab"
Kubernetes использует cgroups для управления CPU и памятью контейнеров. Если включен swap, ядро может игнорировать лимит памяти, потому что будет сбрасывать часть данных в swap. Это нарушает работу OOM (Out Of Memory) killer и других механизмов kubelet'а. Когда swap включён, kubelet может не "увидеть", что контейнер превысил лимит памяти. Kubelet считает, что вся доступная память — это только RAM.
- Включаем модули ядра для корректной сетевой работы подов
```bash
tee /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
```
- Для корректной маршрутизации сетевого трафика
```bash
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
```
- Время на узлах должно быть синхронизировано, чтобы избежать проблем с сертификатами или ещё чего-нибудь
```bash
apt install -y chrony
```
- Проверить что ssh-сервис запущен
```bash
systemctl enable --now ssh
```
- Фаервол для простоты настройки можно отключить, но выставлять весь кластер в интернет очевидно плохая идея
- Добавим репозиторий docker для установки containerd, Kubernetes не запускает контейнеры напрямую, он использует Container Runtime Interface (CRI), который реализует containerd
```bash
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, память и т.п.)
```bash
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
```bash
# Добавить 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` (удобно для отладки)
```bash
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
```
```bash
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`
```bash
echo "alias k='kubectl'" >> ~/.bashrc
source ~/.bashrc
```
- Базовые команды
```bash
crictl info # информация о рантайме
crictl ps -a # список всех контейнеров
crictl images # список всех образов
crictl pods # список подов
crictl logs <container_id> # логи контейнера
```
- Автодополнение для `kubectl`
```bash
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
```
#### DNS-сервер
Данный DNS-сервре настраивается для коммуникации между нодами (серверами), для организации резолва имен между сущностями кубера, кубер использует свой ДНС (CoreDNS)
- Установка BIND9
```bash
apt update
apt install -y bind9 bind9utils bind9-doc
```
- vi /etc/bind/named.conf.options
```bash
//
// ------------------------------------------------------------
// Глобальные параметры 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
```bash
// ------------------------------------------------------------
// Авторитетные зоны
// ------------------------------------------------------------
// Прямая зона 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
```bash
$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
```bash
$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.
```
- Проверка синтаксиса
```bash
# Проверяем синтаксис конфигурации
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
```
- Перезапуск сервиса
```bash
systemctl restart named
systemctl enable named
```
- Добавить на каждой ноде в конфиг netplan
```yml
nameservers:
search: [lab.local]
addresses: [192.168.122.66, 8.8.8.8]
```
- Применить
```bash
netplan apply
# или, если нужен лог
sudo netplan apply --debug
```
- Проверка работы DNS
```bash
dig +short k8s-worker2.lab.local
# prt-запись
dig -x 192.168.122.192 +short
```
#### Настройка NFS
##### Настройка NFS-сервера
- Устанавливаем сервер
```bash
apt update
apt install -y nfs-kernel-server
```
- Создаём каталог который будет экспортироваться
```bash
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` - сеть, которой разрешён доступ
- Экспортировать каталог
```bash
exportfs -rav
# проверить
exportfs -v
```
##### Настройка NFS-клиента
```bash
apt install -y nfs-common
```
- Проверить доступность сервера
```bash
# показывает доступные каталоги
showmount -e 192.168.122.157
```
- Монтируем расшаренный каталог на клиент
```bash
mount -t nfs4 192.168.122.157:/ /mnt
```
- Добавить в `/etc/fstab`, для автомонтирования при перезагрузке
```bash
echo "192.168.122.157:/ /mnt nfs4 defaults,_netdev 0 0" | tee -a /etc/fstab
```
#### Разворачиваем кластер
- Версии api, которые поддерживает установленная версия `kubeadm`
```bash
kubeadm config print init-defaults | grep apiVersion
```
- `vi /etc/kubernetes/kubeadm-config.yaml`
```bash
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
```
- Инициализация первой ноды
```bash
kubeadm init --config /etc/kubernetes/kubeadm-config.yaml
```
- Если приложение долго не завершает свою работу, значит что-то пошло не так. Необходимо отменить все действия и запустить его ещё раз, но с большим уровнем отладки.
```bash
kubeadm reset
kubeadm init --config /etc/kubernetes/kubeadm-config.yaml -v5
```
- Смотрим ip для доступа к кластеру
```bash
kubectl cluster-info
```
- Установим драйвер сети (CNI Plugin), Cilium CNI с поддержкой multicast для разворота нод ROS2
```bash
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
```
- Смотрим ноды в кластере
```bash
kubectl get nodes
```
- Смотрим поды на ноде
```bash
kubectl get pods -A
```
- Регистрируем воркер ноды в кластере (представленная команда выводится в стандартный вывод после инициализации первой контрол ноды)
```bash
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оздаёт ресурс, если его нет,или обновляет, если он уже существует, поддерживает историю изменений, идемпотентен
```yml
# пример описания пода
---
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 пода
```bash
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)
- Пример конфигурации
```yaml
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`
```yml
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'ов и уменьшает старые
- следит, чтобы всегда было достаточно доступных реплик
- Пример обновления образа
```bash
kubectl set image deployment/myapp myapp-container=nginx:1.26
```
- Откат на предыдущую версию deployment (на ту версию, которая была применена до последнего успешного обновления)
```bash
kubectl rollout undo deployment myapp
```
- Проверка состояния
```bash
kubectl rollout status deployment myapp
kubectl get deployment
kubectl describe deployment myapp
```
- При каждом изменении (kubectl apply, set image, scale, и т.п.) создаётся новая ревизия, по умолчанию куб хранит 10 ревизий
```bash
# посмотреть историю ревизий
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 удаляются безвозвратно"
- Кусочек конфига
```yaml
volumeMounts:
- name: empty-volume
mountPath: /empty
volumes:
- name: empty-volume
emptyDir: {}
```
#### hostPath
!!! warning "Изпользовать hostPath небезопасно!!!"
Контейнер получает прямой доступ к файловой системе хоста
- Пример
```yaml
volumes:
- name: host-logs
hostPath:
path: /var/log/nginx
type: Directory
```
- Kubernetes может проверять, существует ли путь, и что он из себя представляет
```yaml
type: Directory # Должен быть каталог
type: DirectoryOrCreate # Создает каталог, если его нет
type: File # Должен быть файл
type: FileOrCreate # Создает файл, если его нет
type: Socket # Должен быть сокет
type: CharDevice # Символьное устройство
type: BlockDevice # Блочное устройство
```
#### ConfigMap
ConfigMap - сущность, предназначенная для хранения нечувствительных данных конфигурации в виде пар ключ: значение, позволяет отделить конфигурацию от кода и применять её к контейнерам без необходимости пересборки образа.
- `k get cm`
- Пример
```yaml
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: my-config
```
---
- Пример
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
data:
APP_MODE: production
LOG_LEVEL: debug
```
- Передача переменных окружения из ConfigMap в Pod
```yaml
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 сертификаты
- Пример
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
username: YWRtaW4= # base64 от 'admin'
password: MWYyZDFlMmU2N2Rm # base64 от '1f2d1e2e67df'
```
- Для удобства админитратора есть поле `strigData`, когда манифест примениться содержимое будет закодировано в base64
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
stringData:
username: admin
password: s3cr3t
```
- Так подключается в манифест
```yaml
env:
- name: username
valueFrom:
secretKeyRef:
name: my-secret
key: username
```
!!! warning ""
При добавлении новых секретов, необходимо помнить про правила мерджа манифестов, аннотацию `kubectl.kubernetes.io/last-applied-configuration`
- Добавление секретов в контейнер в виде тома
```yaml
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
```
```bash
# внутри контейнера
cat /etc/secret/username # выведет: user
cat /etc/secret/password # выведет: password
```
#### downwardAPI
`downwardAPI` позволяет передать метаданные `Pod'а`(например, имя пода, namespace, labels, annotations, ресурсы) в контейнер через переменные окружения или файлы.
- Пример (как том (файлы))
```yaml
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
```
- Пример (как переменные окружения)
```yaml
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`
- Пример
```yaml
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"