K8s
Ссылки#
YAML Синтаксис#
Основные сущности#
-
Скалярные значения
-
Списки (массивы)
или -
Словари
или -
Многострочные строки
|
- сохраняет всё как есть, включая\n
>
- склеивает строки в одну с пробелами
Расширенные возможности#
-
Ссылки и якори ($, *)
-
Линтер
Разное#
-
Null
-
Boolean
чтобы явно задать строку, необходимо использовать кавычки
Разворот кластера#
Буду поднимать 1 мастер ноду, 2 воркер ноды, 1 вспомогательную (DNS, etc)
Поднимаем ВМ для кластера#
Я делаю всё от рута
-
apt update && apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils
- устанавливаем гипервизор -
Создаём ВМ
-
virsh vncdisplay k8s-master
- выводит VNC-дисплей, к которому привязан указанная гостевая ОС, если запущена
Пример вывода
Значит порт: 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 вспомогательную, не забываем менять выделяемые ресурсы для ВМ
Дополнительные команды для управления ВМ
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
- список виртуальных сетей libvirtvirsh net-dumpxml default
- показать XML-конфигурацию сети defaultvirsh dumpxml <vm-name>
- посмотреть XML-конфиг ВМvirsh net-edit default
- отредактировать настройки сети (например, static DHCP)- Клонировать ВМ
Подготовка ВМ#
- Откючаем
swap
, k8s требует отключенный swap для корректной работы планировщика
Не забыть убрать запись из /etc/fstab
Kubernetes использует cgroups для управления CPU и памятью контейнеров. Если включен swap, ядро может игнорировать лимит памяти, потому что будет сбрасывать часть данных в swap. Это нарушает работу OOM (Out Of Memory) killer и других механизмов kubelet'а. Когда swap включён, kubelet может не "увидеть", что контейнер превысил лимит памяти. Kubelet считает, что вся доступная память — это только RAM.
-
Включаем модули ядра для корректной сетевой работы подов
-
Для корректной маршрутизации сетевого трафика
-
Время на узлах должно быть синхронизировано, чтобы избежать проблем с сертификатами или ещё чего-нибудь
-
Проверить что 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, память и т.п.)
-
Добавим репозиторий 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
(удобно для отладки) -
Добавим алиас для команды
kubectl
-
Базовые команды
-
Автодополнение для
kubectl
DNS-сервер#
Данный DNS-сервре настраивается для коммуникации между нодами (серверами), для организации резолва имен между сущностями кубера, кубер использует свой ДНС (CoreDNS)
-
Установка BIND9
-
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.
-
Проверка синтаксиса
-
Перезапуск сервиса
-
Добавить на каждой ноде в конфиг netplan
-
Применить
-
Проверка работы DNS
Настройка NFS#
Настройка NFS-сервера#
-
Устанавливаем сервер
-
Создаём каталог который будет экспортироваться
-
vi /etc/exports
-
rw
- разрешает чтение и запись sync
- операции записи выполняются немедленно (безопасно)no_subtree_check
- ускоряет работу при экспорте подкаталоговroot_squash
- если клиент заходит как root, он будет понижен до "nobody" (безопаснее)fsid=0
- нужен для корня экспортов в NFSv4 (в NFSv4 экспортируется только один корень)-
192.168.122.0/8
- сеть, которой разрешён доступ -
Экспортировать каталог
Настройка NFS-клиента#
-
Проверить доступность сервера
-
Монтируем расшаренный каталог на клиент
-
Добавить в
/etc/fstab
, для автомонтирования при перезагрузке
Разворачиваем кластер#
-
Версии api, которые поддерживает установленная версия
kubeadm
-
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
-
Инициализация первой ноды
-
Если приложение долго не завершает свою работу, значит что-то пошло не так. Необходимо отменить все действия и запустить его ещё раз, но с большим уровнем отладки.
-
Смотрим ip для доступа к кластеру
-
Установим драйвер сети (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 explain <name>
- дока (kubectl explain pod.spec
)kubectl edit deployment deployment_name
(kubectl edit) - изменение манифеста на лету, нигде не версионируется (использовать только для дебага на тесте)
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>
- логи последнего контейнера
Разница между 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 пода
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
доступен для чтения всем клиентам
Repcicaset#
kubectl get rs
- вывести репликасетыkubectl delete rs <name>-rs
- удалить rsk delete replicaset --all
- удалить все rs в nsk describe replicaset <name>
k scale --replicas 3 replicaset <name>
- заскейлисть репликасет-
k set image replicaset <name> <container_name>=<new_image_name>
- обновить образ контейнера (но нужно пересоздать поды, replicaset не решает проблему обновления приложения, rs просто поддерживает заданное количество подов, задачу обновления решает абстрацкия deployment) -
Пример конфигурации
Deployment#
Абстракция более выского уровня, которая управляте replicasetами и podами
- создаёт и управляет ReplicaSet'ом
- Rolling updates — обновляет приложения без простоя
- Откат (rollback) к предыдущей версии
- Масштабирование (scale up/down)
-
Самовосстановление (если Pod удалён или упал)
-
Пример
deployment
Обновление#
- создаваёт новый ReplicaSet с новой версией образа
- постепенно увеличивает количество новых Pod'ов и уменьшает старые
-
следит, чтобы всегда было достаточно доступных реплик
-
Пример обновления образа
-
Откат на предыдущую версию deployment (на ту версию, которая была применена до последнего успешного обновления)
-
Проверка состояния
-
При каждом изменении (kubectl apply, set image, scale, и т.п.) создаётся новая ревизия, по умолчанию куб хранит 10 ревизий