From cc217d032c21e60c59163a1a1891a2b26100ca97 Mon Sep 17 00:00:00 2001 From: ilyamak04 Date: Sun, 29 Jun 2025 16:09:22 +0300 Subject: [PATCH] k8s --- docs/Other/k8s.md | 587 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 583 insertions(+), 4 deletions(-) diff --git a/docs/Other/k8s.md b/docs/Other/k8s.md index 8a39e6d..57e6a9a 100644 --- a/docs/Other/k8s.md +++ b/docs/Other/k8s.md @@ -1,3 +1,5 @@ +### Ссылки + ### YAML Синтаксис #### Основные сущности @@ -124,13 +126,38 @@ virt-install \ Значит порт: 5900 + 0 - `remote-viewer vnc://localhost:5900` - конфигурируем, устанвливаем ВМ -- `virsh list` - список запущенных ВМ +- `virsh list --all` - список запущенных ВМ - `virsh start k8s-master` - запуск созданонй ВМ - `virsh domifaddr k8s-master` - узнаём адрес ВМ - `ssh ilyamak04@192.168.122.157` - ну и подключаемся по ssh Аналогично поднимаем 2 воркер ноды, и 1 вспомогательную, не забываем менять выделяемые ресурсы для ВМ +??? info "Дополнительные команды для управления ВМ" + - `virsh shutdown ` - штатное выключение ВМ + - `virsh destroy ` - жёсткое выключение, например, если ВМ зависла, НЕ УДАЛЯЕТ ВМ + - `virsh list --all` - показать список всех виртуальных машин (включая выключенные) + - `virsh start ` - запустить виртуальную машину + - `virsh undefine ` - удалить ВМ из libvirt (не удаляет диск в /var/lib/libvirt/images/) + - `virsh domifaddr ` - показать IP-адрес ВМ (если доступен) + - `virsh dumpxml ` - вывести XML-конфигурацию ВМ + - `virsh console ` - подключиться к консоли ВМ (если настроен serial-порт) + - `virsh domstate ` - показать текущее состояние ВМ + - `virsh autostart ` - включить автозапуск ВМ при старте хоста + - `virsh autostart --disable ` - отключить автозапуск ВМ + - `virsh net-list` - список виртуальных сетей libvirt + - `virsh net-dumpxml default` - показать XML-конфигурацию сети default + - `virsh dumpxml ` - посмотреть 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 для корректной работы планировщика @@ -158,7 +185,7 @@ net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 EOF -# проверяем +# перечитываем конфигурации, применяем sysctl --system ``` @@ -174,6 +201,415 @@ 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 <> ~/.bashrc +source ~/.bashrc +``` + +- Базовые команды +```bash +crictl info # информация о рантайме +crictl ps -a # список всех контейнеров +crictl images # список всех образов +crictl pods # список подов +crictl logs # логи контейнера +``` + +- Автодополнение для `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:/srv/nfs/k8s /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 ` - дока (`kubectl explain pod.spec`) +- `kubectl edit deployment deployment_name` (kubectl edit) - изменение манифеста на лету, нигде не версионируется (использовать только для дебага на тесте) ### POD @@ -183,8 +619,18 @@ POD - одно запущенное приложение в кластере k8s - `kubectl create -f pod.yml` - создать под согласно конфигу из файла - `kubectl get pod` - список подов -- `kubectl describe pod ` - описание объекта +- `kubectl describe pod ` - описание пода +- `kubectl describe pod -n | less` - описание пода в нс - `kebectl delete pod ` или `kubectl delete -f pod.yml` - удаление пода +- `k -n delete pod ` - удалить под + +- `k get pod -n -o yaml | less` - посмотреть полный манифест пода +- `kubectl -n logs ` - логи пода +- `kubectl -n logs -c ` - логи последнего контейнера + +!!! info "Разница между `create` и `apply`" + `create` создаёт ресурс только если его ещё нет, если ресурс уже существует — выдаёт ошибку + `apply` cоздаёт ресурс, если его нет,или обновляет, если он уже существует, поддерживает историю изменений, идемпотентен ```yml # пример описания пода @@ -199,4 +645,137 @@ spec: # описание объекта image: nginx:latest ports: - containerPort: 80 -``` \ No newline at end of file +``` + +#### Ресурсы (QoS) + +Приоритет Pod'ов при выделении ресурсов и при давлении на узел + +QoS не управляется напрямую, а автоматически присваивается каждому Pod'у в зависимости от указанных ресурсов (requests и limits) в манифесте. + +куб определяет 3 уровня QoS + +- `Guaranteed` - requests == limits для всех контейнеров в Pod'е, высший приоритет, удаляется в последнюю очередь +- `Burstable` - задан requests, но не равно limits, или не для всех +- `BestEffort` - не указано ничего (ни requests, ни limits), если ресурсов на ноде не хватает, такие поды убиваются в первую очередь + +- Посмотреть QoS пода +```bash +kubectl get pod -o jsonpath='{.status.qosClass}' +``` + +#### Best practice для описания пода + +Должны быть: +- Метки +- Задан образ контейнера +- Ресурсы контейнера(ов) ограничены +- Пробы + +### Namespace + +- Namespace используются для изоляции групп ресурсов в пределах одного кластера kubernetes. Имена ресурсов должны быть уникальными в пределах namespace. + +- `kubectl get ns` - вывести неймспейсы +- `kubectl create ns ` - создать нс +- `kubectl delete ns ` - удалить нс +- `k get ns ` +- `kubectl config set-context --current --namespace=<имя-namespace>` - сменить ns чтобы писать команды без флага `-n` + +- нс `kube-system` располагаются приложения control-plane +- нс `kube-public` доступен для чтения всем клиентам + +### Repcicaset + +- `kubectl get rs` - вывести репликасеты +- `kubectl delete rs -rs` - удалить rs +- `k delete replicaset --all` - удалить все rs в ns +- `k describe replicaset ` +- `k scale --replicas 3 replicaset ` - заскейлисть репликасет +- `k set image replicaset =` - обновить образ контейнера (но нужно пересоздать поды, 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ами + +- создаёт и управляет 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 +``` + +#### Обновление + +- создаваёт новый 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 +``` +