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

Docker Compose: bind mount a named volume - różnice

Dowiedz się, kiedy stosować bind mount, a kiedy named volume w Docker Compose. Wyjaśniamy różnice w uprawnieniach plików, zarządzaniu danymi, backupie oraz migracji kontenerów.

Bind mount czy named volume: krótka odpowiedź

Wolumeny w Docker Compose występują w dwóch rodzajach, a wybór zależy od tego, kto zarządza plikami. Bind mount należy stosować dla plików edytowanych i odczytywanych przez użytkownika, takich jak konfiguracje, szablony czy statyczne strony WWW. Named volume służy do przechowywania danych zarządzanych przez aplikację, na przykład plików baz danych, indeksów wyszukiwania czy przesłanych mediów. Bind mount wskazuje na ścieżkę w systemie hosta, którą można otworzyć w edytorze. Named volume to przestrzeń dyskowa tworzona i śledzona przez Docker, do której dostęp uzyskuje się za pośrednictwem narzędzi Docker.

Oba typy pojawiają się pod tym samym kluczem volumes: wewnątrz definicji usługi, co prowadzi do częstych pomyłek. Różnica polega na zawartości po lewej stronie dwukropka. Jeśli lewa strona zaczyna się od . lub /, jest to ścieżka w systemie hosta, czyli bind mount. Każda inna wartość jest nazwą, co oznacza named volume; taka nazwa musi zostać dodatkowo zadeklarowana w sekcji volumes: na najwyższym poziomie pliku.

Dwie składnie w pliku compose

services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: changeme
    volumes:
      - pgdata:/var/lib/postgresql/data
  web:
    image: nginx:1.27
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./site:/usr/share/nginx/html:ro

volumes:
  pgdata:

pgdata:/var/lib/postgresql/data to wolumen nazwany. ./nginx.conf:/etc/nginx/nginx.conf to montowanie typu bind mount, a :ro montuje je w trybie tylko do odczytu, co jest właściwym ustawieniem domyślnym dla konfiguracji, której kontener nie powinien modyfikować. Pomiń wpis najwyższego poziomu volumes:, a Compose zatrzyma się z błędem service "db" refers to undefined volume pgdata.

Uruchom usługę i wyświetl zasoby utworzone przez Docker:

docker compose up -d
docker volume ls

Wolumen nie nazywa się pgdata. Nazywa się <project>_pgdata, gdzie nazwa projektu domyślnie przyjmuje nazwę katalogu zawierającego plik compose. Katalog o nazwie myapp skutkuje nazwą myapp_pgdata. Jest to istotne, ponieważ zmiana nazwy katalogu spowoduje utworzenie nowego, pustego wolumenu, a aplikacja będzie wyglądać tak, jakby utraciła dane. W rzeczywistości tak się nie stało: stary wolumen jest nadal widoczny po wykonaniu docker volume ls. Przypisz nazwę za pomocą name: w pliku compose lub ustaw COMPOSE_PROJECT_NAME, jeśli katalog może zostać przeniesiony. Tego typu ustawienia powinny znajdować się wraz z innymi plikami środowiskowymi i sekretami Compose.

Dlaczego błędy uprawnień dotyczą tylko bind mounts

To najważniejsza różnica praktyczna, wynikająca z jednej zasady: nazwany wolumen, który jest pusty przy pierwszym użyciu, jest inicjowany zawartością obrazu, podczas gdy bind mount nigdy nie jest.

Gdy Docker montuje pusty nazwany wolumen w miejscu katalogu, który posiada już zawartość w obrazie, kopiuje tę zawartość do wolumenu, zachowując uprawnienia i właściciela zdefiniowane w obrazie. Oficjalny obraz Postgres dostarcza /var/lib/postgresql/data, którego właścicielem jest jego własny użytkownik postgres, więc wolumen otrzymuje tego samego właściciela o tym samym numerycznym identyfikatorze, a baza danych uruchamia się poprawnie.

Bind mount działa odwrotnie. Kontener widzi dokładnie to, co znajduje się na hoście, włącznie z uprawnieniami, a zawartość obrazu w tej ścieżce jest ukryta. Jeśli katalog na hoście nie istnieje, Docker daemon tworzy go, działając jako root, co skutkuje katalogiem, którego właścicielem jest root:root. Proces kontenera działający jako użytkownik inny niż root nie może wtedy zapisać do niego danych:

PermissionError: [Errno 13] Permission denied: '/data/app.db'

Rozwiązaniem jest dopasowanie identyfikatorów. Własność w ramach bind mount jest porównywana według numerycznego identyfikatora użytkownika (uid), a nie nazwy, ponieważ kontener posiada własny plik /etc/passwd. Użytkownik o nazwie app wewnątrz kontenera nie ma znaczenia dla hosta. Uid 1000 oznacza uid 1000 po obu stronach.

id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./data

docker compose exec web id wyświetla uid, z którym faktycznie uruchamia się proces kontenera. Należy dopasować właściciela katalogu na hoście do tego numeru lub przypisać kontener do własnego numeru za pomocą user: "1000:1000" w definicji usługi. Przypisanie user: jest czystszym rozwiązaniem dla aplikacji napisanej samodzielnie. Zmiana właściciela katalogu na hoście (chown) jest bezpieczniejsza w przypadku obrazów, których nie jesteś autorem, ponieważ niektóre z nich uruchamiają punkt wejścia (entrypoint) jako root, a następnie obniżają uprawnienia, oczekując konkretnej własności plików.

Warto znać jeszcze dwie pułapki. W systemach Fedora, RHEL oraz innych z aktywnym SELinux (security-enhanced Linux), bind mount jest blokowany, dopóki nie zostanie zmieniona etykieta. Należy wtedy dodać :z dla ścieżki współdzielonej między kontenerami lub :Z dla ścieżki używanej tylko przez jeden kontener, zapisując to jako - ./data:/data:Z. Ponadto bind mount pojedynczego pliku, zamiast całego katalogu, przestaje działać, gdy edytor zastępuje plik nowym zamiast edytować go w miejscu, ponieważ montowanie odnosi się do oryginalnego inoda. Kontener będzie widział starą zawartość aż do restartu. W przypadku często edytowanych plików należy montować katalog nadrzędny.

Wydajność: gdzie różnica jest odczuwalna

Na serwerze z systemem Linux oba typy wolumenów korzystają z tej samej ścieżki w jądrze systemu, więc różnica w przepustowości jest na tyle mała, że nie powinna stanowić kryterium wyboru. Nazwane wolumeny korzystające z domyślnego sterownika local znajdują się w tym samym systemie plików co reszta Docker, w lokalizacji /var/lib/docker/volumes/, natomiast bind mount znajduje się w miejscu wskazanym przez użytkownika.

Różnica pojawia się w Docker Desktop dla systemów macOS oraz Windows, gdzie kontenery działają wewnątrz maszyny wirtualnej. W takim przypadku bind mount przechodzi z systemu plików hosta do maszyny wirtualnej przez warstwę współdzielenia plików, co powoduje zauważalne spowolnienie przy zadaniach wymagających wielu operacji na małych plikach, takich jak drzewo zależności Node.js czy pamięć podręczna frameworka PHP. Nazwane wolumeny pozostają wewnątrz maszyny wirtualnej i nie generują tego narzutu. Z tego powodu wiele plików Compose używanych w środowiskach programistycznych montuje katalog źródłowy jako bind mount, ale deklaruje nazwany wolumen dla node_modules.

Drugą istotną różnicą jest miejsce zapisu danych. Bind mount do /mnt/backup umieszcza dane na wskazanym dysku. Nazwany wolumen trafia do systemu plików, w którym znajduje się /var/lib/docker, co w przypadku serwera VPS zazwyczaj oznacza dysk główny. Baza danych rozrastająca się wewnątrz nazwanego wolumenu zapełnia ten sam dysk, na którym zapisywane są logi systemowe. Należy to sprawdzić, zanim dojdzie do awarii:

docker system df -v
df -h /var/lib/docker

docker system df -v wyświetla listę wszystkich wolumenów wraz z ich rozmiarem i oznacza te, do których nie odwołuje się już żaden kontener.

Inspekcja wolumenu nazwanego

Wolumen nazwany nie jest czarną skrzynką. Należy zapytać Docker o jego lokalizację:

docker volume inspect myapp_pgdata

Pole Mountpoint wskazuje rzeczywistą ścieżkę w systemie hosta, zazwyczaj /var/lib/docker/volumes/myapp_pgdata/_data. Można ją odczytać za pomocą sudo ls, co jest przydatne do szybkiej weryfikacji. Nie należy traktować tego miejsca jako lokalizacji do edycji plików. Zapisywanie tam plików jako root powoduje ponowne wystąpienie problemów z uprawnieniami opisanych powyżej, a sama ścieżka jest szczegółem implementacyjnym sterownika local, którego nie posiadają inne sterowniki wolumenów.

Bezpiecznym sposobem na zajrzenie do wnętrza wolumenu jest użycie tymczasowego kontenera, który go zamontuje:

docker run --rm -v myapp_pgdata:/vol alpine ls -la /vol

Metoda ta działa z każdym sterownikiem, uwzględnia te same uprawnienia, które widzi właściwy kontener, i nie pozostawia żadnych śladów dzięki fladze --rm.

Wykonywanie kopii zapasowych poszczególnych typów

Bind mount to zwykły katalog, więc każde narzędzie do tworzenia kopii zapasowych na poziomie plików obsłuży go bez problemu. Wystarczy wskazać ścieżkę na hoście i gotowe. Named volume wymaga dodatkowego kroku, ponieważ narzędzie musi uzyskać dostęp do jego zawartości. Należy zamontować wolumen oraz katalog hosta w tym samym tymczasowym kontenerze, a następnie utworzyć archiwum:

docker run --rm \
  -v myapp_pgdata:/data:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

Przywracanie danych polega na odwróceniu tego procesu do nowego wolumenu:

docker volume create myapp_pgdata_restored
docker run --rm \
  -v myapp_pgdata_restored:/data \
  -v "$PWD":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

tar zachowuje numeryczne identyfikatory właścicieli plików, gdy działa jako root wewnątrz kontenera, co pozwala na poprawne korzystanie z przywróconego wolumenu przez aplikację.

Jedno ostrzeżenie dotyczy obu typów. Kopiowanie plików bazy danych w trakcie jej pracy tworzy archiwum "ruchomego celu", co może prowadzić do przywrócenia bazy w stanie uszkodzonym. Należy najpierw zatrzymać usługę lub wykonać zrzut za pomocą narzędzia dostarczonego z bazą danych, jak w docker compose exec -T db pg_dump -U postgres appdb > appdb.sql. Pozwala to uzyskać zwykły plik, który można następnie uwzględnić w standardowej szyfrowanej procedurze kopii zapasowych restic wraz z plikami compose.

Migracja bind mount do nazwanego wolumenu

Przeniesienie jest operacją kopiowania, a nie zmiany nazwy, i zajmuje około minuty.

docker compose down
docker volume create myapp_pgdata
docker run --rm \
  -v "$PWD/data":/from \
  -v myapp_pgdata:/to \
  alpine sh -c 'cp -a /from/. /to/'

cp -a zachowuje właściciela, uprawnienia oraz znaczniki czasu, dzięki czemu użytkownik kontenera, który miał dostęp do starego katalogu, może odczytać nowy wolumen. Następnie należy zmodyfikować usługę, aby korzystała z pgdata:/var/lib/postgresql/data, dodać pgdata do sekcji volumes: najwyższego poziomu, wykonać docker compose up -d i sprawdzić logi aplikacji przed usunięciem starego katalogu. W przypadku operacji w drugą stronę stosuje się to samo polecenie z zamienionymi /from oraz /to.

Podczas testów należy pamiętać o jednej kwestii. docker compose down pozostawia nazwane wolumeny bez zmian, natomiast docker compose down -v usuwa każdy nazwany wolumen zadeklarowany w projekcie i operacji tej nie można cofnąć. Bind mount przetrwa oba polecenia, ponieważ Docker nigdy nie był właścicielem tego katalogu. Jeśli polecenia cyklu życia są jeszcze nieznane, przewodnik po podstawach Docker Compose dla VPS zawiera ich szczegółowe omówienie.

Wybór strategii dla poszczególnych usług

Należy ustalić, kto zapisuje pliki. Konfiguracja edytowana w edytorze tekstu i zatwierdzana w git powinna znajdować się w bind mount, zamontowanym w :ro, ponieważ musi być widoczna i wersjonowana. Stan aplikacji, którego nie edytuje się ręcznie, powinien znajdować się w named volume, ponieważ Docker poprawnie nadaje uprawnienia, a dane nie zależą od ścieżki na hoście.

Przypadkiem mieszanym są media. Biblioteka zdjęć jest zapisywana przez aplikację, ale zarządzana przez użytkownika i często jest na tyle duża, że wymaga dedykowanego dysku. Należy użyć bind mount do ścieżki na tym dysku i jednorazowo skonfigurować uprawnienia. Jest to wzorzec stosowany w większości rozwiązań self-hosted: named volumes dla baz danych i pamięci podręcznych, bind mounts dla konfiguracji oraz dużych katalogów wymagających nadzoru. System obsługi zgłoszeń, taki jak Chatwoot działający na VPS, wykorzystuje dokładnie ten model: Postgres w named volume oraz przesłane załączniki w ścieżce, którą można objąć kopią zapasową.

FAQ

Jaka jest różnica między bind mount a named volume?

Bind mount mapuje ścieżkę na hoście do kontenera, dzięki czemu obie strony widzą ten sam katalog i można go edytować za pomocą standardowych narzędzi. Named volume to przestrzeń dyskowa tworzona i zarządzana przez Docker, do której odwołuje się poprzez nazwę i deklaruje w bloku najwyższego poziomu volumes:. Praktyczny podział opiera się na własności: bind mounts służą do konfiguracji utrzymywanej przez użytkownika, a named volumes do danych zarządzanych przez aplikację.

Dlaczego otrzymuję błąd "permission denied" przy bind mount, a nie przy named volume?

Pusty named volume jest inicjowany na podstawie obrazu, więc dziedziczy własność ustawioną w obrazie i użytkownik kontenera może do niego zapisywać. Bind mount pokazuje katalog hosta dokładnie w takiej postaci, w jakiej się znajduje, a jeśli Docker musiał go utworzyć, przypisał mu własność root. Uruchom docker compose exec <service> id, aby sprawdzić identyfikator numeryczny używany przez kontener, a następnie wykonaj sudo chown -R <uid>:<gid> na katalogu hosta lub ustaw user: "1000:1000" w definicji usługi.

Gdzie Docker przechowuje named volumes na dysku?

Przy użyciu domyślnego sterownika local znajdują się one w /var/lib/docker/volumes/<volume>/_data, a docker volume inspect <volume> wyświetla dokładną ścieżkę Mountpoint. Można ją odczytać w celu weryfikacji, ale zapisywać dane należy wyłącznie za pośrednictwem kontenera. Edycja plików jako root na hoście zmienia własność w sposób, którego kontener może nie obsłużyć poprawnie.

Jak wykonać kopię zapasową named volume?

Uruchom tymczasowy kontener z zamontowanym wolumenem oraz katalogiem hosta, a następnie wykonaj archiwizację z jednego do drugiego za pomocą docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data .. W przypadku bazy danych należy użyć dedykowanego narzędzia do zrzutu (dump), zamiast kopiować pliki w czasie pracy, ponieważ kopia wykonana w trakcie zapisu może doprowadzić do przywrócenia uszkodzonych danych.

Czy docker compose down usuwa wolumeny?

docker compose down usuwa kontenery i sieci, pozostawiając named volumes w nienaruszonym stanie. docker compose down -v usuwa również wszystkie named volumes zadeklarowane w projekcie, bezpowrotnie. Bind mounts nie są usuwane przez żadne z tych poleceń, ponieważ dany katalog należy do hosta, a nie do Docker.