# Окружение курса: удалённый сервер вместо Windows + Docker Desktop Курс [LEARNING.md](LEARNING.md) написан под Windows + Docker Desktop + Git Bash. Этот документ — альтернативное окружение: тот же курс, тот же kind, но на удалённом Ubuntu-сервере по SSH. Здесь — характеристики железа, результаты бенчмарков и точечные адаптации команд там, где они отличаются от курса. Сам курс не переписан — по нему проходишь как есть, отличия смотришь здесь по мере необходимости. ## Сервер | | | |---|---| | Хост | `totserver@192.168.31.163`, Ubuntu 24.04.3 LTS, kernel 6.8.0-124-generic | | CPU | Intel N100, 4 ядра / 4 потока, до 3.4 ГГц, пассивное охлаждение | | RAM | 16 ГБ DDR4-2667 (1 планка, второй слот пустой — апгрейд до 32 ГБ возможен) | | Диск | Kingston NVMe 1 ТБ, ~852 ГБ свободно | | Сеть | 1 Гбит/с (enp2s0) | | Уже занято | Gitea + Postgres + два CI-раннера + file-server (docker) + Grafana + nginx (systemd), ~1.3 ГБ RAM в простое. Порты 80, 443, **3000 (Grafana)**, **3030 (Gitea)**, 222 (Gitea SSH), 4400 (file-server), 9090 (Prometheus) на хосте заняты этим стеком — **не трогать**. Подробный чек-лист — [«CI-инфраструктура на сервере — что нельзя ломать»](#ci-инфраструктура-на-сервере--что-нельзя-ломать) ниже | | sudo | Требует пароль — все команды курса на этом сервере выполняются без sudo (kind/helm стоят в `~/.local/bin`) | ## Результаты бенчмарков (18-07-2026) | Тест | Результат | |---|---| | CPU, sysbench, 4 потока, 15с | 11 283 events/sec | | CPU, sysbench, 1 поток, 10с | 3 301 events/sec | | RAM, sysbench memory, 4 потока | 9 900 МиБ/с | | Диск, fio seq write 1M blocks | ~1024 МиБ/с (1.07 ГБ/с) | | Диск, fio random 4k, mix 70/30, 4 jobs, iodepth=16 | read 12.6k IOPS / write 5.4k IOPS, avg latency ~0.2 мс | | `kind create cluster` (1 нода, с нуля) | 52.8 с (в основном — скачивание образа ноды `kindest/node`) | | Нода Ready + все поды kube-system Ready | ещё +6.5 с сверху | | Idle-потребление 1-нодового kind-кластера | ~516 МБ RAM, ~20% CPU одного ядра | | Температура CPU под нагрузкой | 60°C (crit 89.8°C у NVMe, 105°C у CPU) — троттлинга нет | ## Вердикт Сервер уверенно тянет весь курс, модули 0–13, включая самый тяжёлый — модуль 11 (`kube-prometheus-stack`, обычно 2–3 ГБ RAM под Prometheus+Grafana+Alertmanager) — с большим запасом в 16 ГБ. Диск с латентностью ~0.2 мс на случайных 4k операциях с запасом покрывает требования etcd к fsync. Ограничение курса «Docker Desktop не меньше 8 ГБ RAM» здесь неактуально — нативный Docker на Linux видит всю память хоста, никакого выделенного лимита нет. Единственное реальное ограничение — 4 ядра CPU: под тяжёлой нагрузкой (например, одновременно 3-нодовый kind-кластер + Helm-чарт с Prometheus) возможны просадки по отзывчивости, но не критично для pet-лабы. ## Точечные адаптации курса по модулям ### Модуль 0 — установка инструментов Вместо `choco install kind kubernetes-cli kubernetes-helm` (Windows): ```bash # kubectl уже стоит через snap (kubectl 1.35.6) — можно оставить, ставить заново не нужно snap list kubectl # kind — бинарь в ~/.local/bin (без sudo) mkdir -p ~/.local/bin KIND_VER=$(curl -s https://api.github.com/repos/kubernetes-sigs/kind/releases/latest | grep -oP '"tag_name": "\K[^"]+') curl -Lo ~/.local/bin/kind "https://kind.sigs.k8s.io/dl/${KIND_VER}/kind-linux-amd64" chmod +x ~/.local/bin/kind # helm — официальный установочный скрипт, без sudo curl -fsSL -o /tmp/get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod +x /tmp/get_helm.sh HELM_INSTALL_DIR=$HOME/.local/bin USE_SUDO=false /tmp/get_helm.sh rm -f /tmp/get_helm.sh # проверка (в интерактивной SSH-сессии ~/.local/bin уже в PATH через ~/.profile) docker --version; kind --version; kubectl version --client; helm version ``` Bash-синтаксис курса (heredoc, `base64 -d`, `curl`) работает нативно в SSH-сессии — отдельный Git Bash не нужен, это уже полноценный Linux. ### Модуль 2 — топология кластера Порты 80/443 хоста заняты Gitea, поэтому в `kind-config.yaml` из модуля 2 сразу добавляй `extraPortMappings`, чтобы не пересоздавать кластер повторно в модуле 6: ```yaml kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 80 hostPort: 8080 - containerPort: 443 hostPort: 8443 - role: worker - role: worker ``` ### Модуль 6 — Ingress Порты 80/443 заняты — доступ к `demo.local` идёт через 8080: ```bash # с самого сервера curl -H "Host: demo.local" http://localhost:8080 # с Windows-машины: добавить в C:\Windows\System32\drivers\etc\hosts # 192.168.31.163 demo.local # и открывать http://demo.local:8080 в браузере ``` ### Модуль 7 — Secret/base64 `base64 -d` и heredoc работают нативно, отдельного Git Bash не требуется (актуально только для Windows-окружения курса). ### Модуль 11 — Helm, kube-prometheus-stack Оговорку курса про «Docker Desktop не меньше 8 ГБ RAM» — игнорировать, неприменимо. Ресурсов в `my-values.yaml` из модуля 11 достаточно оставить как есть или ослабить (сервер потянет и дефолтные значения чарта). ## CI-инфраструктура на сервере — что нельзя ломать Вне периметра K8s-курса, но на этом же сервере: Gitea + два CI-раннера Gitea Actions обслуживают реальный проект (`maxim/Pluto-SDR`, кросс-сборка C-кода под ARM). 18-07-2026 раннер `gitea_runner` был починен из restart-loop (устаревшая регистрация act_runner — вылечено чистой перерегистрацией), и поднят второй раннер `gitea_runner_armhf` — кастомный образ cross-builder'а (Debian + `arm-linux-gnueabihf-gcc` + статические armhf-либы в `/root/xarm`, собираются в образе через `build_deps.sh`). Подробный разбор этой настройки — в [../docker/CASE.md](../docker/CASE.md) → раздел 9 (это реальный кейс легенды, не учебный). **Перед каждой сессией K8s-курса и в конце неё — быстрая проверка, что CI-стек жив:** ```bash docker ps --filter name=gitea --format '{{.Names}}\t{{.Status}}' # ожидаем Up у всех четырёх: gitea, gitea_db, gitea_runner, gitea_runner_armhf ``` Чек-лист, что можно ломать курсом, а что нет: - **Не выполнять** `docker system prune -a` / `docker image prune -a`, пока запущен курс или контейнеры Gitea остановлены: образ `gitea-runner-armhf:latest` собран локально и нигде больше не существует (пересборка — кросс-компиляция 5 ARM-библиотек, ~20 мин и нужен интернет). `kind delete cluster` — безопасен, kind-образы отдельные. - **Не удалять** файлы регистрации раннеров: `/opt/gitea/runner/.runner` и `/opt/gitea/runner-armhf/data/.runner` (личность раннера на сервере) — их удаление форсирует restart-loop, аналогичный уже починенному. `.env`-файлы в тех же каталогах — тоже не трогать. - **Не запускать** `docker-compose ... --remove-orphans` внутри `/opt/gitea` — несколько compose-файлов делят один каталог/проект, `--remove-orphans` может снести соседний стек. - **Порты в `kind-config.yaml`** (`extraPortMappings` из модуля 2) — использовать только 8080/8443. Не занимать 3000 (Grafana), 3030 (Gitea), 222 (Gitea SSH), 4400 (file-server), 9090 (Prometheus). - **Конфиг Gitea**: `REQUIRE_SIGNIN_VIEW = false` в `app.ini` обязателен для CI-клонов (бэкап рядом: `app.ini.bak-2026-07-18`) — не возвращать в `true`. Воркфлоу Pluto-SDR клонируют `localhost:3000` через socat-проброс **внутри** `gitea_runner_armhf` на порт Gitea (:3030) — хостовый порт 3000 (Grafana) тут ни при чём, трогать его конфигурацию не требуется. - **После ребута сервера** всё поднимается само (`restart: unless-stopped` у обоих раннеров + `gitea.service` для Gitea/Postgres) — вмешательство не требуется. - **Признак, что CI жив**: в админке https://totmaxim.ru/-/admin/actions/runners оба раннера (`my-runner`, `my-runner-ci`) online.