Magazyny danych w Dockerze

Wraz z usunięciem kontenera, usuwane są też wszystkie jego pliki. Tak więc, jeśli coś dodaliśmy bądź zmodyfikowaliśmy bezpośrednio w samym kontenerze to też zostanie to usunięte. Rozwiązaniem może być tu dodatkowy magazyn, gdzie pliki będą zapisywane na stałe.

Co to jest magazyn (storage) w dockerze?

Magazyn dla kontenerów jest to obiekt, który jest pojemnikiem na dane kontenera. 

Po co jest magazyn w dokerze?

Możesz się spotkać też z określeniem, że kontenery są immutable, czyli niezmienne. W praktyce oznacza to, że gdy kontener wymaga jakiś  zmiany to docelowo nie modyfikujemy aktualnego, tylko usuwany go. A zmiany wprowadzamy już dla nowego obrazu, z którego powstanie nowy kontener, tak by już przy utworzeniu, od początku zawierał wszystkie potrzebne nam dane.
Na przykład jeśli kontener wymaga jakiegoś pakietu, to deklaracja dodania tegoż pakietu powinna być zapisana w dockerfile i na podstawie tego utworzony nowy obraz i nowy kontener będzie zawierał już ten pakiet. 

No dobrze, ale co z danymi które, chcę modyfikować już podczas pracy kontenera?
Na przykład chce wrzucać nową wersję strony, nad którą pracuje, bez konieczności uruchamiania nowego wersji kontenera za każdym razem. Jak to zrobić w kontenerze? 

Tu docker też przewidział taką potrzebę i dlatego mamy kilka różnych rozwiązań na magazyn danych, takich jak: wolumen, bind mont czy tmpfs

Jakie są rodzaje magazynów w dockerze?

Wolumen (Volumes) 

Jest to jeden z najczęściej wykorzystywanych pojemników na dane kontenera. Wolumen to dodatkowy i oddzielny obiekt w systemie plików Dockera, gdzie zapisywane są dane dla kontenera. Nie mamy tam bezpośredniego dostępu z poziomu hosta – dane w Wolumenach są odizolowane od danych hosta.
Co ważne, wolumen nie jest usuwany wraz z usunięciem kontenera.
Z jednego wolumenu może korzystać wiele kontenerów.
Wolumen najczęściej wykorzystywany do przechowywania danych bazy danych.
Do wolumenów możemy ograniczyć prawa dla danego kontenera tylko do odczytu (RO – read only).

Wolumen możemy utworzyć oddzielnie lub utworzyć go razem z poleceniem docker run

docker volume create <nazwaWolumenu>

docker run -it --name mynginx -p 8080:80 -v <nazwaWolumenu>:/usr/share/nginx/html nginx


Bind mount

Ten typ magazynu dla kontenera to po prostu podmontowanie lokalnego katalogu z hosta do katalogu wewnątrz  kontenera. Innymi słowy pliki z katalogu kontenera widzimy bezpośrednio w katalogu hosta.

Synchronizacja działa w dwie strony –  gdy zmodyfikujemy coś w katalogu po stronie hosta to będzie to widoczne w kontenerze i na odwrót, gdy zmodyfikujemy

Warto mieć na uwadze, że właścicielem tych katalogów (na hoście i kontenerze) musi być ten sam użytkownik. W przeciwnym razie możesz nie mieć dostępu takiego katalogu, gdzie inny użytkonik jest właścielem. Dobrym przykładem może być tu kontener Jenkinsa gdzie mamy użytkonika jenkins a nie root, jak w przypadku większości kontenerów. Tu rozwiązaniem najłatwiejszym jest korzystanie z wolumenów a nie bind mountów.

docker run -it -d -p 8080:80 --name mynginx -v /sciezka/do/plikow/lokalnych:/usr/share/nginx/html nginx

tmpfs (temporary file system)

W przypadku tego magazynu,, jak sama nazwa wskazuje, jest to tymczasowy magazyn na dane przechowywane tylko  w pamięci hosta. Właściwie ten magazyn to rodzaj do RAMdisku. Obecnie,  jest dostępny tylko w Dockerze dla Linuksa. 

Co ważne, po zatrzymaniu kontenera dane są usuwane, więc to tak naprawdę tymczasowy obiekt na dane. Ten rodzaj magazynu przydany jest szczególne do wrażliwych danych, gdzie nie chcemy żeby pozostał po danych jakikolwiek ślad w system polików hosta czy kontenera.

Magazyn typu wolumen czy bind mont modyfikuje file system natomiast tmpfs nie, ponieważ dane są zapisywane  tylko w pamięci operacyjnej.  

docker run -it --mount type=tmpfs,destination=/tmpdisk,tmpfs-size=10m alpine:latest /bin/df -h /tmpdisk

Jaki rodzaj magazynu jest najlepszy? Wolumen, bind bmount, tmpfs – co wybrać?

Nie ma tu jednoznacznej odpowiedzi jaki rodzaj magazynu jest najlepszy. Wszystko zależy od potrzeb i wymagań. Zauważyłem, że często na środowiskach deweloperskich, nie produkcyjnych, korzysta się z bind mountów, bo wygodniej, natomiast na środowiskach produkcyjnych, dane przechowuje się już w wolumenach bo pewniej i bezpieczniej. Takie podejście też jest spoko.

Jak zapisać już wprowadzone dane w kontenerze?

Wprowadziłem zmianę danych bezpośrednio w kontenerze, które MUSZĘ zachować. Nie mam podpiętego żadnego magazynu. Co teraz?

Nie jest to optymalne podejście aby modyfikować dane w kontenerze, które muszą być zachowane po restarcie kontenera. Lepiej jest te modyfikacje wprowadzić wcześniej w obrazie czy pliku Dockerfile ewentualnie mieć je w oddzielnym magazynie typu wolumen czy bind mount.
Jednak zrozumiałe jest, szczególnie przy tworzeniu oprogramowania, że czasem zdarzają się przypadki w których musimy wprowadzić zmiany w działającym kontenerze. A potem zachować je tak by po restarcie kontenera były te zmiany obecne.
Do tego służy polecenie docker commit. Powoduje ono utworzenie nowego obrazu na podstawie obecnego kontenera. Czyli odwracamy proces – standardowo uruchamiany kontenery na podstawie obrazu natomiast w wyjątkowych przypadkach jak ten możemy utworzyć obraz na podstawie działającego kontenera. Jednak podkreślam – tak robimy tylko w wyjątkowych przypadkach.

docker commit <IDKontenera> <nazwaNowegoObrazu>

Nawiasem mówiąc, spotkałem się z określaniem wolumen na każdy rodzaj magazynu kontenera. Co jest trochę mylne, ponieważ nie ma takiego czegoś jak “wolumen bind mount” – to są dwa inne rodzaje magazynów na dane.
Warto jednak mieć na uwadze, że i takie uproszczenia pojawiają się w potocznej mowie osób zajmujących się dockerem.

Tags: