04. [20p] Docker Volumes

Defineam un container Docker ca fiind o instanță în execuție a unei imagini Docker. În acest sens, o mare parte din datele existente în interiorul unui container provin din nivelele (layers) de construcție a imaginii instanțiate. O aplicație containerizată, odată lansată, poate genera date pe care le stochează pe sistemul de fișiere. În caz particular, aplicația noastră va stoca imaginile urcate în platformă pe sistemul de fișiere din backend, într-o cale specifică: /home/rl-user/rl-app/rl-images/upload.

Straturile/layerele din construcția imaginii sunt read-only, ele deservind totalitatea containerelor aflate în execuție, care sunt instanțe ale imaginii. În cazul în care este necesară manipularea datelor existente sau crearea de date noi, funcția de storage a Docker Engine-ului va separa modificările aduse imaginii de bază print-un strat (layer) adițional, poziționat peste straturile read-only existente. Nivelul suplimentar, cu drepturi Read-Write (R/W), este activ atâta timp cât containerul își desfășoară ciclul de viață. La finalizarea execuției unui container, informația generată la runtime și stocată pe sistemul de fișiere se pierde. Mecanismul de stocare a datelor, așa cum a fost descris anterior poartă numele de Copy-on-write (COW), și este realizat prin utilizarea unui sistem de fișiere special din categoria Union File Systems.

În continuare ne propunem să exploatăm mecanismele native Docker pentru asigurarea persistenței datelor.

În demo-ul anterior, ați avut ocazia să urcați poze în platforma de sharing de imagini. Dacă nu ați făcut-o, acum este un moment propice (formatul suportat este PNG). În continuare vom șterge containerul de backend și îl vom reconstrui:

student@aldebaran:~$ docker rm -f rl-backend
student@aldebaran:~$ docker run -d --name=rl-backend  \
   -e DB_SERVER=rl-database \
   --network=dbnet \
   rlrules/docker-lab-backend
student@aldebaran:~$ docker network connect appnet rl-backend

Dați refresh la pagina web, încărcată în browser. Pozele nu mai există întrucât acestea au fost scrise de backend pe sistemul de fișiere. Pentru a păstra consistența informației stocate în baza de date vom reseta (șterge) atât baza de date cât și containerul de backend.

student@aldebaran:~$ docker rm -f rl-backend
student@aldebaran:~$ docker rm -f rl-database

Știm că aplicația stochează pozele uploadate în locația /home/rl-user/rl-app/rl-images/upload de pe sistemul de fișiere. Pentru a asigura persistența acestui folder, în cazul în care accidental ștergem containerul de backend, sau în cazul în care suntem nevoiți să îl relansăm, din cauza unei probleme de funcționare, vom crea ceea ce se numește un Docker volume.

student@aldebaran:~$ docker volume create poze
student@aldebaran:~$ docker volume list

In continuare vom relansa serviciul baze de date:

student@aldebaran:~$ docker run -d --name=rl-database \
   -e MYSQL_DATABASE=rl-database \
   -e MYSQL_USER=rl-user \
   -e MYSQL_PASSWORD=rl-specialpassword \
   -e MYSQL_ROOT_PASSWORD=root \
   -e TZ=Europe/Bucharest \
   --network=dbnet \
   mysql

Urmat de serviciul de backend, atașând în plus volumul nou creat.

student@aldebaran:~$ docker run -d --name=rl-backend  \
   -e DB_SERVER=rl-database \
   --network=dbnet \
   --mount type=volume,src=poze,dst=/home/rl-user/rl-app/rl-images/upload \
   rlrules/docker-lab-backend
[...]
student@aldebaran:~$ docker network connect appnet rl-backend

Alternativ puteti utiliza si constructia -v poze:/home/rl-user/rl-app/rl-images/upload

Să vedem dacă putem obține persistența datelor în urma unor rulări succesive. Urcați câteva poze în platformă și refaceți containerul de backend:

student@aldebaran:~$ docker rm -f rl-backend
student@aldebaran:~$ docker run -d --name=rl-backend  \
   -e DB_SERVER=rl-database \
   --network=dbnet \
   -v poze:/home/rl-user/rl-app/rl-images/upload \
   rlrules/docker-lab-backend
student@aldebaran:~$ docker network connect appnet rl-backend

Disecând mecanismul de abstractizare prin volume, un obiect de tip volum este în, în spate, un folder stocat pe sistemul de fișiere al mașinii gazdă, într-o zonă specifică a Docker Engine-ului. Să încercăm să găsim această locație utilizând comanda docker volume inspect:

student@aldebaran:~$ docker volume inspect poze

Pentru simplitate:

student@aldebaran:~$ docker volume inspect poze --format {{.Mountpoint}}

O altă metodă de a asigura persistența datelor o poate furniza mecanismul de Mount Binding. În loc de a crea și atașa un volum unui container Docker, o altă posibilitate o presupune partajarea directă a unui custom folder de pe sistemul de fișiere al mașinii gazdă, între cele 2 entități. Întrucât anterior am descoperit unde stochează Docker datele dintr-un obiect de timp volum, în continuare vom copia fișierele din volum într-un custom folder creat în home-ul utilizatorului student și vom monta acel folder utilizând mecanismul de mount binding.

student@aldebaran:~$ mkdir $HOME/poze
student@aldebaran:~$ sudo cp -p `docker volume inspect poze --format {{.Mountpoint}}/*` $HOME/poze/
student@aldebaran:~$ docker rm -f rl-backend
[...]
student@aldebaran:~$ docker run -d --name=rl-backend  \
   -e DB_SERVER=rl-database \
   --network=dbnet \
   --mount type=bind,src=$HOME/poze,dst=/home/rl-user/rl-app/rl-images/upload \
   rlrules/docker-lab-backend
[...]   
student@aldebaran:~$ docker network connect appnet rl-backend
[...]

Urcați o nouă poză în platformă. Apare aceasta în directorul poze?