# Архитектура ## Топология кластера Кластер работает в **HA-режиме** с embedded etcd: все три ноды являются полноценными мастерами. При отказе **любой одной** ноды кластер продолжает работать (кворум 2 из 3). ``` ┌──────────────────────────────────────────────────────────────┐ │ Локальная сеть 192.168.1.0/24 │ │ VIP: 192.168.1.100 (kube-vip) │ │ ├── :6443 K3S API Server (HA) │ │ └── :80/:443 ingress-nginx → приложения │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │ │ │ master01 │ │ worker01 │ │ rpi01 │ │ │ │ 192.168.1.10 │ │ 192.168.1.11 │ │ .1.12 │ │ │ │ x86_64 │ │ x86_64 │ │ aarch64 │ │ │ │ K3S server │ │ K3S server │ │ K3S server │ │ │ │ etcd #1 │ │ etcd #2 │ │ etcd #3 │ │ │ │ cluster-init │ │ kube-vip │ │ NoSchedule │ │ │ │ NFS server │ │ workloads ✓ │ │ workloads ✗│ │ │ │ workloads ✓ │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────┘ │ │ StorageClass: nfs-master01 (default) │ └──────────────────────────────────────────────────────────────┘ ``` ## Роли нод | Нода | etcd | Workloads | Описание | |---|---|---|---| | master01 | #1 (leader) | ✓ | cluster-init, NFS server | | worker01 | #2 | ✓ | Рабочие нагрузки | | rpi01 | #3 | ✗ | Только quorum, taint NoSchedule | ## CNI плагин ```yaml # group_vars/all/main.yml k3s_cni: "flannel" # flannel | calico | cilium ``` | CNI | Особенности | |---|---| | `flannel` | Встроен в K3S, VXLAN overlay, минимальная настройка | | `calico` | Network Policy, IPAM, BGP, VXLAN/IPIP | | `cilium` | eBPF dataplane, Hubble observability, L7 policy | При calico/cilium Flannel отключается автоматически. ```bash make install-cni K3S_CNI=calico make install-cni K3S_CNI=cilium ``` ## Порядок инициализации K3S ``` master01 (cluster-init: true) ↓ API готов на :6443 worker01 (join → master01) ↓ etcd = 2/3 rpi01 (join → master01, NoSchedule taint) ↓ etcd = 3/3, кворум достигнут ``` ## kube-vip VIP через ARP (L2). При отказе мастера VIP мигрирует за несколько секунд. Требования к VIP: - В той же подсети что серверы - Не занят другим устройством - Не в пуле DHCP Автоопределение интерфейса через `ansible_default_ipv4.interface` — работает для Ubuntu (`enp3s0`), RPi (`end0`), VM (`eth0`). Принудительно: `kube_vip_interface: "eth0"`. kube-vip также обрабатывает `LoadBalancer` сервисы — все аддоны получают IP из подсети. ## NFS + CSI NFS сервер на master01, StorageClass именуется `nfs-` (например `nfs-master01`). Каждый PVC → отдельная папка в `/storage/nfs/`: ``` /storage/nfs/ ├── default/my-pvc/pvc-xxx-yyy/данные/ ``` NFS на отдельном хосте: ```ini [nfs_server] nfshost ansible_host=192.168.1.20 ``` ```yaml csi_nfs_server: "192.168.1.20" ``` ## ingress-nginx LoadBalancer сервис → IP от kube-vip. Отключает Traefik K3S. Поддерживает кастомную страницу ошибок. ## Raspberry Pi Роль автоматически определяет ARM-архитектуру и: 1. Включает `memory cgroup` в `/boot/firmware/cmdline.txt` + перезагрузка 2. Пониженные kubelet-резервы (`cpu=50m, memory=128Mi`) 3. Taint `node-type=raspberry-pi:NoSchedule` Рекомендуемая ОС: **Raspberry Pi OS Lite 64-bit (Bookworm)** для RPi 4/5. Для деплоя на RPi добавь toleration: ```yaml tolerations: - key: "node-type" operator: "Equal" value: "raspberry-pi" effect: "NoSchedule" ``` ## Docker образ ``` FROM python:3.12-slim-bookworm ├── ansible-core 2.16, ansible 9.x ├── Helm 3.14.4, kubectl v1.29.3 ├── molecule >= 6.0 + molecule-plugins[docker] ├── yamllint, ansible-lint └── Collections: community.general, ansible.posix, kubernetes.core ```