SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-27

Docker Compose na Ubuntu 24.04: przewodnik konfiguracji

Instalacja Docker Engine i Compose v2 na Ubuntu 24.04. Konfiguracja stosu z Miniflux i PostgreSQL. Rozwiązanie problemu z ufw oraz bezpieczne zarządzanie wolumenami danych.

Co budujesz

Docker Compose stanowi fundament niemal wszystkich rozwiązań opisanych w tym serwisie. Nextcloud, Vaultwarden, n8n, Immich, Rocket.Chat – każdy z tych przewodników rozpoczyna się od utworzenia pliku compose, a niniejsza strona wyjaśnia znaczenie jego zawartości. Zainstalujesz Docker Engine oraz wtyczkę Compose v2 z oficjalnego repozytorium apt firmy Docker na systemie Ubuntu 24.04, a następnie uruchomisz stos składający się z dwóch usług: czytnika RSS Miniflux oraz bazy danych PostgreSQL. Ta para pozwala przećwiczyć wszystkie wzorce wykorzystywane przez większe aplikacje: przypięte wersje obrazów, bazę danych z kontrolą stanu (healthcheck), wolumen nazwany, sekrety w pliku .env oraz port udostępniony wyłącznie na localhost.

Instalacja zajmuje pięć minut. Pozostała część przewodnika omawia kwestie, które mogą sprawiać trudności w przyszłości: grupę docker jako równoważnik uprawnień root, porty publikowane z pominięciem reguł ufw oraz flagę w docker compose down, która usuwa bazę danych bez prośby o potwierdzenie.

Wymagania wstępne: świeża instalacja Ubuntu 24.04 na serwerze KVM VPS, użytkownik z uprawnieniami sudo oraz co najmniej jeden gigabajt pamięci RAM. Istniejąca instalacja Docker również jest dopuszczalna; pierwsza sekcja zawiera informacje o tym, co należy usunąć.

Instalacja z repozytorium Docker, a nie Ubuntu

Przed wykonaniem pierwszej komendy należy uniknąć dwóch błędów. Pakiet docker.io z repozytorium Ubuntu działa, lecz jest przestarzały względem wydań Docker i nie posiada struktury wtyczek, której wymagają inne komponenty. Z kolei samodzielny plik binarny docker-compose, zawierający myślnik w nazwie, to Compose v1: oparty na języku Python, nierozwijany od 2023 roku i będący przyczyną problemów w starszych poradnikach. Obecny standard to docker compose zapisywany ze spacją – wtyczka CLI instalowana z tego samego repozytorium co silnik.

Jeśli którykolwiek z tych elementów znajduje się już w systemie, należy go usunąć, wliczając w to docker-compose-v2, czyli pakiet wtyczki dostarczany przez Ubuntu, aby zapewnić spójność pochodzenia oprogramowania:

sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc

Package 'docker.io' is not installed, so not removed to standardowy wynik na świeżym serwerze VPS. Następnie należy dodać repozytorium Docker i przeprowadzić instalację:

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Zweryfikuj wszystkie trzy warstwy:

docker --version
docker compose version
sudo docker run --rm hello-world

Pierwsze dwie komendy wyświetlą wersje oprogramowania, a Docker Compose version v2.x.x potwierdzi obecność wtyczki, a nie przestarzałego pliku binarnego v1. Uruchomienie hello-world powinno zakończyć się komunikatem Hello from Docker!. Pakiet automatycznie aktywuje usługę przy starcie systemu; systemctl is-enabled docker wyświetli enabled.

Grupa docker to root, podejmuj decyzję świadomie

Obecnie każde polecenie docker wymaga użycia sudo, ponieważ gniazdo demona w /var/run/docker.sock jest własnością użytkownika root oraz grupy docker. Bez przynależności do tej grupy otrzymasz najczęściej wyszukiwany błąd Docker:

permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock

Standardowe rozwiązanie:

sudo usermod -aG docker $USER

Przynależność do grupy jest weryfikowana przy logowaniu, więc błąd będzie nadal występował w bieżącej powłoce. Uruchom newgrp docker dla tej sesji lub wyloguj się i zaloguj ponownie; id powinno wtedy wyświetlić docker na liście grup.

Teraz część szczera, powiedziana wprost: przynależność do grupy docker jest równoznaczna z uprawnieniami root na hoście. Nie "prawie root", nie "podniesione uprawnienia", lecz root. Każdy członek tej grupy może uruchomić docker run --rm -it -v /:/host alpine chroot /host i przejąć kontrolę nad całym systemem plików bez pytania o hasło. Grupa ta istnieje dla wygody, a nie dla izolacji.

Tryb rootless w Docker to realna alternatywa, w której sam demon działa jako użytkownik bez uprawnień. Wiąże się to z kosztami: porty poniżej 1024 wymagają dodatkowej konfiguracji, sieć działa przez warstwę pośredniczącą w przestrzeni użytkownika z mierzalnym narzutem, a niektóre obrazy nie działają poprawnie bez rzeczywistego roota. Na VPS z jednym administratorem, który i tak posiada uprawnienia sudo, zmiana grupy w praktyce niczego nie zmienia i jest to założenie przyjmowane w każdym poradniku tutaj, jednak nigdy nie należy traktować tego dostępu jako czegoś mniej istotnego niż sudo.

Anatomia pliku compose

Każdy stos usług powinien znajdować się w osobnym katalogu. Nazwa katalogu staje się nazwą projektu, która stanowi prefiks dla kontenerów, sieci i wolumenów:

sudo mkdir -p /opt/miniflux && sudo chown $USER /opt/miniflux && cd /opt/miniflux

Utwórz plik compose.yml (jest to współczesna nazwa; docker-compose.yml nadal działa). Pomiń stary klucz version:, jest on przestarzały, a Compose wyświetla ostrzeżenie, jeśli go wykryje.

services:
  miniflux:
    image: miniflux/miniflux:2.2.9
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - DATABASE_URL=postgres://miniflux:${POSTGRES_PASSWORD}@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=miniflux
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux", "-d", "miniflux"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db-data:

Każda linia powyżej to konkretna decyzja. Wprowadzaj je pojedynczo.

Przypinanie wersji obrazów, :latest wraz z pull to niekontrolowana aktualizacja

Używaj postgres:16-alpine, a nie postgres:latest. Tag nie jest zamrożony: :latest za każdym razem po wykonaniu pull wskazuje na obraz, który autor wypchnął jako ostatni. Jeśli połączysz to z nawykiem rutynowej aktualizacji, o którym przeczytasz w docker compose pull && docker compose up -d, to :latest oznacza, że skoki wersji głównych nastąpią w momencie, gdy autor je opublikuje, a nie wtedy, gdy Ty zdecydujesz. W przypadku PostgreSQL nie jest to sytuacja hipotetyczna: nagły skok z 16 na 17 spowoduje, że kontener utknie w pętli restartów z powodu niekompatybilnego katalogu danych, ponieważ główne aktualizacje Postgres wymagają wykonania dump i restore, a nie zwykłego restartu.

Przypnij przynajmniej wersję główną (postgres:16-alpine uwzględnia wydania poprawkowe 16.x), a aplikacje przypinaj do konkretnego wydania, takiego jak miniflux/miniflux:2.2.9. Sprawdź stronę wydań projektu i użyj wersji aktualnej w momencie tworzenia pliku. Aktualizacja stanie się wtedy celową zmianą w jednej linii, widoczną w git diff.

Publikowanie na 127.0.0.1, ponieważ Docker omija ufw

"127.0.0.1:8080:8080" to adres hosta, port hosta i port kontenera. Większość poradników podaje "8080:8080", co jest skrótem od 0.0.0.0:8080:8080: nasłuchiwanie na wszystkich interfejsach, w tym na publicznym.

Oto pułapka, w którą wpada niemal każdy. Docker publikuje port poprzez zapisanie reguły DNAT, która przepisuje docelowy adres IP pakietu na wewnętrzny adres IP kontenera przed filtrowaniem. Pakiet trafia więc ścieżką FORWARD i nigdy nie dociera do INPUT, gdzie znajdują się reguły ufw. sudo ufw deny 8080 zgłasza sukces, ufw status pokazuje, że port jest zablokowany, a usługa mimo to odpowiada całemu Internetowi. Twój firewall nie jest uszkodzony; został zaprojektowany tak, aby być omijanym. Dlaczego Docker omija ufw i jak skutecznie filtrować ruch kontenerów wyjaśnia ten mechanizm oraz poprawkę DOCKER-USER dla portów, które muszą pozostać publiczne.

Nawyk, który eliminuje ten problem: wiąż publikowane porty z 127.0.0.1, chyba że masz konkretny powód, by tego nie robić, i umieść reverse proxy przed wszystkim, co powinno być wystawione na świat. To dokładnie to, co buduje przewodnik po reverse proxy Traefik jako kolejny krok po tej stronie: jeden kontener, który zajmuje porty 80 i 443 i kieruje ruch do reszty usług według nazwy hosta, z obsługą TLS. (Przechodzisz ze starszej konfiguracji Traefik v2? Przewodnik migracji z Traefik v2 do v3 omawia zmiany nazw i reguł.)

Po uruchomieniu stosu zweryfikuj powiązanie: sudo ss -tlnp | grep 8080 powinno pokazać 127.0.0.1:8080, a nie 0.0.0.0:8080 lub *:8080.

Wolumeny nazwane a bind mounts

db-data:/var/lib/postgresql/data to wolumen nazwany: Docker tworzy i zarządza katalogiem w /var/lib/docker/volumes/ i montuje go w kontenerze. Alternatywą jest bind mount, ./data:/var/lib/postgresql/data, który mapuje wybraną przez Ciebie ścieżkę na hoście.

Podział, który sprawdza się w praktyce: wolumeny nazwane dla danych, z którymi pracują tylko kontenery, przede wszystkim bazy danych, ponieważ Docker inicjalizuje wolumen z uprawnieniami oczekiwanymi przez obraz, dzięki czemu prawa dostępu działają poprawnie. Bind mounts dla plików, z którymi pracujesz z poziomu hosta, plików konfiguracyjnych edytowanych edytorem tekstu, bibliotek multimediów synchronizowanych przez rsync – wszystkiego, czego ścieżka powinna być oczywista. Klasycznym błędem bind mount jest własność plików: kontener działa jako UID 999, Twój katalog na hoście należy do UID 1000, a aplikacja kończy działanie przy starcie z błędem permission denied w logach. Wolumeny nazwane sprawiają, że ta klasa błędów znika, kosztem przechowywania danych w ścieżce zarządzanej przez Dockera, co opisano poniżej.

environment i .env, trzymaj sekrety poza git

${POSTGRES_PASSWORD} nie jest odczytywane z Twojej powłoki; Compose interpoluje je z pliku o nazwie .env znajdującego się obok compose.yml. Utwórz go:

cat > .env <<'EOF'
POSTGRES_PASSWORD=change-me-to-something-long
ADMIN_PASSWORD=change-me-too
EOF
chmod 600 .env
echo ".env" >> .gitignore

Wygeneruj rzeczywiste wartości za pomocą openssl rand -hex 24. Celowo używamy formatu hex, a nie base64: to hasło trafia do ciągu połączeniowego DATABASE_URL, a znaki /, + i =, które może wygenerować base64, psują parsowanie URL. Jest to błąd, który objawia się jako problem z uwierzytelnianiem, a nie błąd składni, co kosztuje cały wieczór pracy. Linia .gitignore musi znaleźć się w pliku przed pierwszym commitem: plik compose można bezpiecznie publikować i wersjonować, plik .env nigdy nie powinien trafić do repozytorium, a sekret, który znalazł się w historii git, należy uznać za skompromitowany i zrotować. Jeśli uruchomisz stos z brakującą zmienną, Compose wyświetli głośne ostrzeżenie i kontynuuje pracę z pustym ciągiem znaków, co w przypadku hasła Postgres oznacza niedziałające wdrożenie:

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string.

docker compose config wyświetla w pełni zinterpolowany plik, co jest najszybszym sposobem sprawdzenia, co faktycznie otrzymają kontenery; pamiętaj, że wynik zawiera Twoje sekrety.

depends_on nie czeka na nic, chyba że dodasz healthcheck

Sam depends_on: [db] kontroluje tylko kolejność startu: Compose uruchamia Postgres najpierw, a aplikację chwilę później, podczas gdy Postgres potrzebuje jeszcze kilku sekund na akceptację połączeń. Aplikacja próbuje połączyć się z bazą, nie udaje się to, więc kończy działanie lub ponawia próbę, zależnie od jakości kodu.

Niezawodna wersja to ta użyta w pliku powyżej: usługa db definiuje healthcheck (Postgres dostarcza pg_isready dokładnie w tym celu), a aplikacja deklaruje depends_on z condition: service_healthy. Compose uruchamia bazę danych, odpytuje o stan co 10 sekund i uruchamia Miniflux dopiero, gdy test przejdzie pomyślnie. Jeśli baza danych nigdy nie osiągnie stanu gotowości (złe hasło, uszkodzony wolumen), aplikacja nigdy nie wystartuje, a Compose wskaże, która zależność zawiodła:

dependency failed to start: container miniflux-db-1 is unhealthy

Ten komunikat wskazuje na docker compose logs db, gdzie znajduje się rzeczywisty błąd.

restart: unless-stopped

restart: unless-stopped dla obu usług oznacza, że kontenery wracają po awarii oraz po restarcie VPS, ale pozostają wyłączone, jeśli celowo wykonałeś docker compose stop. Alternatywa always przywraca kontenery nawet po ręcznym zatrzymaniu, co rzadko jest pożądanym zachowaniem. Bez polityki restartu, restart po aktualizacji jądra o 4 rano po cichu wyłączy Twoje usługi, dopóki tego nie zauważysz.

Codzienne operacje

Wszystkie codzienne czynności sprowadzają się do pięciu poleceń, wykonywanych z poziomu katalogu projektu.

docker compose up -d        # create and start; idempotent, recreates only what changed
docker compose ps           # status, ports, and health of this project's containers
docker compose logs -f miniflux   # follow one service's logs; --tail 100 for recent history
docker compose pull && docker compose up -d   # upgrade to the pinned tags
docker compose down         # stop and remove containers and the network

Polecenie up -d można bezpiecznie uruchamiać wielokrotnie; porównuje ono plik z bieżącym stanem systemu i modyfikuje tylko te usługi, których konfiguracja lub obraz uległy zmianie. Para poleceń aktualizujących pobiera obrazy wskazywane przez przypięte tagi: poprawki w ramach postgres:16-alpine, natomiast w przypadku sztywnych wersji nic się nie zmieni, dopóki nie zostanie edytowany plik, co jest zamierzonym działaniem. Stare obrazy gromadzą się po aktualizacjach; miejsce na dysku można odzyskać za pomocą docker image prune -f.

Teraz polecenie destrukcyjne, o którym należy pamiętać: docker compose down jest bezpieczne, ponieważ kontenery i sieć są tymczasowe, a dane znajdują się w wolumenach. docker compose down -v usuwa również nazwane wolumeny. Oznacza to natychmiastową utratę bazy danych, bez prośby o potwierdzenie i możliwości cofnięcia operacji. Flaga -v służy do usuwania eksperymentalnych środowisk; w przypadku stosu zawierającego rzeczywiste dane, należy traktować ją tak samo jak rm -rf. W /var/lib/docker/volumes/ nie istnieje mechanizm kosza.

Aby uzyskać jednorazowy dostęp do powłoki wewnątrz uruchomionego kontenera: docker compose exec db psql -U miniflux otwiera konsolę bazy danych, a docker compose exec miniflux sh zapewnia dostęp do powłoki wewnątrz aplikacji.

Gdzie faktycznie znajdują się dane

Wolumeny nazwane otrzymują prefiks projektu, więc db-data w katalogu o nazwie miniflux staje się miniflux_db-data:

docker volume ls
docker volume inspect miniflux_db-data

Dane wyjściowe inspect zawierają istotny wiersz:

"Mountpoint": "/var/lib/docker/volumes/miniflux_db-data/_data"

Ten katalog to baza danych, której właścicielem jest root w systemie plików hosta. Przetrwa on down, aktualizacje oraz przebudowy kontenerów. Jest to również dokładnie ten element, który musi zostać uwzględniony w kopiach zapasowych.

Tworzenie kopii zapasowej wolumenu nazwanego

Standardowy schemat polega na użyciu tymczasowego kontenera, który montuje wolumen w trybie tylko do odczytu obok katalogu hosta i archiwizuje dane za pomocą tar:

docker run --rm \
  -v miniflux_db-data:/data:ro \
  -v "$PWD":/backup \
  alpine:3.22 tar czf /backup/miniflux-db-$(date +%F).tar.gz -C /data .

Nie wymaga to instalacji dodatkowego oprogramowania ani pozostawiania uruchomionych procesów. Przywracanie danych jest procesem odwrotnym, polegającym na użyciu tar xzf w nowym, pustym wolumenie z odwróconymi punktami montowania.

Ważna uwaga dotycząca baz danych: archiwizacja katalogu danych działającego Postgres może przechwycić stan w trakcie zapisu, co uniemożliwi poprawne uruchomienie bazy. Należy albo użyć docker compose stop na czas trwania operacji tar, albo, co jest lepszym rozwiązaniem, wykonać zrzut logiczny, który jest spójny z założenia:

docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gz

Flaga -T wyłącza pseudo-terminal, który Compose przydziela domyślnie; przesyłanie wyjścia zrzutu przez TTY może prowadzić do jego uszkodzenia. Należy umieścić jedno z tych poleceń w cron i skopiować wynik poza VPS; kopia zapasowa na tym samym dysku, co chronione dane, jest jedynie duplikatem, a nie kopią zapasową. Przewodnik po Nextcloud zawiera pełną, zaplanowaną procedurę opartą dokładnie na tych dwóch schematach.

Tryby awarii i towarzyszące im komunikaty

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock, użytkownik nie należy jeszcze do grupy docker lub bieżąca sesja nie uwzględnia tej zmiany. id wyświetla aktywne grupy; newgrp docker naprawia bieżącą powłokę, a wylogowanie i ponowne zalogowanie rozwiązuje problem dla wszystkich sesji.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?, inny problem: sam daemon nie działa. sudo systemctl status docker oraz sudo journalctl -u docker -n 50 wskazują przyczynę. Na serwerze VPS klasyczną przyczyną jest zapełnienie dysku, sprawdź to za pomocą df -h /var/lib/docker.

Bind for 127.0.0.1:8080 failed: port is already allocated, inny kontener już korzysta z tego portu hosta. docker ps wskazuje który; zazwyczaj winny jest nieaktywny kontener pozostały po testach sprzed docker run tygodni. Jeśli docker ps nie wykazuje konfliktów, port jest zajęty przez proces spoza Docker; sudo ss -tlnp | grep 8080 pozwoli go zidentyfikować.

yaml: line 14: did not find expected key, błąd wcięć w linii wskazanej w komunikacie lub bezpośrednio nad nią. Pliki Compose to format YAML: wymagają wcięć dwuspacjowych, wyłącznie za pomocą spacji; użycie znaku tabulacji w jakimkolwiek miejscu powoduje błąd krytyczny. docker compose config weryfikuje poprawność pliku bez uruchamiania usług; warto wyrobić sobie nawyk uruchamiania tego polecenia po każdej edycji.

Niespodzianka ze strony ufw nie generuje żadnego błędu, co czyni ją niebezpieczną: wdrożenie przebiega pomyślnie, ufw status wygląda poprawnie, a skanowanie portów z zewnątrz mimo to wykrywa bazę danych. Należy ponownie przeczytać sekcję dotyczącą portów, sprawdzić każdy wpis ports: pod kątem brakującego prefiksu 127.0.0.1: i potwierdzić stan z innej maszyny za pomocą curl http://your-vps-ip:8080; pożądaną odpowiedzią jest connection refused.

W tym miejscu przewodnik po Traefik pozwala przekształcić pojedynczy stos w wiele aplikacji za jednym punktem wejścia HTTPS, a co warto hostować samodzielnie w 2026 stanowi listę usług do uruchomienia. Gdy działa już kilka takich stosów i każdy posiada własny formularz logowania, serwer SSO typu Authentik pozwala skonsolidować je do jednego konta za tym samym proxy.

Serwer gier, taki jak serwer Minecraft na VPS, jest dobrym pierwszym projektem Compose do ćwiczeń. Jeśli lepszym materiałem do nauki będzie coś używanego codziennie, openGym, samodzielnie hostowany tracker treningów, to niewielki stos przypięty do taga git zamiast taga obrazu. Przed zarejestrowaniem pierwszego klucza dostępu wymaga on terminacji TLS. Zdjęcia są zwykle pierwszymi danymi, które chce się odzyskać z cudzej chmury, a porównanie PhotoPrism i Immich pozwala ustalić minimalną ilość pamięci RAM oraz procedurę tworzenia kopii zapasowych przed przypisaniem wolumenu do któregoś z tych narzędzi. Gdy dwie usługi przestają wystarczać, uruchomienie AFFiNE jako obszaru roboczego w stylu Notion wykorzystuje te same wzorce w czterech kontenerach. Jest też dobrym testem tego, czy przypięte tagi, healthchecki i nazwane wolumeny stały się już nawykiem.

FAQ

Dlaczego otrzymuję błąd "permission denied while trying to connect to the Docker daemon socket"?

Użytkownik nie należy do grupy docker lub został do niej dodany po rozpoczęciu bieżącej sesji, ponieważ przynależność do grup jest weryfikowana tylko przy logowaniu. Należy wykonać sudo usermod -aG docker $USER, następnie newgrp docker lub wylogować się i zalogować ponownie, a na koniec potwierdzić uprawnienia za pomocą id. Grupa ta zapewnia dostęp równoważny z rootem do hosta, dlatego należy dodawać do niej wyłącznie użytkowników, którym przyznano by uprawnienia sudo.

Czy polecenie docker compose down usuwa dane?

Standardowe docker compose down nie usuwa danych; usuwa jedynie kontenery oraz sieć projektu. Wolumeny nazwane (named volumes) pozostają nienaruszone, a kolejne up -d ponownie je podłączy. docker compose down -v to wariant destrukcyjny: usuwa on wolumeny nazwane, co oznacza utratę bazy danych bez możliwości potwierdzenia czy cofnięcia operacji. Nigdy nie należy uruchamiać -v na stosie (stack) z rzeczywistymi danymi bez posiadania zweryfikowanej kopii zapasowej.

Jaka jest różnica między docker-compose a docker compose?

docker-compose (z łącznikiem) to Compose v1, samodzielny plik binarny w języku Python, którego cykl życia zakończył się w 2023 roku i nie powinien być instalowany na nowych serwerach. docker compose (ze spacją) to Compose v2, wtyczka Go dla Docker CLI, instalowana jako docker-compose-plugin z repozytorium apt firmy Docker. Polecenia oraz pliki YAML są niemal w pełni kompatybilne, więc jeśli stary poradnik zaleca docker-compose up, należy wpisać docker compose up.

Dlaczego kontener Docker jest dostępny z Internetu, mimo że ufw blokuje port?

Ponieważ Docker publikuje porty za pomocą reguł DNAT w łańcuchu PREROUTING w iptables, a przekierowane pakiety przechodzą ścieżką FORWARD przez własne łańcuchy Dockera, nigdy nie trafiają one do łańcucha INPUT, w którym działają reguły ufw. W związku z tym ufw deny 8080 nie ma wpływu na opublikowany port kontenera. Problem należy rozwiązać u źródła: publikować porty na 127.0.0.1: i udostępniać usługi za pośrednictwem reverse proxy.

Czy powinienem używać wolumenu nazwanego czy bind mount?

Wolumeny nazwane należy stosować dla danych, do których dostęp ma tylko kontener, w szczególności dla baz danych, ponieważ Docker automatycznie ustawia właściciela zgodnie z wymaganiami obrazu, co zapewnia poprawne uprawnienia. Bind mounts należy stosować dla plików obsługiwanych również z poziomu hosta: edytowanych konfiguracji, przesyłanych multimediów oraz wszystkiego, co ma mieć łatwo dostępną ścieżkę. Jeśli kontener nie uruchamia się z błędem permission denied przy użyciu bind mount, pierwszą rzeczą do sprawdzenia jest niezgodność UID między hostem a kontenerem.