Files
homelab-upgrade/docs/DEPLOY.md
T
homelab-updaterandClaude Opus 5.5 4b6b179525
ci / check (push) Failing after 6s
ci / publish (push) Skipped
docs: Trilium connected to Arcane Git Sync
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:59:56 +02:00

25 KiB

Wdrożenie na VM103

Stan na 2026-09-19: na VM103 działa łańcuch prawdziwej aktualizacji przez sidecar executor (sekcja „Prawdziwe aktualizacje”). Pierwsza aktualizacja: jackett v0.24.2601-ls30 → v0.24.2624-ls33 (18:06, verify ok). Aplikacja bez „Real updates” zostaje w trybie na sucho.

Adres https://upgrade.mariuszpacek.pl (traefik, web-secured, certyfikat http, wildcard DNS na 192.168.0.139)
Dostęp z LAN i z internetu, tylko po zalogowaniu Keycloakiem (realm home, usługa auth = oauth2-proxy jako forwardAuth Traefika; sekcja „Logowanie”)
Manifest /opt/homelab/compose/homelab-upgrade/compose.yaml (kopia deploy/compose.yaml)
Obraz git.mariuszpacek.pl/mariusz.pacek/homelab-upgrade:<tag> z rejestru Gitei, budowany przez Gitea Actions (etykieta org.opencontainers.image.revision = sha commita)
Dashboard kafelek „Upgrade” w grupie Infra na https://dash.mariuszpacek.pl z etykiet homepage.* na server (homepage czyta je przez swoje połączenie z Dockerem; jego pliki nie są zmieniane)
Stopka gałąź i numer buildu CI (foundations · build 6; na master sam numer), pełny sha w podpowiedzi; z argumentów builda BRANCH, BUILD_NUMBER, REVISION → /api/build
Tagi <sha> (pełny, do wycofania), <gałąź> (master, foundations), latest tylko z master
Dane /srv/appdata/homelab-upgrade/data (SQLite + WAL, właściciel uid 1000, chmod 700)
Kontenery server (sieci default + proxy), driver (sieci default + docker + executor; wyjście do rejestrów i adresów aplikacji; nie widzi plików projektów compose), docker-proxy (docker.sock tylko do odczytu, przepuszcza tylko GET na kontenery; sieć docker bez wyjścia), executor (jedyny zapisujący: root bez capabilities, docker.sock, /opt/homelab/compose; sieć executor bez wyjścia), model (claude CLI właściciela, uid 1000, bez socketu i plików projektów; sieci default + executor)
Kopie manifestów /srv/appdata/homelab-upgrade/backups/<projekt>/<id>/ (root, katalogi 0700, pliki 0600)
Rekord vzdump /srv/appdata/homelab-upgrade/host/vzdump.json (pisze timer na Proxmoksie, driver czyta tylko do odczytu)

server i driver: użytkownik 1000, system plików tylko do odczytu (poza /data i /tmp), bez capabilities, bez portu na hoście, bez docker.sock. docker-proxy ma docker.sock tylko-do-odczytu i przepuszcza wyłącznie GET na /containers (POST=0). Jego system plików nie jest tylko do odczytu, bo entrypoint przy starcie zapisuje haproxy.cfg (przy read_only kontener restartował się w pętli). Port 8080 na hoście VM jest zajęty przez inną usługę, dlatego appka nie publikuje portu: traefik łączy się z kontenerem przez sieć proxy.

Aktualizacja

Obieg: git push → Gitea Actions (.gitea/workflows/ci.yaml): npm run check, a na master, foundations i tagach wydań v… także build i push obrazu do rejestru Gitei → wdrożenie tylko ręcznie, przyciskiem albo przez API. Arcane nie zarządza tym projektem.

Wydanie: tag v<rok>.<miesiąc>.<numer> (np. v2026.10.1) na commicie z master, najlepiej jako release w Gitei; CI buduje obraz :v2026.10.1 (i :<sha>). Stopka pokazuje wtedy v2026.10.1 · build N.

Wdrożenie: Gitea → repo → Actions → deploy → Run workflow (gałąź master), pole version: tag wydania, pełny sha albo latest (ostatni master); force tylko świadomie. To samo przez API/MCP: dispatch_workflow z workflow_id: deploy.yaml, ref: master, inputs: { version, force }; wynik i log w runie.

Workflow (.gitea/workflows/deploy.yaml) działa tylko z definicji na master: sprawdza format wersji, pobiera obraz i uruchamia skrypt z tego obrazu (/app/deploy/update.sh --install) na katalogu /opt/homelab/compose/homelab-upgrade przez socket Dockera. update.sh:

  1. odmawia (kod 3), gdy instancja silnika jest w stanie running (run na bramce lub w kolejce restart przeżywa, przerwany węzeł wznawia się w UI przyciskiem „Retry the step”);
  2. robi spójną kopię bazy przez działający serwer (/data/queue.sqlite.before-deploy-<czas>, zostaje 5 najnowszych); bez kopii odmawia (kod 5);
  3. z --install wgrywa compose.yaml i update.sh z obrazu (poprzedni compose zostaje jako compose.yaml.previous, diff w logu);
  4. docker compose pull (gdy obrazu nie ma: przywraca compose i kończy bez restartu) i up -d;
  5. czeka do 90 s na healthy serwera i executora oraz na stabilne pozostałe usługi; gdy nowa wersja nie wstaje, wraca do poprzedniego obrazu (lokalny tag :rollback) i poprzedniego compose.yaml, nie zmienia .env i kończy się kodem 1.

--force pomija krok 1 i pozwala na brak kopii z kroku 2. Wycofanie to ponowne wdrożenie starszej wersji tym samym przyciskiem. Stare obrazy zostają na VM.

Awaryjnie, gdy Gitea lub runner nie działa, ten sam skrypt ręcznie na VM103:

cd /opt/homelab/compose/homelab-upgrade
./update.sh                 # tag z .env (domyślnie latest)
./update.sh v2026.10.1      # inna wersja (tag, gałąź albo pełny sha) i zapamiętanie jej w .env
./update.sh --force         # pomija blokadę „trwa krok / węzeł runu” i brak kopii bazy

Ręczny update.sh nie wgrywa compose.yaml; po zmianie deploy/compose.yaml wdrażaj przyciskiem albo skopiuj plik.

Przy zmianie schematu bazy nowa wersja migruje bazę przy starcie (migracje są transakcyjne; nowszej bazy niż kod odmawia otwarcia). Wycofanie do starszego obrazu po zmianie schematu nie zadziała, bo starszy kod odmówi otwarcia nowszej bazy: wtedy przywraca się kopię queue.sqlite.before-deploy-* z kroku 2.

Logowanie (Keycloak)

Usługa auth (oauth2-proxy, deploy/compose.yaml) stoi przed aplikacją: Traefik pyta ją o każde zapytanie (forwardAuth); bez sesji przeglądarka idzie do https://login.mariuszpacek.pl/realms/home, po powrocie wpuszczane są tylko adresy z AUTH_ALLOWED_EMAILS. Sesja trwa 7 dni (odświeżana co godzinę), wylogowanie: https://upgrade.mariuszpacek.pl/oauth2/sign_out. Publiczne zostają tylko manifest.webmanifest i icon.svg.

Jednorazowo w Keycloaku (realm home):

  1. Clients → Create client: typ OpenID Connect, Client ID homelab-upgrade; Client authentication on, Standard flow on, Direct access grants off.
  2. Valid redirect URIs https://upgrade.mariuszpacek.pl/oauth2/callback, Web origins https://upgrade.mariuszpacek.pl.
  3. Client scopes → homelab-upgrade-dedicated → Add mapper → By configuration → Audience: Included Client Audience homelab-upgrade, Add to access token on (oauth2-proxy sprawdza audience).
  4. Credentials → skopiuj Client secret.

W /opt/homelab/compose/homelab-upgrade/.env na VM103 (root, 600):

AUTH_CLIENT_SECRET=<client secret z Keycloaka>
AUTH_COOKIE_SECRET=<openssl rand -base64 32 | tr -- '+/' '-_'>
AUTH_ALLOWED_EMAILS=<adres e-mail konta w Keycloaku>

Bez tych trzech wartości docker compose odmawia (wdrożenie kończy się bez restartu, update.sh przywraca poprzedni compose.yaml).

Jednorazowa konfiguracja

  1. Rejestr: działa od razu (Packages w Gitei są domyślnie włączone; https://git.mariuszpacek.pl/v2/ odpowiada 401).
  2. Token (Gitea → Settings → Applications): write:package dla CI. Tokenów nie wklejamy do repo ani logów. read:package dla VM103 nie jest potrzebny, dopóki pakiet jest publiczny (pull anonimowy działa).
  3. Sekret repo REGISTRY_TOKEN (repo → Settings → Actions → Secrets): token write:package.
  4. Runner (deploy/runner/, na VM103 w /opt/homelab/compose/gitea-runner/; dane w /srv/appdata/gitea-runner/data). Token rejestracyjny: repo → Settings → Actions → Runners → Create new runner (token na poziomie repo zamiast całej instancji). Runner ma docker.sock, czyli praktycznie root na VM: rejestruj go tylko dla tego repo.
  5. docker login na VM103: pomijamy, bo pull jest anonimowy. Gdyby pakiet stał się prywatny: docker login git.mariuszpacek.pl -u mariusz.pacek tokenem read:package.
  6. Przełączenie z lokalnego obrazu: skopiuj deploy/compose.yaml i deploy/update.sh do /opt/homelab/compose/homelab-upgrade/, po pierwszym zielonym buildzie uruchom ./update.sh <sha>. Później oba pliki wgrywa workflow deploy.

Ograniczenia, które warto znać: job dostaje repo z http://192.168.0.139:13080 (port Gitei na VM), bo whitelist traefika nie obejmuje sieci jobów; docker push idzie z demona VM, więc źródłowy adres to 192.168.0.139 z whitelisty Gitei.

Awaryjnie: build ręczny bez rejestru

Na hoście Proxmox: git archive --format=tar.gz -o /tmp/src.tar.gz HEAD, przenieś plik na VM103 (sha256 do porównania). Na VM103:

cd /srv/appdata/homelab-upgrade/build && rm -rf src && mkdir src && tar -xzf src.tar.gz -C src
cd src && docker build --pull=false -t git.mariuszpacek.pl/mariusz.pacek/homelab-upgrade:manual --build-arg REVISION=<sha> .
cd /opt/homelab/compose/homelab-upgrade && TAG=manual docker compose up -d

Notatki wydań i kontrola po aktualizacji (per aplikacja)

Notatki wydań nie są ustawieniem: są w skillu projektu (Apps → aplikacja → Skill), w wierszu „Release notes” tabeli „Źródła”, np. | Release notes | https://nextcloud.com/changelog/ · https://github.com/nextcloud/server/releases |. Link github.com/<owner>/<repo>/releases driver czyta przez API GitHuba (tylko wydania między działającą wersją a kandydatem), każdy inny link jako stronę; do 4 źródeł. Z takim wierszem skok powyżej progu auto trafia najpierw do modelu (release_notes), a właściciel widzi w decyzji jego ocenę. Bez wiersza jest zwykły STOP. 10 z 15 skilli w config/skills/ ma już taki wiersz (brakuje w deluge, dockge, gitea, homepage i keycloak: tam major dostaje zwykły STOP, dopóki wiersz nie zostanie dopisany w skillu).

Jedno ustawienie w Apps → aplikacja, domyślnie wyłączone:

  • Post-upgrade check executor: sonnet / opus = po udanym verify model sprawdza, czy aktualizacja wymaga czynności poinstalacyjnych (czyta ocenę notatek, skill i stan usługi; co robić po aktualizacji, można dopisać w skillu). Model wykona tylko to, co dopuszcza config/agent-exec.json (dokładne komendy, bez wildcardów); reszta trafia do właściciela jako STOP migration_required. Dziś lista ma tylko komendy Nextclouda: kontrola odbiorcza ze skilla (tylko odczyt: php occ status z --output=json i bez, php occ config:app:get core lastcron, php occ app:list, pidof crond w usłudze cron) oraz to, co po upgrade brakuje w bazie (php occ db:add-missing-indices, db:add-missing-columns, db:add-missing-primary-keys; użytkownik www-data, usługa app). Model widzi listę przez hl exec-rules i nie zgaduje. Dla pozostałych aplikacji ten krok tylko wypisze, co zrobić ręcznie.

Schemat bazy przechodzi na v10 (v8 dodał post_upgrade_executor, v9 zdejmuje niepotrzebną release_notes_source, v10 dodaje niepodłączony jeszcze katalog i instancje nowego silnika workflow); starszy obraz jej nie otworzy, więc przed wdrożeniem kopia queue.sqlite*.

Dry run: jak testować

  1. W appce (https://upgrade.mariuszpacek.pl) otwórz aplikację (Apps → nazwa) i kliknij „Dry run”. Run niczego nie zmienia: czyta działającą wersję, rejestr i release notes, a przed kopią i apply kończy się na „Dry run finished”.
  2. Przebieg widać na stronie runu (graf i historia); gdy run czeka na decyzję, jest na Overview i przychodzi push.
  3. Konfigurację aplikacji (app_config) zmienia się na jej stronie: włączenie, próg auto, wzorzec tagów, URL i status do sprawdzenia, wykonawcy modeli, podpowiedź, notatka, „Real updates”. Usługa, obraz i pozycja są tylko do odczytu. config/apps.json służy tylko do zasiania nowych wpisów.

Znane ograniczenia tego etapu:

  • dockge i grafana mają w compose sam digest, bez tagu. docker ps pokazuje jednak w polu Image lokalny tag wskazujący ten sam obraz (np. louislam/dockge:1.5.0, sprawdzone 2026-09-19), więc status może przejść dalej zamiast zatrzymać się na version_unknown. Taki tag to nazwa nadana obrazowi przy pobraniu, nie to, co stoi w compose. Pewną wersję da port image_version.
  • Nazwa projektu compose musi być nazwą katalogu (domyślna w compose). Projekt z własnym name: w compose.yaml da błąd „no container of service …”.
  • manifest_sha256 jest null: ten tryb nie czyta compose.yaml. Kroki zmieniające (backup, apply) będą potrzebowały dostępu do plików projektów, a to decyzja właściciela.
  • homeassistant startuje wyłączony (config/apps.json); od 2026-09-23 nie ma już listy aplikacji pod absolutnym STOP, więc właściciel włącza go (i traefik, mqtt, unifi) flagą enabled na stronie aplikacji.
  • Driver nie czyta plików projektów, ale proxy z CONTAINERS=1 pozwala na inspect, który pokazuje zmienne środowiskowe kontenerów. Dopóki nie ma boksu, driver jest kodem zaufanym.
  • Driver ma ruch wychodzący do całej sieci (nie tylko do rejestrów); zawężenie to zadanie boksu.

Prawdziwe aktualizacje (executor)

Decyzje właściciela i zasady: docs/DESIGN.md, „Executor”. Każda aplikacja ma workflow update-<app> (kopia szablonu z domain/workflow-update.ts): odczyt wersji, wybór obrazu, release notes, kopia, apply_dry_run, apply, verify, sprawdzenie przez model; zmiana powyżej progu auto, brak kopii, nieudany verify itd. zatrzymują run na bramce z decyzją właściciela (Overview). Run „Real” wymaga „Real updates” w konfiguracji aplikacji.

Jednorazowe przygotowanie (każdy zapis za zgodą właściciela)

  1. Kopia bazy (migracja v2 dodaje app_config.apply; starszy obraz nie otworzy nowszej bazy):
    cd /srv/appdata/homelab-upgrade/data && for f in queue.sqlite*; do cp -p "$f" "$f.before-v2"; done
    
  2. Katalogi na VM103:
    install -d -o root -g root -m 0700 /srv/appdata/homelab-upgrade/backups
    install -d -o root -g root -m 0755 /srv/appdata/homelab-upgrade/host
    
  3. Timer na Proxmoksie (pliki z deploy/proxmox/): skrypt co godzinę czyta najnowszą kopię VM103 z vm-storage (pvesh) i zapisuje ją przez guest agenta do host/vzdump.json (plik 0644, bez sekretów).
    install -m 0755 homelab-upgrade-vzdump-record /usr/local/sbin/
    install -m 0644 homelab-upgrade-vzdump.service homelab-upgrade-vzdump.timer /etc/systemd/system/
    systemctl daemon-reload && systemctl enable --now homelab-upgrade-vzdump.timer
    systemctl start homelab-upgrade-vzdump.service   # pierwszy zapis od razu
    
  4. deploy/compose.yaml i deploy/update.sh do /opt/homelab/compose/homelab-upgrade/, potem ./update.sh foundations. update.sh czeka też na zdrowy executor.
  5. Whitelisty traefika: driver łączy się z adresami aplikacji jako 172.16.0.1 (brama sieci proxy po maskaradzie). W jackett i ombi nieaktualny wpis 172.18.0.1/16 zamieniono 2026-09-19 na 172.16.0.1/32 (kopie .compose.yaml.before-whitelist-20260919T121215Z); orca odpowiada 401 (basic auth aplikacji), tak jak z LAN. Nowa aplikacja z whitelistą potrzebuje tego samego wpisu, inaczej verify dostanie 403.

Włączenie i przebieg

  1. Apps → aplikacja → „Real updates” → Save. To jedyne miejsce konfiguracji: executor ma EXECUTOR_PROJECTS: "*" (wszystkie projekty poza absolutnym STOP i samym homelab-upgrade). Jawna lista w compose.yaml zawęziłaby to; aplikacja spoza niej kończy się STOP w status. Przed zmianą preflight sprawdza adres aplikacji: gdy już wtedy odpowiada inaczej niż „Expected HTTP status” (np. 403 z whitelisty), łańcuch staje przed kopią i apply, bo verify mógłby tylko cofnąć zmianę.
  2. Strona aplikacji → „Real run” (albo harmonogram w trybie Real). Wersja w progu auto przechodzi sama: kopia, apply_dry_run (diff: tylko services.<usł>.image), apply, verify, sprawdzenie przez model.
  3. Bramki (Overview → „Decide”): „Approve the update” — Proceed = reszta runu sama, Skip = nic się nie zmienia; „Update check failed” / „Repair failed” — Roll back przywraca compose.yaml z kopii, Skip zostawia jak jest. Rollback cofa tylko manifest, nie dane: Nextcloud, radarr, sonarr, bazarr i jellyfin migrują bazę przy starcie i na starszym obrazie mogą nie wstać („downgrading is not supported”). Wtedy naprawa to nowszy obraz i dokończenie migracji (Nextcloud: occ upgrade, occ maintenance:mode --off).
  4. Po zmianie: kopia w backups/<projekt>/<id>/, log executora (docker compose logs executor: projekt, usługa, hash przed i po).

Grupy (DESIGN.md, „Grupy”): Apps pokazuje składniki projektu razem (grafana, pod nim └ influxdb); każdy ma własny przełącznik „Real updates”, próg i adres. Usługi na tym samym obrazie (nextcloud app + cron) zmieniają się razem. Nowe wpisy z config/apps.json (np. składniki baz) driver dopisuje przy starcie, nie ruszając istniejących wierszy. gitea-db (postgres:14) i nextcloud-redis (redis:7-alpine) są wyłączone: najpierw trzeba w manifeście przypiąć konkretną działającą wersję.

2026-09-19, Nextcloud 31.0.12 → 31.0.14: verify po 30 s widział health: starting i 404 (migracja bazy przy starcie), a automatyczny rollback przywrócił 31.0.12 na dane 31.0.14.1, więc kontener restartował się w pętli. Naprawa: app i cron na nextcloud:31.0.14-apache@sha256:07ec73cc… (kopia manifestu backups/nextcloud/manual-20260919T184504Z), occ upgrade, occ maintenance:mode --off. Od tej wersji verify czeka na start i nie cofa sam.

Ręczny powrót do dowolnej kopii: STOP w kolejce → rollback, albo z kroku z backup_id w wejściu. Wyłączenie wszystkiego: odznacz „Real updates” (kroki zmieniające kończą się wtedy bez zmian) albo usuń EXECUTOR_URL z drivera (cały driver wraca do trybu na sucho).

Model, powiadomienia, noc

Jednorazowo (właściciel)

  1. Katalog logowania modelu na VM103: install -d -o 1000 -g 1000 -m 0700 /srv/appdata/homelab-upgrade/claude.
  2. Logowanie claude (Twoim kontem, raz; dane zostają w tym katalogu):
    cd /opt/homelab/compose/homelab-upgrade && docker compose exec -it model-claude /opt/claude/bin/claude
    # w CLI: /login, potem /exit
    
    Wygasłe logowanie kończy repair błędem auth_failed (push); wtedy powtórz ten krok.
  3. Katalog logowania Codeksa na VM103: install -d -o 1000 -g 1000 -m 0700 /srv/appdata/homelab-upgrade/codex.
  4. Logowanie codex (Twoim kontem, raz; dane zostają w tym katalogu):
    cd /opt/homelab/compose/homelab-upgrade && docker compose run --rm model-codex /opt/codex/bin/codex login --device-auth
    
    Bez tego kroku profile Codeksa kończą się błędem auth_failed.
  5. Home Assistant: w /opt/homelab/compose/homelab-upgrade/.env dopisz (nigdy do repo):
    HA_URL=http://192.168.0.139:8123
    HA_TOKEN=<długoterminowy token z profilu HA>
    HA_NOTIFY=notify.<twoja_usługa>
    
    update.sh zmienia w .env tylko linię TAG=.
  6. Harmonogram: każdy workflow ma własny cron (strona aplikacji albo Workflows → Schedule); starego NIGHTLY_AT już nie ma. Stary homelab-nightly-update.timer na Proxmoksie wyłącz dopiero wtedy, gdy harmonogramy nowego silnika działają: systemctl disable --now homelab-nightly-update.timer.
  7. ./update.sh po każdej zmianie .env.

Jak działa

  • Nieudany verify → model.repair: model przez hl ogląda i naprawia jedną aplikację, potem kod wykonuje jeszcze raz verify; gdy i to nie pomoże, run czeka na bramce (rollback albo zostaw).
  • hl exec w repair jest domyślnie wyłączony. Dokładne dopuszczenia (project, service, user albo null, pełne argv) wpisuje się do wersjonowanego config/agent-exec.json; nie ma wildcardów ani sh -c.
  • Skill aplikacji (Apps → aplikacja → Skill) to fakty dla modelu; warto tam wpisać wymagania wersji (np. „Nextcloud 32 wymaga MariaDB ≥ 10.6”).
  • Push (driver, Home Assistant), gdy run czeka na decyzję, gdy się nie powiedzie i gdy run „Real” się skończy; bez HA_URL/HA_TOKEN tylko do logu.

Arcane i repo compose

Repozytorium ssh://git@git.mariuszpacek.pl:2244/mariusz.pacek/homelab-compose.git jest prywatne, na master, zawiera 20 katalogów projektów z samym compose.yaml, archiwum to_delete/dockge oraz .gitignore; pliki .env i sekrety nie są śledzone. Główny checkout VM103: /srv/appdata/homelab-upgrade/git/repo. Dziesięć compose używających env_file w formacie raw skonwertowano przez tools/compose-env-compat.py; pełny wynik docker compose config porównano ściśle, wartości lokalne pozostały bez zmian.

Arcane v2.13.1 działa pod https://arcane.mariuszpacek.pl. Projekty używają Git Sync w trybie Deploy (w UI: Pull), ścieżka <projekt>/compose.yaml, syncDirectory=false, interwał 5 minut. Autosync jest włączony dla wszystkich 19 projektów; stosy Arcane i homelab-upgrade są wyłączone, a upgrade-lab działa bezpośrednio. Wszystkie manifesty projektów zawierają etykietę com.getarcaneapp.arcane.updater: "false". Arcane sam wykonuje redeploy projektu po zmianie compose, więc executor w trybie git nie uruchamia pull/up.

Początkowe synchronizacje 18 projektów (i Trilium, dołączonego 2026-09-30) zachowały SHA plików env i nie zmieniły startów kontenerów; Arcane może utworzyć pusty .env. Źródła nie wymagały restartu podczas importu. Test Jackett przez API executora potwierdził ścieżkę komentarz → commit 47c2b7f → push → udany sync Arcane i HTTP 301; rollback executora wykonał git revert, przywrócił pierwotny SHA i zakończył się powodzeniem.

config/workflow-schedules.json rozkłada starty w strefie Europe/Warsaw (czas polski): poniedziałek Bazarr 19:00, Jackett 21:00; wtorek Radarr 19:00, Sonarr 21:00; środa Deluge 19:00, Ombi 21:00; czwartek Homepage 19:00, OrcaSlicer 21:00; piątek Gitea 18:00, baza 19:00, Keycloak 20:00, baza 22:00; sobota Home Assistant 18:00, Nextcloud 20:00, baza 22:00, Redis 23:00; niedziela Trilium 16:00, Grafana 18:00, Jellyfin 20:00. InfluxDB i Dockge są wyłączone.

Konfiguracja prywatna /srv/appdata/homelab-upgrade/git-config/deployments.json jest montowana jako /git-config tylko do odczytu, a GIT_DEPLOYMENTS_FILE=/git-config/deployments.json. Schemat v1: repoPath=/git/repo, branch=master, sshKeyPath=/git-ssh/id_ed25519, knownHostsPath=/git-ssh/known_hosts; projekty mają tryb direct albo git, webhookUrl i opcjonalny redeployWebhookUrl. Executor ma checkout do zapisu, katalog git-ssh tylko do odczytu oraz sieci executor i default; git i OpenSSH są częścią obrazu. Klucz executora z prawem zapisu znajduje się w /srv/appdata/homelab-upgrade/git-ssh/id_ed25519, klucz Arcane tylko do odczytu w /srv/appdata/arcane/git-ssh/id_ed25519. known_hosts przypina trzy publiczne algorytmy Gitei porównane z plikiem .pub kontenera. Nie umieszczaj tokenów ani webhook URL zawierających sekrety w dokumentacji, repo ani logach.

Kod obsługuje apply, migrate, rollback i hl write/up; istniejący verify nadal rozstrzyga powodzenie. Brudny checkout, rozbieżny SHA lub sekrety inline blokują publikację. Zmiany env zapisuje się lokalnie przed pushem i przy odrzuconej publikacji przywraca; rollback zmian wyłącznie env używa osobnego webhooka redeploy. Rollback Git cofa automatycznie tylko commity manifestu zmieniające pojedynczy plik; pozostałe wymagają ręcznego przeglądu.

Właściciel potwierdził konfigurację konta Arcane przez Keycloak dla pacekm90@gmail.com; tej konfiguracji nie weryfikowano niezależnie w tej sesji. Wcześniejsze lokalne konto pacekm90 było tymczasowe; nie dokumentować hasła. Callback OIDC Arcane: https://arcane.mariuszpacek.pl/auth/oidc/callback.

Dockge został zatrzymany (down, bez -v). Jego katalogi compose/appdata oraz 29 starych kopii (łącznie 31 ścieżek) przeniesiono na VM do /srv/appdata/to_delete/20260930; niczego nie usunięto. Wszystkie 20 wpisów harmonogramu zapisano i porównano przez API z planem.

Poprawka wydajności podglądów harmonogramów została wdrożona z przetestowanego drzewa roboczego na obrazie homelab-upgrade:git-arcane-20260930-r4; executor pozostaje na homelab-upgrade:git-arcane-20260930-r2. Publikacja kodu w Git uruchamia sprawdzenie i budowę obrazu w CI; wdrożenie obrazu na VM wymaga osobnego uruchomienia update.sh. Weryfikacja: npm run check — 104 pliki, 1240 testów PASS; API harmonogramów po naprawie około 0,34 s zamiast blokowania serwera. Tymczasowy token instalacyjny Gitei unieważniono i sprawdzono HTTP 401.

Wycofanie

cd /opt/homelab/compose/homelab-upgrade && docker compose down     # dane zostają w /srv/appdata/homelab-upgrade/data

Pełne usunięcie: dodatkowo rm -r /opt/homelab/compose/homelab-upgrade /srv/appdata/homelab-upgrade i docker image rm $(docker images -q 'git.mariuszpacek.pl/mariusz.pacek/homelab-upgrade'). Inne projekty nie są dotknięte.

Uwagi

  • Kroki zmieniające (backup, apply, rollback) idą wyłącznie przez executor (DESIGN.md, „Executor”); proxy dla drivera zostaje tylko GET. Reszta boksu (ruch wychodzący drivera, modele) jest nadal otwarta.
  • Przed wystawieniem poza LAN trzeba dodać logowanie (DESIGN.md: „logowanie do przemyślenia”).