Automatyczne testowanie i aktualizowanie aplikacji Docker na Raspberry Pi
Część 3 z 7 serii Homelab na Raspberry Pi

Management Summary
CI/CD to proces automatycznego sprawdzania zmian w oprogramowaniu i dostarczania nowych wersji. Na Raspberry Pi obsługującym lokalne usługi ogranicza powtarzalną pracę przy aktualizacjach i ułatwia ustalenie, jaka wersja działa. Artykuł opisuje kontrolowaną drogę od zgłoszenia zmiany do uruchomionej aplikacji. Jasna odpowiedzialność i ograniczone uprawnienia pomagają uniknąć sprzecznych aktualizacji. Nadal potrzebne są kopie i możliwość odtworzenia, ponieważ starszy program nie cofa automatycznie zmian zapisanych danych.
Spis treści
Lokalny potok CI/CD może sprawdzać zmiany i wdrażać usługi Docker Compose na Raspberry Pi bez osobnej sesji SSH przy każdej aktualizacji. Git przechowuje definicję wdrożenia, a lokalny proces wykonawczy stosuje zatwierdzoną wersję. Nadal potrzebne są kopie zapasowe, monitoring i procedura odtwarzania.
1. Powtarzalna wersja wdrożenia
CI oznacza automatyczne sprawdzanie integracji, a CD dostarczanie lub wdrażanie zmian. Webhook jedynie uruchamia zadanie. W podejściu GitOps repozytorium opisuje stan docelowy, a proces automatyczny uzgadnia działające usługi z tym opisem.
- Konfiguracja: Compose definiuje usługi, sieci i montowanie wolumenów. Zawartość wolumenów i rekordy bazy danych nie znajdują się w pliku YAML. Sekrety wymagają przechowywania poza zwykłym repozytorium Git.
- Identyfikacja wersji: Konkretny commit i digesty obrazów określają zatwierdzony stan. Digest to odcisk obliczany z zawartości, identyfikujący konkretną wersję obrazu. Zmienny tag, np.
:latest, nie wystarcza do odtworzenia wdrożenia. - Odtwarzanie: Historia Git ułatwia śledzenie zmian, ale nie jest z definicji niezmienna. Starsza konfiguracja nie cofa migracji bazy ani usunięcia plików. Potrzebne są osobne kopie zapasowe i sprawdzona procedura odzyskiwania.

2. Weryfikacja webhooka i wykonanie zadania
Usługa nasłuchująca, np. adnanh/webhook, odbiera zdarzenie z repozytorium. Dla GitHub weryfikacja X-Hub-Signature-256 wykorzystuje niezmienioną treść żądania, sekret webhooka i porównanie w stałym czasie, którego długość nie zdradza, jaka część oczekiwanego podpisu już pasuje. HMAC potwierdza podpisaną treść; osobno trzeba sprawdzić dozwolone zdarzenie, repozytorium i gałąź.
- Odrzucić niepoprawne i niedozwolone żądania. Zapisywać identyfikatory dostarczenia, aby wykrywać duplikaty i zapobiegać ponownemu wykonaniu.
- Umieścić zatwierdzone zadanie w kolejce bez dostępu do Dockera. Dowolne pola żądania nie mogą stawać się poleceniami powłoki.
- Osobny proces wykonawczy pobiera zatwierdzony commit do kontrolowanego katalogu wydania. Blokada zapobiega równoczesnym wdrożeniom tego samego stosu.
- Sprawdzić pełną konfigurację Compose, jawnie pobrać lub zbudować obrazy, a następnie uruchomić wydanie.
Samo docker compose up -d --remove-orphans nie tworzy kompletnego potoku. Zmiana obrazu lub konfiguracji powoduje odtworzenie istniejącego kontenera. Nowsza zawartość niezmienionego tagu w rejestrze nie musi zostać pobrana przez to polecenie. Potrzebna jest świadomie ustawiona polityka pobierania lub osobny krok pull. Nazwa projektu i zestaw plików Compose muszą być spójne.
3. Kontrola działania i obsługa błędów
docker compose up --wait --wait-timeout 120 czeka na stan running lub healthy i włącza pracę w tle. Limit 120 sekund jest przykładem. Bez testu zdrowia sprawdzany jest tylko stan uruchomienia usługi.
Docker HEALTHCHECK określa stan po skonfigurowanych odstępach i nieudanych próbach. Sam status unhealthy w zwykłym Docker Compose nie wywołuje restartu ani wycofania wersji. Proces wdrożeniowy wymaga osobnej obsługi błędów, testów funkcji aplikacji i użytecznych logów. Działający proces nie potwierdza poprawnego logowania ani dostępu do bazy.
Lokalne budowanie na ARM może zastąpić kompilację skrośną, jeśli obrazy bazowe i zależności obsługują docelową architekturę. Budowanie obciąża jednak procesor, pamięć i nośnik Raspberry Pi.
4. Oddzielenie dostępu sieciowego od uprawnień
Usługa odbierająca webhooki powinna działać bez uprawnień root i bez dostępu do gniazda Dockera. Grupa docker daje uprawnienia na poziomie roota przy zwykłym demonie działającym jako root. Proxy tylko do odczytu pozwala sprawdzać stan, lecz nie wdrażać zmian kontenerów.
Mały uprzywilejowany proces wykonawczy może przyjmować wyłącznie sprawdzone zadania dla ustalonych repozytoriów i celów. Pliki Compose mogą żądać szerokich uprawnień lub montowania plików hosta, dlatego konfiguracja i kod muszą pochodzić z zaufanego źródła. VLAN zarządzający z regułami zapory ogranicza dostępne ścieżki, ale nie gwarantuje ochrony przed przejętym urządzeniem w dozwolonej sieci.
5. GitHub Actions i ograniczony klucz SSH
Runner to program wykonujący zadania workflow. Runner hostowany przez GitHub może łączyć się z Pi przez SSH w uwierzytelnionej sieci prywatnej lub VPN. Publiczny port SSH nie jest bezwzględnie wymagany. Runner self-hosted pobiera zadania z GitHub. Aktualna dokumentacja wymienia Linux ARM64, ale nie wymienia już ARM32. Przed instalacją potrzebna jest weryfikacja systemu, architektury i zgodności poszczególnych Actions.
Runner potrzebuje wychodzącego HTTPS na porcie 443 do GitHub. Zadania mogą wymagać dodatkowych połączeń z Git, rejestrem obrazów lub aplikacjami. Odbieranie zadań nie wymaga portu przychodzącego. Prywatne repozytorium nie czyni dowolnego kodu workflow bezpiecznym. Niezaufany kod pull requestów nie może otrzymywać sekretów wdrożeniowych ani dostępu do produkcyjnego Dockera.
Odrębny klucz wdrożeniowy może mieć poniższy wpis w authorized_keys. AAAA… jest miejscem na pełny klucz publiczny:
restrict,command="/usr/local/bin/deploy-stack" ssh-ed25519 AAAA… ci-deploy
command= wymusza zapisane polecenie, a restrict wyłącza przekierowania, PTY i ~/.ssh/rc. Skrypt musi odrzucać niedozwolone dane, w tym SSH_ORIGINAL_COMMAND; zależności i konfiguracja nie mogą być modyfikowane przez wywołującego. Skradziony klucz nadal umożliwia wielokrotne wywołanie dozwolonej operacji. Samo stałe polecenie nie stanowi pełnej granicy bezpieczeństwa.
6. Harmonogram aktualizacji obrazów
Pierwotne repozytorium containrrr/watchtower zarchiwizowano 17 grudnia 2025 r. Przed przejściem na fork społecznościowy, np. nickfedor/watchtower, trzeba osobno sprawdzić wersję i zgodność z API Dockera. Sprawdzanie obrazów prowadzi do wymiany kontenerów, ale nie testuje zgodności aplikacji.
Podlinkowana dokumentacja Watchtower v1.14.3 podaje domyślny interwał 86 400 sekund i sześciopolowy WATCHTOWER_SCHEDULE. 0 0 4 * * * oznacza godzinę 4:00. Jawne TZ=Europe/Warsaw określa oczekiwany czas lokalny; udokumentowana strefa domyślna to UTC. Harmonogram i WATCHTOWER_POLL_INTERVAL są alternatywami.
WATCHTOWER_LABEL_ENABLE=true wybiera kontenery z etykietą com.centurylinklabs.watchtower.enable=true. WATCHTOWER_CLEANUP=true usuwa stare obrazy po aktualizacji, ale nie zarządza wszystkimi logami i danymi wolumenów. Może też usunąć lokalny obraz potrzebny do wycofania. Dla każdej usługi powinien działać jeden mechanizm aktualizacji, aby GitOps i Watchtower nie tworzyły niezależnie sprzecznych stanów.
Pytania i odpowiedzi
Jak wycofać nieudane wdrożenie?
Kontrolowane wycofanie przywraca komplet znanego wydania: konfigurację, zgodne pliki dodatkowe i konkretne digesty obrazów. Cofnięcie tylko jednego pliku Compose może utworzyć mieszankę wersji. Zmiana musi również trafić do repozytorium, aby następne wdrożenie nie odtworzyło awarii.
Starszy obraz nie odwraca migracji bazy. Przed wycofaniem potrzebna jest ocena zgodności danych oraz, w razie potrzeby, odtworzenie sprawdzonej kopii. Procedura wymaga testu poza produkcją i uwzględnienia danych powstałych po aktualizacji.
Źródła
- Docker Compose: dokumentacja
- GitHub: dokumentacja runnerów self-hosted
- GitHub: dodawanie runnerów self-hosted
- OpenBSD: sshd(8), format pliku authorized_keys
- Docker: konfiguracja Linuksa po instalacji
- Watchtower (nicholas-fedor): argumenty
- robfig/cron v1.2.0: format wyrażeń Cron
- Docker: odtwarzanie, wolumeny, pobieranie, oczekiwanie i osierocone kontenery
- Docker: stan, odstępy i ponowienia kontroli
- Docker: restart po zakończeniu procesu
- GitHub: HMAC-SHA256 i porównanie w stałym czasie
- GitHub: kontrola zdarzeń, kolejki i identyfikatory dostarczenia
- GitHub: dostęp do prywatnej sieci z hostowanych runnerów
- Pierwotny projekt: archiwizacja 17 grudnia 2025 r.
Homelab na Raspberry Pi
- Uruchamianie Raspberry Pi 4 i 5 z SSD: konfiguracja i odzyskiwanie systemu
- Zasilanie Raspberry Pi podczas awarii prądu: porównanie pięciu rozwiązań UPS
- Automatyczne testowanie i aktualizowanie aplikacji Docker na Raspberry Pi
- Serwer domowy Docker Compose: Traefik, TLS i monitorowanie aktualizacji
- Jellyfin na Raspberry Pi 5: odtwarzanie filmów bez kosztownej konwersji
- Dostęp do sieci domowej przez WireGuard: Raspberry Pi jako brama VPN
- Monitorowanie Raspberry Pi: Prometheus i Grafana


