Uruchamianie Docker Compose jako usługa Linuxa za pomocą systemd
Docker Compose uruchamiany przy starcie systemu, zarządzany przez systemd.
Skrypt Docker Compose na serwerze Linux powinien uruchamiać się przy starcie systemu, zatrzymywać się poprawnie przy wyłączaniu oraz przetrwać ponowne uruchomienia bez interwencji człowieka.
Docker Compose nie jest Kubernetes, a dla obciążeń, na które celuje ten przewodnik, jest to w porządku. Dla wielu rzeczywistych systemów projekt Compose na pojedynczym hoście Linux stanowi odpowiednią ilość infrastruktury — jest prosty, czytelny, łatwy do kopii zapasowych oraz wystarczający dla wewnętrznych narzędzi, projektów pobocznych, usług self-hosted, środowisk stagingowych, małych aplikacji produkcyjnych oraz infrastruktury deweloperskiej.

Brakującym elementem jest zazwyczaj zarządzanie usługami. Uruchamianie tego ręcznie nie wystarczy:
docker compose up -d
Pojedyncze polecenie uruchamia stos, ale nie dokumentuje, jak stos powinien startować przy bootowaniu, zatrzymywać się podczas wyłączania, przeładowywać się po zmianach, zapisywać logi, odzyskiwać się po awariach czy bezpiecznie aktualizować. Tutaj z pomocą przychodzi systemd.
Ten przewodnik przeprowadza przez uruchamianie projektu Docker Compose jako usługi Linux za pomocą systemd — pliki jednostek, kolejność startową, aktualizacje, logi oraz kopie zapasowe. Podział odpowiedzialności jest celowy: Docker uruchamia kontenery, Compose definiuje stos, a systemd uruchamia i zatrzymuje projekt na hoście. Jest to część Narzędzia Deweloperskie - Przewodnik po Procesach Deweloperskich.
Kiedy Docker Compose jako Usługa Ma Sens
Uruchamianie Compose pod systemd ma sens, gdy posiadasz:
- Pojedynczy serwer Linux
- Małą aplikację self-hosted
- Stos proxy odwrotnego
- Stos monitoringu
- Lokalną platformę deweloperską
- Narzędzie wewnętrzne
- Środowisko stagingowe
- Prostą usługę produkcyjną z znanymi limitami
Przykłady:
- Nginx Proxy Manager
- Traefik
- Gitea
- Grafana i Prometheus
- PostgreSQL oraz mała aplikacja webowa
- Uptime Kuma
- Usługi pomocnicze Home Assistant
- Prywatny rejestr obrazów
- Wewnętrzne API, worker oraz Redis
Compose jest dobrym wyborem, gdy model operacyjny jest nadal zrozumiały dla jednej osoby przeglądającej jeden katalog.
Kiedy Docker Compose Nie Wystarczy
Należy użyć czegoś innego, gdy potrzebujesz:
- Harmonogramowania na wielu węzłach
- Automatycznego ponownego harmonogramowania między hostami
- Odkrywania usług na poziomie klastra
- Poziomego autoskalowania
- Wdrożeń rollingowych na wielu maszynach
- Precyzyjnej tożsamości obciążeń
- Skomplikowanej polityki sieciowej
- Operacji platformowych dla wielu dużych zespołów
W tym momencie Kubernetes, Nomad, Swarm lub zarządzana platforma mogą być lepszym wyborem.
Moje praktyczne zasady to: unikanie używania Kubernetes tylko po to, aby ominąć naukę systemd, oraz unikanie używania Compose, gdy obciążenie wyraźnie wymaga orkiestracji między wieloma hostami.
Podstawowa Architektura
Czysta konfiguracja oddziela pliki projektu, jednostkę systemd oraz dane trwałego magazynu na hoście. Projekt Compose znajduje się pod ścieżką /opt/myapp/ z plikami compose.yaml, .env, data/, backups/ oraz opcjonalnymi skryptami, takimi jak scripts/update.sh. Plik jednostki systemd znajduje się w /etc/systemd/system/myapp.service.
Każda warstwa ma jasno zdefiniowane zadanie: Docker uruchamia kontenery, Compose definiuje stos aplikacji, systemd uruchamia i zatrzymuje projekt Compose przy starcie i wyłączaniu, system plików hosta przechowuje trwałe dane, kopie zapasowe pozostają jawne, a aktualizacje przechodzą przez skryptowane, możliwe do weryfikacji kroki. Ten układ jest celowo nudny, ponieważ nudna infrastruktura jest łatwiejsza do naprawy, gdy coś się zepsuje o 2 rano.
Przygotowanie Katalogu Projektu Compose
Utwórz katalog pod ścieżką /opt:
sudo mkdir -p /opt/myapp
sudo chown -R "$USER":"$USER" /opt/myapp
cd /opt/myapp
Utwórz plik Compose:
nano compose.yaml
Przykład:
services:
web:
image: nginx:stable
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
healthcheck:
test: ["CMD-SHELL", "nginx -t || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes: {}
Utwórz katalog treści:
mkdir -p html
echo "Hello from Docker Compose" > html/index.html
Najpierw przetestuj ręcznie:
docker compose up -d
docker compose ps
docker compose logs --tail=50
Następnie zatrzymaj go przed przekazaniem cyklu życia systemd:
docker compose down
Nie twórz usługi systemd, dopóki projekt Compose nie będzie działać ręcznie. Podczas testowania trzymaj pod ręką Cheat-sheet Docker Compose dla komend ps, logs, pull oraz struktury projektu.
Użyj Nowoczesnej Komendy docker compose
Docker Engine oraz wtyczka Compose muszą być zainstalowane przed napisaniem pliku jednostki. Na Ubuntu, Instalacja Dockera na Ubuntu przeprowadza przez APT, Snap, tryb bez uprawnień root oraz bezpieczeństwo po instalacji, abyś miał działającą komendę docker compose.
Używaj tego:
docker compose version
Nie tego:
docker-compose version
Stary binarny plik docker-compose nadal istnieje na wielu maszynach, ale nowoczesny Docker używa Compose jako wtyczki do Dockera CLI.
W plikach usług oraz skryptach preferuj:
/usr/bin/docker compose
Możesz znaleźć ścieżkę do Dockera za pomocą:
command -v docker
Zazwyczaj jest to:
/usr/bin/docker
Tworzenie Usługi systemd dla Docker Compose
Jeśli pliki jednostek są Ci nieznane, Uruchomienie Dowolnego Wykonywalnego Pliku jako Usługi w Linux wyjaśnia Type, ExecStart, systemctl oraz ogólny przepływ pracy systemd. Ta sekcja stosuje te wzorce specyficznie do stosu Compose.
Utwórz plik usługi:
sudo nano /etc/systemd/system/myapp.service
Użyj tej jednostki:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Przeładuj systemd:
sudo systemctl daemon-reload
Uruchom usługę:
sudo systemctl start myapp.service
Włącz ją przy starcie:
sudo systemctl enable myapp.service
Sprawdź status:
systemctl status myapp.service
Sprawdź kontenery:
cd /opt/myapp
docker compose ps
Dlaczego Type=oneshot i RemainAfterExit=yes?
To jest ta część, którą wiele przewodników robi subtelnie błędnie.
docker compose up -d uruchamia kontenery w trybie odłączonym i kończy swoje działanie, więc nie ma długotrwałego procesu Compose w pierwszym planie, którego systemd miałby nadzorować. Jednostka systemd nie powinna udawać, że docker compose up -d jest długotrwałym demonem.
Użyj:
Type=oneshot
RemainAfterExit=yes
To informuje systemd:
- Uruchom komendę startową.
- Traktuj jednostkę jako aktywną po pomyślnym zakończeniu komendy.
- Uruchom
ExecStop, gdy usługa zostanie zatrzymana.
To pasuje do rzeczywistego zachowania odłączonego Compose, dlatego Type=oneshot z RemainAfterExit=yes jest prawidłowym domyślnym wyborem dla większości stosów.
Dlaczego Nie Type=simple?
Z Type=simple, systemd oczekuje, że proces ExecStart będzie kontynuował działanie, ale docker compose up -d kończy swoje działanie po uruchomieniu kontenerów. Może to sprawić, że systemd uzna, że usługa się zakończyła, a następnie wywoła logikę zatrzymania lub oznaczy jednostkę jako nieaktywną w zależności od konfiguracji.
Jeśli chcesz Type=simple, zazwyczaj uruchomiłbyś Compose w pierwszym planie:
ExecStart=/usr/bin/docker compose up
To może działać, ale zazwyczaj nie preferuję tego dla stosów Compose na serwerach. Odłączone kontenery wraz z jawnym ExecStop są łatwiejsze w obsłudze.
Jednostka Przyjaźniejsza do Produkcji
Dla prawdziwego serwera preferuję nieco bardziej rygorystyczną jednostkę:
[Unit]
Description=MyApp Docker Compose stack
Documentation=https://example.com/docs/myapp
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/.env.systemd
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Ważne szczegóły:
WorkingDirectorywskazuje na projekt Compose.ExecStartPrewaliduje konfigurację Compose.ExecReloadodtwarza zmienione usługi.ExecStopzatrzymuje i usuwa kontenery projektu Compose oraz domyślną sieć.EnvironmentFile=-...oznacza, że plik jest opcjonalny.
Utwórz opcjonalny plik środowiska systemd:
nano /opt/myapp/.env.systemd
Przykład:
COMPOSE_PROJECT_NAME=myapp
Następnie przeładuj systemd:
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
Compose .env vs systemd EnvironmentFile
Compose i systemd mają własne mechanizmy środowiskowe, a mieszanie ich powoduje mylące błędy “zmienna nie ustawiona” przy starcie.
Compose automatycznie odczytuje plik .env w katalogu projektu w celu podstawienia zmiennych w pliku Compose.
Przykład .env:
APP_TAG=1.2.3
WEB_PORT=8080
Przykład compose.yaml:
services:
web:
image: nginx:${APP_TAG}
ports:
- "${WEB_PORT}:80"
EnvironmentFile systemd ustawia zmienne środowiskowe dla samej komendy docker compose.
Przykład:
EnvironmentFile=-/opt/myapp/.env.systemd
Dla wielu projektów potrzebujesz tylko Compose .env.
Użyj pliku środowiska systemd, gdy chcesz zdefiniować takie rzeczy jak:
COMPOSE_PROJECT_NAME=myapp
COMPOSE_FILE=compose.yaml
DOCKER_HOST=unix:///var/run/docker.sock
Nie używaj żadnego z tych plików jako swobodnej skarbca sekretów. Jeśli sekrety są ważne, użyj Docker secrets, zewnętrznego menedżera sekretów, zaszyfrowanych plików lub co najmniej rygorystycznych uprawnień.
Ustaw rygorystyczne uprawnienia:
chmod 600 /opt/myapp/.env
chmod 600 /opt/myapp/.env.systemd
Polityki Restartu: Docker vs systemd
Istnieją dwie warstwy restartu — polityka restartu kontenera w Compose oraz polityka restartu usługi systemd — i nie powinny być one mieszane oślepnie.
Dla długotrwałych kontenerów ustaw polityki restartu w Compose:
services:
web:
image: nginx:stable
restart: unless-stopped
Najczęstsze wartości restartu:
| Polityka | Znaczenie |
|---|---|
| no | Nie restartuj automatycznie |
| always | Restartuj po wyjściu i restarcie demona |
| on-failure | Restartuj tylko po awarii |
| unless-stopped | Restartuj, chyba że zatrzymano ręcznie |
Dla większości trwałych usług preferuję:
restart: unless-stopped
Jest to przewidywalne i szanuje intencjonalne ręczne zatrzymania.
Sama jednostka systemd zazwyczaj nie powinna się wielokrotnie restartować, ponieważ docker compose up -d nie jest działającym obciążeniem. Kontenery są obciążeniem.
Dlatego unikaj tego, chyba że masz konkretny powód:
Restart=always
W większości jednostek Compose-as-service pozwól Dockerowi obsługiwać restarty kontenerów.
Testy Zdrowia (Health Checks)
Polityki restartu restartują kontenery, gdy procesy kończą działanie. Nie naprawiają magicznie każdej nietypowej aplikacji.
Dodaj testy zdrowia tam, gdzie są przydatne:
services:
app:
image: example/app:latest
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Sprawdź zdrowie:
docker compose ps
Zbadaj kontener:
docker inspect container-name
Testy zdrowia są szczególnie przydatne dla:
- Aplikacji webowych
- Proxy odwrotnych
- Baz danych
- Kolejek
- Wewnętrznych API
- Workerów z punktem końcowym zdrowia
Są mniej przydatne, gdy sprawdzają tylko, czy proces istnieje, ponieważ proces, który żyje, ale jest zawieszony, nadal wygląda na zdrowy. Zły test zdrowia to tylko kolejne kłamstwo w YAML.
Kolejność Startu i depends_on
Compose może definiować zależności:
services:
app:
image: example/app:latest
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
To może pomóc w kolejności startu, ale nie ufaj temu nadmiernie. Aplikacje powinny nadal obsługiwać powtórzenia — bazy danych się restartują, sieci się urywają, DNS potrzebuje czasu, a odporna aplikacja powtarza połączenia zamiast zakładać idealną kolejność startową.
Logi: journalctl i docker compose logs
Dwa widoki logów pokrywają większość debugowania: systemd przechwytuje cykl życia samej jednostki, podczas gdy Compose przechwytuje wyjście aplikacji z działających kontenerów.
Logi usługi systemd:
journalctl -u myapp.service -n 100 --no-pager
Śledź logi systemd:
journalctl -u myapp.service -f
Logi usługi Compose:
cd /opt/myapp
docker compose logs --tail=100
docker compose logs -f
docker compose logs -f web
Dla większości debugowania aplikacji docker compose logs jest bardziej przydatne; dla debugowania cyklu życia — błędy startu, awarie jednostek, błędy uprawnień — journalctl jest bardziej przydatne. Jeśli systemctl start myapp się nie powiedzie, sprawdź najpierw journalctl. Jeśli stos się uruchomi, ale aplikacja jest uszkodzona, sprawdź docker compose logs.
Rotacja Logów
Logi Dockera mogą rosnąć w nieskończoność, jeśli ich nie skonfigurujesz.
Dla małych serwerów skonfiguruj rotację logów Dockera w /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Restartuj Dockera:
sudo systemctl restart docker
Następnie restartuj stos Compose:
sudo systemctl restart myapp.service
Dotyczy to nowo utworzonych kontenerów. Odtwórz kontenery, jeśli to konieczne:
cd /opt/myapp
docker compose up -d --force-recreate
Rotacja logów nie jest glamorous, ale to jeden z najłatwiejszych sposobów zapobiegania awarii z powodu pełnego dysku na małym serwerze.
Aktualizacja Usługi Compose
Prosty ręczny przepływ aktualizacji:
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
Jeśli zarządzane przez systemd, możesz użyć:
sudo systemctl reload myapp.service
Jeśli Twoja jednostka ma:
ExecReload=/usr/bin/docker compose up -d --remove-orphans
Ale pamiętaj: ExecReload nie pobiera obrazów, chyba że dołączysz ten krok.
Dla jawnych aktualizacji utwórz skrypt.
mkdir -p /opt/myapp/scripts
nano /opt/myapp/scripts/update.sh
Skrypt:
#!/usr/bin/env bash
set -euo pipefail
cd /opt/myapp
docker compose config --quiet
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
docker compose ps
Spraw go wykonywalny:
chmod +x /opt/myapp/scripts/update.sh
Uruchom go:
/opt/myapp/scripts/update.sh
Następnie jednostka usługi może pozostać skupiona na cyklu życia, podczas gdy skrypt aktualizacji obsługuje wdrożenie.
Bezpieczniejszy Skrypt Aktualizacji z Hakiem Kopii Zapasowej
Dla usług z stanem, aktualizuj dopiero po kopii zapasowej.
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp/backups"
cd "$APP_DIR"
mkdir -p "$BACKUP_DIR"
echo "Walidacja pliku compose"
docker compose config --quiet
echo "Uruchamianie haki kopii zapasowej"
if [ -x "$APP_DIR/scripts/backup.sh" ]; then
"$APP_DIR/scripts/backup.sh"
else
echo "Nie znaleziono haki kopii zapasowej"
fi
echo "Pobieranie obrazów"
docker compose pull
echo "Odtwarzanie usług"
docker compose up -d --remove-orphans
echo "Usuwanie nieużywanych obrazów"
docker image prune -f
echo "Obecny status"
docker compose ps
To nadal jest proste, ale teraz koduje nawyk operacyjny: kopia zapasowa przed zmianą.
Zatrzymywanie Usługi
Zatrzymaj stos:
sudo systemctl stop myapp.service
To uruchamia:
docker compose down
Domyślnie docker compose down usuwa:
- Kontenery dla usług w pliku Compose
- Sieci zdefiniowane przez plik Compose
- Domyślną sieć
Nie usuwa nazwanych wolumenów, chyba że o to poprosisz.
Nie używaj swobodnie:
docker compose down -v
To usuwa nazwane wolumeny zadeklarowane w pliku Compose oraz anonimowe wolumeny podłączone do kontenerów. Dla baz danych i aplikacji z stanem może to oznaczać usunięcie prawdziwych danych.
Używaj down -v tylko wtedy, gdy masz na myśli “zniszcz to środowisko”.
Restartowanie Usługi
Restartuj jednostkę systemd:
sudo systemctl restart myapp.service
To uruchamia komendę stop, a następnie komendę start.
Dla samego restartu kontenerów bez ich odtwarzania:
cd /opt/myapp
docker compose restart
Wažne rozróżnienie:
docker compose restartrestartuje istniejące kontenery.docker compose up -dstosuje zmiany konfiguracji lub obrazów, odtwarzając kontenery, gdy to konieczne.
Jeśli zmieniłeś compose.yaml, użyj:
docker compose up -d
Nie tylko:
docker compose restart
Obsługa Kontenerów Siotków (Orphan Containers)
Jeśli zmienisz nazwę lub usuniesz usługę w compose.yaml, stare kontenery mogą pozostać jako siotki.
Użyj:
docker compose up -d --remove-orphans
Dlatego przykłady usług systemd w tym przewodniku używają:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
To utrzymuje stos bliżej bieżącego pliku Compose.
Kopie Zapasowe
Kopie zapasowe zależą od obciążenia, ale zasady są stabilne.
Dla montowań bind:
/opt/myapp/data/
Zrób kopię tego katalogu.
Dla nazwanych wolumenów:
docker volume ls
Zbadaj wolumin:
docker volume inspect volume-name
Dla baz danych, kopie systemu plików nie są zawsze wystarczające. Użyj kopii zapasowych świadomych aplikacji:
Przykład PostgreSQL:
docker compose exec -T db pg_dump -U postgres appdb > backups/appdb.sql
Przykład MariaDB:
docker compose exec -T db mariadb-dump -u root -p appdb > backups/appdb.sql
Przykład Redis:
docker compose exec redis redis-cli BGSAVE
Stos Compose bez planu kopii zapasowych nie jest usługą — to tymperymentalny eksperyment, który przypadkiem ma czas uptime.
Podstawy Bezpieczeństwa
Dla małej usługi Compose na Linux, zacznij od tej podstawy:
- Trzymaj projekt Compose pod
/opt/appname. - Używaj jawnych tagów obrazów, nie tylko
latest, gdy stabilność ma znaczenie. - Używaj montowań bind lub nazwanych wolumenów świadomie.
- Nie eksponuj portów, których nie potrzebujesz.
- Umieść usługi publiczne za proxy odwrotnym.
- Używaj HTTPS na krawędzi.
- Trzymaj sekrety z dala od Gita.
- Ogranicz uprawnienia
.env. - Unikaj kontenerów przywilejowych, chyba że są naprawdę wymagane.
- Unikaj montowania gniazda Dockera do kontenerów.
- Trzymaj Dockera i obrazy zaktualizowane.
- Testuj zachowanie zapory ogniowej z innej maszyny.
Niebezpieczny wzorzec:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
To daje kontenerowi kontrolę nad Dockerem. W praktyce może to stać się kontrolą na poziomie hosta. Używaj tego tylko wtedy, gdy rozumiesz ryzyko.
Limity Zasobów
Na małych serwerach jeden zły kontener może pochłonąć hosta.
Compose obsługuje ustawienia związane z zasobami, ale zachowanie może zależeć od wersji Dockera Engine i Compose. Dla prostej ochrony zacznij od limitów na poziomie aplikacji i limitów logowania Dockera.
Dla niektórych obciążeń możesz dodać limity pamięci:
services:
app:
image: example/app:stable
restart: unless-stopped
mem_limit: 512m
Skonfiguruj również liczbę workerów na poziomie aplikacji, limity kolejek oraz rozmiary cache. Limity kontenerów są przydatne, ale nie zastępują zrozumienia aplikacji.
Przykład: Realistyczna Usługa Compose
Katalog:
/opt/whoami/
compose.yaml
.env
Plik Compose:
services:
whoami:
image: traefik/whoami:v1.10
restart: unless-stopped
ports:
- "${WHOAMI_PORT}:80"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost || exit 1"]
interval: 30s
timeout: 5s
retries: 3
Plik .env:
WHOAMI_PORT=8080
COMPOSE_PROJECT_NAME=whoami
Jednostka systemd:
[Unit]
Description=Whoami Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/whoami
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Zainstaluj ją:
sudo systemctl daemon-reload
sudo systemctl enable --now whoami.service
Przetestuj:
curl http://localhost:8080
Sprawdź status:
systemctl status whoami.service
cd /opt/whoami
docker compose ps
Rozwiązywanie Problemów
Usługa Startuje, Ale Kontenery Nie Działają
Sprawdź systemd:
journalctl -u myapp.service -n 100 --no-pager
Zwaliduj Compose:
cd /opt/myapp
docker compose config
Sprawdź Dockera:
systemctl status docker
docker info
WorkingDirectory Jest Niewłaściwe
Jeśli systemd nie może znaleźć Twojego pliku Compose, potwierdź:
WorkingDirectory=/opt/myapp
Następnie sprawdź:
ls -la /opt/myapp
ls -la /opt/myapp/compose.yaml
Usługa działa z WorkingDirectory, nie z Twojego bieżącego katalogu powłoki.
Docker Permission Denied
Jeśli jednostka działa jako root, normalnie ma dostęp do Dockera.
Jeśli ustawisz User=someuser, ten użytkownik musi mieć dostęp do Dockera. Zazwyczaj oznacza to przynależność do grupy docker lub konfigurację Dockera bez uprawnień root.
Sprawdź:
groups someuser
Dodaj użytkownika, jeśli to odpowiednie:
sudo usermod -aG docker someuser
Bądź ostrożny. Grupa Docker jest efektywnie przywilejowana.
Komenda Compose Nie Znaleziona
Znajdź Dockera:
command -v docker
Użyj pełnej ścieżki w jednostce:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Jeśli wtyczka Compose jest brakująca:
docker compose version
Zainstaluj ją używając swojego źródła pakietów Dockera.
Brakujące Zmienne Środowiskowe
Sprawdź konfigurację Compose tak, jakby widział ją systemd:
cd /opt/myapp
docker compose config
Jeśli systemd potrzebuje dodatkowych zmiennych środowiskowych, użyj:
EnvironmentFile=-/opt/myapp/.env.systemd
Jeśli Compose potrzebuje zmiennych do podstawienia, użyj:
/opt/myapp/.env
Są one powiązane, ale nie identyczne.
Kontenery Nie Startują Po Ponownym Uruchomieniu
Sprawdź, czy usługa systemd jest włączona:
systemctl is-enabled myapp.service
Włącz ją:
sudo systemctl enable myapp.service
Sprawdź Dockera:
systemctl is-enabled docker
systemctl status docker
Sprawdź logi bootowania:
journalctl -u myapp.service -b --no-pager
Aplikacja Startuje Przed Gotowością Bazy Danych
Dodaj test zdrowia bazy danych oraz depends_on z service_healthy.
Napraw również aplikację. Powinna ona powtarzać połączenia z bazą danych. Kolejność startu infrastruktury jest pomocna, ale logika powtórzeń aplikacji jest lepsza.
Dysk Pełny Logami Dockera
Sprawdź zużycie dysku przez Dockera:
docker system df
Sprawdź duże logi kontenerów:
sudo du -h /var/lib/docker/containers | sort -h | tail
Skonfiguruj rotację logów Dockera w /etc/docker/daemon.json.
Następnie odtwórz kontenery.
Częste Błędy
Błąd 1: Uruchamianie docker compose up w rc.local
Uruchamianie docker compose up z rc.local lub skryptu logowania działa, dopóki nie przestanie — użyj odpowiedniej jednostki systemd zamiast tego.
Błąd 2: Używanie Restart=always w systemd oraz restart: always w Compose
Zazwyczaj potrzebujesz tylko polityk restartu kontenera w Compose. Unikaj dwóch nadzorców walczących ze sobą.
Błąd 3: Zapominanie o –remove-orphans
Zmiany nazw i usunięcia usług mogą zostawić stare kontenery. Użyj:
docker compose up -d --remove-orphans
Błąd 4: Używanie docker compose restart Po Zmianach Konfiguracji
restart restartuje kontenery. Nie stosuje wszystkich zmian konfiguracji.
Użyj:
docker compose up -d
Błąd 5: Uruchamianie down -v Bez Myślenia
To może usunąć wolumeny. Dla usług z stanem może to oznaczać usunięcie danych.
Błąd 6: Brak Kopii Zapasowej Przed Pull
Nowe obrazy mogą się zepsuć. Bazy danych mogą się migrować. Tagi mogą się przesuwać. Najpierw zrób kopię zapasową.
Błąd 7: Publikowanie Każdego Portu
Publikuj tylko to, co host musi eksponować. Ruch wewnętrzny między usługami może pozostać w sieci Compose.
Ostatecznie Rekomendowany Wzorzec
Dla większości usług Linux na pojedynczym hoście użyj tego wzorca:
Plik Compose:
services:
app:
image: example/app:stable
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .env
Jednostka systemd:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Włącz ją:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
Obsługuj ją:
sudo systemctl status myapp.service
sudo systemctl restart myapp.service
journalctl -u myapp.service -f
cd /opt/myapp && docker compose logs -f
Ten wzorzec nie jest skomplikowany, i to jest właśnie sedno sprawy. Docker Compose jest doskonały dla małych, zrozumiałych systemów, systemd jest doskonały w uruchamianiu i zatrzymywaniu usług hosta, a razem dają Ci niezawodny model wdrożenia na pojedynczym serwerze, nie udając, że każdy projekt potrzebuje klastra. Dla poleceń na poziomie kontenera poza Composem — obrazy, wolumeny, sieci oraz czyszczenie — zobacz Cheat-sheet Dockera.