Tutorial: Utwardzanie pliku Docker Compose do pracy bez nadzoru na Raspberry Pi

Management Summary
Docker Compose opisuje sposób wspólnego działania aplikacji na serwerze. Na Raspberry Pi pracującym bez stałego nadzoru ustawienia mogą ograniczać zużycie pamięci, rozrastanie się dzienników i zakres dostępu programów. Pomaga to zapobiegać sytuacji, w której jedna usługa obciąża całe urządzenie. Ustalone wersje ułatwiają kontrolowane aktualizacje, a reguły restartu pomagają przy części przerw. Nie zastępują kopii i odtwarzania; zgłoszenie problemu ze stanem aplikacji nie oznacza automatycznej naprawy.
Spis treści
Plik Docker Compose może ograniczyć typowe ryzyka eksploatacyjne, ale kilka ustawień nie gwarantuje roku pracy bez nadzoru. Restart, raportowanie kondycji, retencja dzienników, limity zasobów i aktualizacje obrazów rozwiązują różne problemy. Kopie zapasowe, monitoring i sprawdzone odtwarzanie pozostają osobnymi wymaganiami.

Punkt wyjścia dla stale działającej aplikacji
Przykład dotyczy Docker Engine na Linuksie z aktualnym Compose. Obraz aplikacji musi obsługiwać UID/GID 1000, główny system plików tylko do odczytu i wskazany endpoint kondycji oraz zawierać curl. UID i GID to numeryczne identyfikatory użytkownika i grupy używane przy prawach do plików. Referencja obrazu pochodzi z APP_IMAGE i musi zawierać zweryfikowany digest. Wartości zasobów są przykładowe, a nie odpowiednie dla każdego Raspberry Pi.
services:
app:
image: "${APP_IMAGE:?verified image reference required}"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-fsS", "--max-time", "4", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 60s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
mem_limit: 512m
cpus: 1.5
pids_limit: 128
read_only: true
tmpfs:
- /tmp:size=64m,mode=1777
security_opt:
- no-new-privileges:true
user: "1000:1000"Wymagane katalogi danych aplikacji potrzebują jawnie zapisywalnych woluminów lub bind mountów. Wolumin to przestrzeń przechowywania zarządzana przez Dockera. Bind mount udostępnia wybrany katalog hosta wewnątrz kontenera. Przykład celowo nie zawiera bazy danych ani trwałych danych aplikacji. Inne uprawnienia, porty, katalogi tymczasowe lub wymagania zasobowe potrzebują odpowiedniej konfiguracji; samo skopiowanie ustawień do dowolnego obrazu nie wystarcza.
Restart i raportowanie kondycji
unless-stopped uruchamia zakończony kontener usługi ciągłej zgodnie z regułą Dockera, zachowując celowe zatrzymanie po restarcie demona. Przy always ręcznie zatrzymany kontener może wrócić po restarcie demona; samo zakończenie polecenia zatrzymania nie wywołuje natychmiastowego restartu. Domyślne no wyłącza automatyczne restarty. Zadania jednorazowe mogą zasadnie wymagać innej reguły.
Reguła restartu nie uruchamia procesu ponownie wyłącznie z powodu stanu unhealthy. W zwykłym Compose healthcheck zapisuje status; odtworzenie działania wymaga zakończenia aplikacji lub osobnego mechanizmu sterowania. Rosnące odstępy między próbami zmniejszają częstotliwość restartów, ale nie eliminują zużycia zasobów ani potrzeby alarmu.
Przykład sprawdza endpoint konkretnej aplikacji wewnątrz kontenera. Brak curl, błędny URL, niedostępna zależność lub wolna odpowiedź mogą dać unhealthy; status nie dowodzi jednoznacznie zawieszenia. Test gotowości może obejmować niezbędne zależności, lecz decyzja o automatycznym restarcie wymaga osobnej oceny, aby awaria wspólnej bazy nie wprowadziła wszystkich usług w pętlę restartów.
start_period pozwala na błędy rozruchu bez natychmiastowego zwiększania licznika niepowodzeń. Udany test w tym okresie kończy tę ochronę dla kolejnych błędów. Czas trwania testu i harmonogram również wpływają na przebieg, więc trzy próby w odstępach 30 sekund nie oznaczają dokładnie 90 sekund na uruchomienie.
Dla zależności od bazy danych warunek service_healthy pod depends_on dla usługi db należy do usługi aplikacji, a rzeczywisty healthcheck do usługi bazy. Warunek steruje startem obsługiwanym przez Compose. Nie jest ciągłym nadzorem zależności i nie jest ponownie wykonywany jako warunek Compose, gdy Docker samodzielnie uruchamia kontenery po restarcie hosta. Aplikacje nadal potrzebują ograniczonych ponowień i odtwarzania połączeń.
Ograniczone dzienniki i zużycie zasobów
Domyślny sterownik json-file nie rotuje dzienników bez konfiguracji. Przykład utrzymuje do trzech rotowanych plików po około 10 MB na kontener. Repliki mnożą ten budżet; pliki aplikacji, woluminy i inne dzienniki hosta pozostają poza limitem. Ani 30 MB, ani określony okres retencji nie pasują do każdej instalacji. Docker zaleca również sterownik local dla wielu zastosowań, ponieważ domyślnie włącza rotację.
Domyślne ustawienia demona są scalane z pozostałą konfiguracją. Po zastosowaniu nowych ustawień istniejące kontenery zachowują poprzednią konfigurację dzienników do ponownego utworzenia. Inną opcją jest journald, ale sam wybór sterownika nie oznacza zapisu wyłącznie w RAM: Storage=volatile przechowuje nowe dane dziennika pod /run/log/journal, bez zachowania po restarcie. Istniejące trwałe pliki nie są automatycznie usuwane, a zdalna retencja wymaga osobnej konfiguracji.
mem_limit, cpus i pids_limit ograniczają różne zasoby. Presja pamięci może zakończyć proces wewnątrz kontenera; cały kontener zostanie zrestartowany dopiero po zakończeniu procesu głównego i zastosowaniu reguły restartu. Limity nie gwarantują braku wpływu na host ani pozostałe usługi. Łączny budżet wymaga zapasu dla systemu operacyjnego, Dockera, pamięci podręcznej i szczytów obciążenia. Tmpfs przechowuje pliki tymczasowe w pamięci i zużywa część jej budżetu. Zatrzymanie kontenera powoduje utratę tych plików.
Nie obowiązuje ogólna zasada, że Raspberry Pi OS ma wyłączoną kontrolę pamięci. Obsługa zależy od jądra, konfiguracji cgroup, wersji systemu i trybu pracy. docker info, efektywna konfiguracja kontenera i kontrolowany test na jednorazowym obciążeniu testowym pozwalają ustalić rzeczywiste zachowanie. Parametry rozruchu wymagają zmiany tylko wtedy, gdy wskazuje na to dokumentacja i diagnoza zainstalowanego systemu. Parametry cmdline.txt pozostają w jednej logicznej linii: podział może ukryć dalsze parametry, ale zwykły końcowy znak nowej linii nie powoduje nieuchronnie braku możliwości startu.
Tożsamość obrazu i uprawnienia
Restart istniejącego kontenera nie pobiera nowego obrazu. Ponowne utworzenie może użyć nowszego obrazu lokalnego lub pobranego, zależnie od polityki pobierania i pamięci podręcznej. Tag może się zmienić; digest identyfikuje stałą zawartość obrazu. Przypięcie wymaga więc świadomego procesu aktualizacji, obejmującego sprawdzone zmiany digestów, zgodność platformy i plan wycofania. Stały obraz nie zamraża danych woluminów, usług zewnętrznych ani schematu bazy.
docker buildx imagetools inspect IMAGE:TAG pokazuje metadane rejestru. Digest indeksu wieloplatformowego wskazuje kilka manifestów platform; digest manifestu konkretnej platformy utrwala jeden wariant. Oba rozwiązania mogą być prawidłowe przy świadomym wyborze. Lokalny wpis RepoDigests nie gwarantuje uniwersalnie digestu indeksu, a lokalnie zbudowany obraz może nie mieć żadnego digestu repozytorium. Potrzebna architektura Pi musi faktycznie występować w indeksie. Niezgodność może zakończyć się błędem wyboru, tworzenia lub wykonania, zależnie od ustawień platformy i emulacji.
user: "1000:1000" wybiera tożsamość; zgodność zależy od zachowania obrazu podczas startu i praw do woluminów. no-new-privileges blokuje uzyskiwanie dodatkowych uprawnień przez mechanizmy takie jak programy setuid, ale nie odbiera już przyznanych praw ani nie zmienia root w zwykłego użytkownika. Główny system plików tylko do odczytu pozostawia jawnie zapisywalne mounty zapisywalnymi. Te mechanizmy wymagają testów aplikacji zamiast obietnicy niezmienionego działania każdej aplikacji.
Kontrola konfiguracji z jawną regułą
docker compose config -q sprawdza i rozwija model Compose bez wypisywania wyniku. Zwykła brakująca zmienna powoduje zazwyczaj ostrzeżenie i podstawienie pustego ciągu; ${VAR:?message} odrzuca natomiast brakujące lub puste wartości obowiązkowe. Rozwinięty wynik może zawierać sekrety i wymaga chronionego zapisu.
Poniższy skrypt jest zapisywany jako check-compose.py. Wąska reguła przykładu wymaga, aby każda wymieniona usługa działała stale, jawnie deklarowała aktywny healthcheck, pokazaną rotację JSON i referencję obrazu SHA-256. Dziedziczone testy obrazu, domyślne dzienniki hosta i inne poprawne polityki nie są automatycznie uwzględniane.
import json
import re
import sys
stack = json.load(sys.stdin)
failed = False
for name, svc in stack.get("services", {}).items():
issues = []
if svc.get("restart") not in ("always", "unless-stopped"):
issues.append("restart policy needs review")
health = svc.get("healthcheck") or {}
test = health.get("test") or []
if health.get("disable") or not test or test[0] == "NONE":
issues.append("explicit active healthcheck missing")
log = svc.get("logging") or {}
opts = log.get("options") or {}
if log.get("driver") != "json-file":
issues.append("logging differs from this example policy")
elif opts.get("max-size") != "10m" or str(opts.get("max-file")) != "3":
issues.append("example log rotation limits missing")
if not re.search(r"@sha256:[0-9a-f]{64}$", svc.get("image", "")):
issues.append("SHA-256 image reference missing")
result = "; ".join(issues) if issues else "example policy matched"
print("{}: {}".format(name, result))
failed = failed or bool(issues)
if not stack.get("services"):
print("no services found", file=sys.stderr)
sys.exit(2)
sys.exit(1 if failed else 0)umask 077
docker compose config --format json > resolved.json && python3 check-compose.py < resolved.json
Kod wyjścia 0 oznacza wyłącznie zgodność rozwiniętego modelu z tą regułą. Nie potwierdza digestu w rejestrze, działania aplikacji, egzekwowania limitów ani bezpieczeństwa. Skrypt zwraca 1 przy problemach i 2 dla pustej listy usług. Poprzedzające polecenie Compose musi zakończyć się poprawnie przed kontrolą wyniku.
Testy odtwarzania i użyteczne sygnały
Kontrolowany test serwisowy obejmuje zakończenie aplikacji, awarię zależności, restart hosta, celowo zatrzymane usługi i odtworzenie z kopii zapasowej. Sam restart kontenera nie sprawdza odzyskiwania danych. Stan kontenera, rosnący licznik restartów, wynik healthcheck, wolne miejsce, presja pamięci i zewnętrzny test dostępności dostarczają uzupełniających informacji. Alarm powinien opisywać utrzymujący się problem zamiast każdej niegroźnej zmiany stanu.
Czy unhealthy oznacza automatyczną naprawę przez Dockera?
Nie. Status kondycji w tym układzie Compose jest informacją diagnostyczną. Nieudany test i przyczyna wymagają zbadania; automatyczne przywrócenie działania potrzebuje jawnej strategii.
Czy przypięte obrazy wykluczają automatyczne aktualizacje?
Nie. Narzędzie może proponować lub stosować sprawdzoną zmianę digestu. Samo ponowne pobieranie tego samego digestu nie wybiera nowej wersji, a sposób raportowania sukcesu zależy od narzędzia.
Dlaczego utwardzanie może uniemożliwić start?
Skrypt wejściowy może potrzebować zapisywalnych ścieżek lub początkowej korekty praw. Rozwiązanie wynika z udokumentowanego użytkownika procesu i wymaganych mountów. Dowolna zmiana właścicieli plików na hoście nie jest uniwersalną naprawą.
Źródła
- Docker: automatyczny start kontenerów
- Docker: ograniczenia zasobów
- Docker Compose: kolejność uruchamiania i zatrzymywania
- Docker Compose: podstawianie zmiennych
- Docker: sterownik logów w plikach JSON
- Docker: konfiguracja sterowników logowania
- Dokumentacja Dockerfile: HEALTHCHECK
- Docker Buildx: imagetools inspect
- Docker Compose: dokumentacja usług
- Docker Compose: polecenie config
- systemd: journald.conf i przechowywanie
- Raspberry Pi: konfiguracja parametrów startowych jądra
- Docker: opcje bezpieczeństwa uruchamiania kontenerów


