A deploy workflow, started only by hand (or through the API) and only from master, pulls the chosen image (release tag, sha or latest) and runs that image's own update.sh against VM103's compose directory through the Docker socket. update.sh now copies the database through the running server first, installs the image's compose.yaml and update.sh with --install, and restores the previous compose file together with the previous image when the new version does not come up. CI also builds release tags v*. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 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 | tylko LAN: middleware ipwhitelist 192.168.0.1/24,10.0.0.0/16; appka nie ma logowania |
| 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:
- 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”); - robi spójną kopię bazy przez działający serwer (
/data/queue.sqlite.before-deploy-<czas>, zostaje 5 najnowszych); bez kopii odmawia (kod 5); - z
--installwgrywacompose.yamliupdate.shz obrazu (poprzedni compose zostaje jakocompose.yaml.previous, diff w logu); docker compose pull(gdy obrazu nie ma: przywraca compose i kończy bez restartu) iup -d;- czeka do 90 s na
healthyserwera i executora oraz na stabilne pozostałe usługi; gdy nowa wersja nie wstaje, wraca do poprzedniego obrazu (lokalny tag:rollback) i poprzedniegocompose.yaml, nie zmienia.envi 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.
Jednorazowa konfiguracja
- Rejestr: działa od razu (Packages w Gitei są domyślnie włączone;
https://git.mariuszpacek.pl/v2/odpowiada 401). - Token (Gitea → Settings → Applications):
write:packagedla CI. Tokenów nie wklejamy do repo ani logów.read:packagedla VM103 nie jest potrzebny, dopóki pakiet jest publiczny (pull anonimowy działa). - Sekret repo
REGISTRY_TOKEN(repo → Settings → Actions → Secrets): tokenwrite:package. - 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 madocker.sock, czyli praktycznie root na VM: rejestruj go tylko dla tego repo. docker loginna VM103: pomijamy, bo pull jest anonimowy. Gdyby pakiet stał się prywatny:docker login git.mariuszpacek.pl -u mariusz.pacektokenemread:package.- Przełączenie z lokalnego obrazu: skopiuj
deploy/compose.yamlideploy/update.shdo/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 udanymverifymodel 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 dopuszczaconfig/agent-exec.json(dokładne komendy, bez wildcardów); reszta trafia do właściciela jako STOPmigration_required. Dziś lista ma tylko komendy Nextclouda: kontrola odbiorcza ze skilla (tylko odczyt:php occ statusz--output=jsoni bez,php occ config:app:get core lastcron,php occ app:list,pidof crondw usłudzecron) oraz to, co po upgrade brakuje w bazie (php occ db:add-missing-indices,db:add-missing-columns,db:add-missing-primary-keys; użytkownikwww-data, usługaapp). Model widzi listę przezhl exec-rulesi 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ć
- 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”.
- Przebieg widać na stronie runu (graf i historia); gdy run czeka na decyzję, jest na Overview i przychodzi push.
- Konfigurację aplikacji (
app_config) zmienia się na jej stronie: włączenie, prógauto, 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.jsonsłuży tylko do zasiania nowych wpisów.
Znane ograniczenia tego etapu:
dockgeigrafanamają w compose sam digest, bez tagu.docker pspokazuje jednak w poluImagelokalny tag wskazujący ten sam obraz (np.louislam/dockge:1.5.0, sprawdzone 2026-09-19), więcstatusmoże przejść dalej zamiast zatrzymać się naversion_unknown. Taki tag to nazwa nadana obrazowi przy pobraniu, nie to, co stoi w compose. Pewną wersję da portimage_version.- Nazwa projektu compose musi być nazwą katalogu (domyślna w compose). Projekt z własnym
name:wcompose.yamlda błąd „no container of service …”. manifest_sha256jestnull: ten tryb nie czytacompose.yaml. Kroki zmieniające (backup, apply) będą potrzebowały dostępu do plików projektów, a to decyzja właściciela.homeassistantstartuje 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ąenabledna stronie aplikacji.- Driver nie czyta plików projektów, ale proxy z
CONTAINERS=1pozwala nainspect, 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)
- 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 - 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 - Timer na Proxmoksie (pliki z
deploy/proxmox/): skrypt co godzinę czyta najnowszą kopię VM103 zvm-storage(pvesh) i zapisuje ją przez guest agenta dohost/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 deploy/compose.yamlideploy/update.shdo/opt/homelab/compose/homelab-upgrade/, potem./update.sh foundations.update.shczeka też na zdrowy executor.- Whitelisty traefika: driver łączy się z adresami aplikacji jako
172.16.0.1(brama sieciproxypo maskaradzie). W jackett i ombi nieaktualny wpis172.18.0.1/16zamieniono 2026-09-19 na172.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, inaczejverifydostanie 403.
Włączenie i przebieg
- Apps → aplikacja → „Real updates” → Save. To jedyne miejsce konfiguracji: executor ma
EXECUTOR_PROJECTS: "*"(wszystkie projekty poza absolutnym STOP i samym homelab-upgrade). Jawna lista wcompose.yamlzawęziłaby to; aplikacja spoza niej kończy się STOP wstatus. 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ę. - Strona aplikacji → „Real run” (albo harmonogram w trybie Real). Wersja w progu
autoprzechodzi sama: kopia,apply_dry_run(diff: tylkoservices.<usł>.image),apply,verify, sprawdzenie przez model. - Bramki (Overview → „Decide”): „Approve the update” — Proceed = reszta runu sama, Skip = nic się nie zmienia; „Update check failed” / „Repair failed” — Roll back przywraca
compose.yamlz 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). - 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)
- Katalog logowania modelu na VM103:
install -d -o 1000 -g 1000 -m 0700 /srv/appdata/homelab-upgrade/claude. - Logowanie
claude(Twoim kontem, raz; dane zostają w tym katalogu):Wygasłe logowanie kończycd /opt/homelab/compose/homelab-upgrade && docker compose exec -it model-claude /opt/claude/bin/claude # w CLI: /login, potem /exitrepairbłędemauth_failed(push); wtedy powtórz ten krok. - Katalog logowania Codeksa na VM103:
install -d -o 1000 -g 1000 -m 0700 /srv/appdata/homelab-upgrade/codex. - Logowanie
codex(Twoim kontem, raz; dane zostają w tym katalogu):Bez tego kroku profile Codeksa kończą się błędemcd /opt/homelab/compose/homelab-upgrade && docker compose run --rm model-codex /opt/codex/bin/codex login --device-authauth_failed. - Home Assistant: w
/opt/homelab/compose/homelab-upgrade/.envdopisz (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.shzmienia w.envtylko linięTAG=. - Harmonogram: każdy workflow ma własny cron (strona aplikacji albo Workflows → Schedule); starego
NIGHTLY_ATjuż nie ma. Staryhomelab-nightly-update.timerna Proxmoksie wyłącz dopiero wtedy, gdy harmonogramy nowego silnika działają:systemctl disable --now homelab-nightly-update.timer. ./update.shpo każdej zmianie.env.
Jak działa
- Nieudany
verify→model.repair: model przezhlogląda i naprawia jedną aplikację, potem kod wykonuje jeszcze razverify; gdy i to nie pomoże, run czeka na bramce (rollback albo zostaw). hl execw repair jest domyślnie wyłączony. Dokładne dopuszczenia (project,service,useralbonull, pełneargv) wpisuje się do wersjonowanegoconfig/agent-exec.json; nie ma wildcardów anish -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_TOKENtylko do logu.
Arcane i repo compose
Repozytorium ssh://git@git.mariuszpacek.pl:2244/mariusz.pacek/homelab-compose.git jest prywatne, na master, zawiera 19 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 18 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 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 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”).