Emmagatzematge
Introducció
Section titled “Introducció”Arbre de fitxers
Section titled “Arbre de fitxers”Si vols començar amb un entorn net, esborra-ho tot:
$ docker system pruneWARNING! This will remove: - all stopped containers - all networks not used by at least one container - all dangling images - all dangling build cache
Are you sure you want to continue? [y/N] y...
Total reclaimed space: 27.96MB
A diferència d’altres sistemes operatius, Linux unifica tot l’emmagatzematge en un sol arbre.
A Windows tens C:\
, D:\
, etc.:
{% image “windows.png” %}
Però, en Linux tot està muntat a /
.
{% image “root.png” %}
Punt de muntatge
Section titled “Punt de muntatge”Els dispositius d’emmagatzematge, com ara particions de disc o particions de disc USB, estan connectats a ubicacions específiques d’aquest arbre.
Aquests llocs s’anomenen punts de muntatge.
Un punt de muntatge defineix la ubicació a l’arbre, les propietats d’accés a les dades en aquest punt (per exemple, l’escriptura) i la font de les dades muntades en aquest punt (per exemple, un disc dur, un dispositiu USB o un disc virtual en memòria).
Aquí tens un dibuix que representa un sistema de fitxers construït a partir de diversos dispositius d’emmagatzematge, amb cada dispositiu muntat en una ubicació i nivell d’accés específics.
{% image “mount-points.png” %}
RAM disk
Section titled “RAM disk”Crear un sistema de fitxers en RAM permet que no quedi rastre de fitxers confidencials temporals o utilitzar fitxers temporals amb un accés super ràpid.
Crea un directori i permet que tothom tingui accés:
$ sudo mkdir /var/fast$ sudo chmod 777 /var/fast
Ara crea un sistema de fitxers tmpfs de 1024 MB i nom de dispositiu ramdisk
:
$ sudo mount -t tmpfs -o size=1024m ramdisk /var/fast
Pots veure que la unitat ramdisk s’ha muntat correctament:
$ mount | grep ramdiskramdisk on /var/fast type tmpfs (rw,relatime,size=1048576k,inode64)
Prova de crear un fitxer, veuras que no notaras la diferencia:
$ echo "Hello" > /var/fast/message.txt$ ls -l /var/fast/total 4-rw-rw-r-- 1 isard isard 6 de maig 21 15:34 message.txt
Si desmuntes la carpeta, perds tota la informació perquè no estava guardada en un dispositiu físic sinó en memòria.
$ sudo umount /var/fast$ ls -l /var/fast/total 0
Contenidor
Section titled “Contenidor”Els punts de muntatge permeten que el programari i els usuaris utilitzin l’arbre de fitxers en un entorn Linux sense saber exactament com s’assigna aquest arbre a dispositius d’emmagatzematge específics.
Cada contenidor té un MTN namespace i una arrel única d’arbre de fitxers.
L’arbre de fitxers d’un contenidor està format per un conjunt de punts de muntatge de 4 tipus diferents:
-
ImageFS – Les imatges que s’han descarregat es munten en diferents punts del sistema de fitxers del contenidor.
-
In-memory storage – Un disc RAM com el que hem vist abans
-
Bind mounts – Un directori concret del host
-
Docker Volumes – Un directori lògic del host
A l’esquerra està el sistema de fitxers vist des del contenidor, i a la dreta els punts de muntatge reals en sistema de fitxers del host:
{% image “container-filesystem.png” %}
Bind mount
Section titled “Bind mount”Un bind mount et permet muntar un directori del host en qualsevol punt de muntatge del sistema de fitxers del contenidor.
Arrenca un contenidor Apache amb l’opció -p 80:80
perquè poguem connectar-nos des de fora del host:
$ docker run --rm -d --name apache -p 80:80 httpd...97d2d3f55150795b03ae2a3131ee3cfd469dbfc82e6f793c514853cc73da662b$ curl localhost<html><body><h1>It works!</h1></body></html>
A {% link “p:/linux/docker/network/” %} ja explicarem com funciona l’opció -p
.
Si volem canviar el missatge, podem entrar dins el contenidor i modificar el fitxer index.html
:
$ docker exec -it apache bash...$ echo "Hello!" > htdocs/index.html...$ exit exit$ curl localhostHello!
Una altra opció és crear una carpeta www
fora del contenidor amb un fitxer index.html
i altre contingut.
$ mkdir www$ echo "Bye!" > www/index.html
Eliminem el contenidor que està en execució:
$ docker stop apacheapache
Creem un contenidor nou montant el directori /usr/local/apache2/htdocs
a la nostra carpeta www
.
$ docker run --rm -d --name apache -p 80:80 --mount type=bind,source="$(pwd)"/www,target=/usr/local/apache2/htdocs httpd9dacc8d3d17cd2a4347732ca785e4a8f57fe2031b3baaae96a3399c14c9985c9
Si fas un curl
a localhost pots veure que ara respon amb el teu fitxer index.html
no amb el del contenidor:
$ curl localhostBye!
Modifica el fitxer index.html
i verifica que el servidor apache contesta amb el nou contingut:
$ echo "Patufet"> www/index.html$ curl localhostPatufet
Entra dins el contenidor, modifica el fitxer index.html
, surt del contenidor i verifica que desde fora també s’ha modificat:
$ docker exec -it apache bash...$ cat htdocs/index.html Patufet...$ echo "Patufet" > htdocs/index.html...$ exit$ cat www/index.htmlPatufet
Amb l’ordre docker inspect
pots verificar en la secció Mount
que el muntatge d’enllaç s’ha creat correctament:
{% raw %}$ docker inspect apache --format '{{ json .Mounts }}' | jq{% endraw %}[ { "Type": "bind", "Source": "/home/isard/www", "Destination": "/usr/local/apache2/htdocs", "Mode": "", "RW": true, "Propagation": "rprivate" }]
Com que hem separat el contingut web del servidor web podem crear un altre servidor Apache que escolti al port 8080
i serveixi el mateix contingut:
$ docker run --rm -d --name apache2 -p 8080:80 --mount type=bind,source="$(pwd)"/www,target=/usr/local/apache2/htdocs httpd292f7b72277524fc656593b9504676e782e50e7d407eff6686155376ae699082$ curl localhost:80Patufet$ curl localhost:8080Patufet
També podem crear un altre servidor Nginx que escolti al port 3000
i serveixi el mateix contingut.
L’única diferència és que la carpeta www
la tindrem que montar a /usr/share/nginx/html
:
$ docker run --rm -d --name nginx -p 3000:80 --mount type=bind,source="$(pwd)"/www,target=/usr/share/nginx/html nginx...c1f360dbc7e2ca97ca74648441f6a62bcadaf029954dfb23bf63361993df0e4a$ curl localhost:3000Patufet
Pots veure que hi ha tres servidors web servint el mateix contingut en ports diferents, i tots tenen el contingut de la carpeta www
on ells volen:
{% raw %}$ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"{% endraw %}CONTAINER ID NAMES PORTS20c8ebb1885d nginx 0.0.0.0:3000->80/tcp, :::3000->80/tcp292f7b722775 apache2 0.0.0.0:8080->80/tcp, :::8080->80/tcp9dacc8d3d17c apache 0.0.0.0:80->80/tcp, :::80->80/tcp
A part del contingut també pots montar els fitxer de configuració, d’aquesta manera ens separat el que és teu (estat) del programa que s’ha d’executar (comportament).
Eliminem els contenidors i ens quedem amb l’únic que ens importa: la carpeta www
:
$ docker stop apache apache2 nginxapacheapache2nginx
Emmagatzematge en memòria
Section titled “Emmagatzematge en memòria”La majoria d’aplicacions web utilitzen fitxers de claus privades, contrasenyes de bases de dades, fitxers de claus API o altres fitxers de configuració amb informació sensible.
És millor guardar aquesta informació en memòria perquè no deixa rastre.
Creem un contenidor amb un punt de muntatge en memòria:
$ docker run -it --name memory --mount type=tmpfs,dst=/secret alpine...$ echo "P@ssw0rd" > /secret/password.txt...$ echo "Hello" > /hello.txt...$ exit
Si aturem el contenidor i el tornem a arrencar, l’arxiu password.txt
haurà desaparegut mentres que el fitxer hello.txt
encara estarà:
$ docker stop memorymemory$ docker start memorymemory$ docker exec -it memory sh... $ cat /hello.txt Hello... $ cat /secret/password.txt cat: can't open '/secret/password.txt': No such file or directory
Volums
Section titled “Volums”{% image “volumes.png” %}
Enlloc de crear un carpeta i tenir que dir la ruta on està, pots utilitzar carpetes lògiques que es poden referenciar amb un nom.
Per exemple, quan executes una wiki en un contenidor t’interessa conservar les dades quan elimines el contenidor.
Enlloc de crear una carpeta pots crear un volum i guardar les dades allà.
Imagina’t que vols crear una wiki amb dokuwiki.
El primer pas NO es instal.lar dokuwiki com faries normalment, sinó crear un emmagatzematge on es guarda la wiki.
Crea un volum wiki-nature
:
$ docker volume create wiki-naturewiki-nature$ docker volume lsDRIVER VOLUME NAMElocal wiki-nature{% raw %}$ docker volume inspect --format "{{ json .Mountpoint }}" wiki-nature {% endraw%}"/var/lib/docker/volumes/wiki-nature/_data"
Pots veure que el volum és local (està en una carpeta local), concretament a /var/lib/docker/volumes/wiki
.
Per defecte, un volum és crea en el sistema de fitxers del host, però hi ha opcions més avançades.
Ha continuació has d’arrencar un contenidor dokuwiki amb el volum que has creat perquè totes les pàgines de la wiki s’escriguin en aquest volum.
$ docker run --rm -d --name wiki -p 80:8080 --volume wiki-nature:/bitnami/dokuwiki bitnami/dokuwiki...f11acc644df8f1a2f985be03be66d75766c17f1d15b86d04f2a1fb7a2f85fbf7
Obre un navegador a http://localhost i edita la pàgina principal:
{% image “dokuwiki.png” %}
Aquí tens una explicació de com pots utilitzar la imatge: https://hub.docker.com/r/bitnami/dokuwiki/dockerfile/.
-
Edita la primera pàgina amb algun contingut.
-
Para el contenidor (aquest s’eliminarà perquè has fet servir l’opció
--rm
)
$ docker stop wikiwiki$ docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESad7832d4d2c8 alpine "/bin/sh" 24 minutes ago Up 20 minutes memory
- Pots verificar que les pàgines estan guardades al volum i no es perden.
$ sudo ls /var/lib/docker/volumes/wiki-nature/_data
- Si vols torna a veure o editar la wiki només has de tornar a arrencar un altre contenidor dokuwiki muntant el volum:
$ docker run --rm -d --name wiki -p 80:8080 --volume wiki-nature:/bitnami/dokuwiki bitnami/dokuwikic9794ef60a22dac1e2a35dce8cc1285b68b499a0b925d541c86e0d2d4dfcdb22
Pots veure que el contenidor té un ID diferent i que el contingut s’ha guardat:
{% image “dokuwiki2.png” %}
Activitat
Section titled “Activitat”- Crea un volum
wiki-football
i genera contingut creant un contenidor.
$ docker volume create wiki-football$ docker run --rm -d --name wiki-football -p 90:8080 --volume wiki-football:/bitnami/dokuwiki bitnami/dokuwikia12f77e9b2d9fcf93e1d0cc4502869386fad1fdad1656af15470a8ab3e1a1908
Pots veure que:
-
Pots tenir dos dokuwiki funcionant a la vegada en ports diferents.
-
No has de tenir instal.lat dokuwiki o tenir contenidors funcionat si no els necessites en aquell moment (tot el contingut està guardat en volums).
{% raw %}$ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"{% endraw %}CONTAINER ID NAMES PORTSa12f77e9b2d9 wiki-football 8443/tcp, 0.0.0.0:90->8080/tcp, :::90->8080/tcpc9794ef60a22 wiki 8443/tcp, 0.0.0.0:80->8080/tcp, :::80->8080/tcp$ docker volume lsDRIVER VOLUME NAMElocal wiki-footballlocal wiki-nature
Neteja de volums
Section titled “Neteja de volums”Com has vist abans pots veure tots els volums que tens en el sistema amb l’ordre docker volume ls
:
$ docker volume lsDRIVER VOLUME NAMElocal wiki-footballlocal wiki-nature
Per suprimir un volum has d’executar l’ordre docker volume rm
:
$ docker volume rm wiki-natureError response from daemon: remove wiki-nature: volume is in use - [c9794ef60a22dac1e2a35dce8cc1285b68b499a0b925d541c86e0d2d4dfcdb22]
Però primer has d’aturar el contenidor:
$ docker stop wikiwiki$ docker volume rm wiki-naturewiki-nature
Activitats
Section titled “Activitats”Compartir fitxers
Section titled “Compartir fitxers”Si tenim un conjunt de fitxers html que volem fer servir mitjançant un servidor web, només volem un servidor web que funcioni i res més.
Per tant, enlloc d’executar un contenidor ubuntu i instal.lar un servidor apache, farem servir un contenidor amb una versió concreta d’apache ja instal.lat.
Una de les capacitats més rellevants d’un contenidor, es que podem executar un servidor apache sense haver de insta.lar res en el nostre host, i eliminar-lo quan ja no el necessitem. Pert tant, afegim l’opció –rm
perquè s’elimini quan el parem.
Això si, hem de permetre que es pugui accedir al servidor apache desde fora del contenidor fent servir un port forward a la xarxa virtual privada on està el contenidor:
$ docker run --rm -d --name apache -p 8000:80 httpdad5087500ed6abe77f6226bac5ef6693c8f71b8e2aaf3b0ce8e92a498417109a$ curl localhost:8000<html><body><h1>It works!</h1></body></html
Pots veure que tens accés al servidor web des del host en el port 8000.
El primer que pots observar, és que la pàgina per defecte d’apache és molt senzilla: It works!.
Si vols canviar el contingut de la pàgina pots entrar dins el contenidor i modificar la pàgina:
$ docker exec -it apache bash... $ echo "Hello World!" > htdocs/index.html... $ exit exit$ curl localhost:8000Hello World!
Però, quan el contenidor s’aturi i s’elimini es perdrà tot … Que hem de fer?
Una de les maneres de fer servir un contenidor apache és deixar que el contenidor tingui accés a la carpeta on tenim el nostre lloc web.
Atura el servidor apache:
$ docker stop apacheapache$ curl localhost:8000curl: (7) Failed to connect to localhost port 8000 after 0 ms: Connection refused
Crea el teu lloc web al host: site
$ mkdir site$ echo "Estic fora" > site/index.html
Aquesta vegada arrenca apache montant el directori /usr/local/apache2/htdocs/
del contenidor a la teva carpeta site
en mode només lectura:
$ docker run --rm -d --name apache -p 8000:80 --mount type=bind,src="$(pwd)"/site,dst=/usr/local/apache2/htdocs,readonly=true httpd2cde52ea8c9087bd9fbee769696e447a022044b0cb3bd55b462a8605636a2e43$ curl localhost:8000Estic fora
Si modifiques el contingut del fitxer site/index.html
del host el servidor respondrà amb el nou fitxer:
$ echo "Encara estic fora :-)" > site/index.html$ curl localhost:8000Encara estic fora :-)
Com és possible? Si entres al contenidor veurás que encara que el contenidor superposi els fitxers de la imatge httpd, la nostra comanda superposa la carpeta site a la del contenidor, i el resultat és que ja no té accés al fitxer index.html que està a la imatge, sinò al de la nostra carpeta.
$ docker exec -it apache bash... $ cat htdocs/index.html Encara estic fora :-)... $ exit exit
{% image “layers.png” %}
I si proves de modificar el contingut del fitxer index.html
no pots, perquè has montat la carpeta site amb permisos de només readonly
.
$ docker exec -it apache bash... $ echo "Estic dins" > htdocs/index.html bash: htdocs/index.html: Read-only file system
Com pots veure ja no estas sotmès a la dictadura d’apache o nginx: Tens el teu site al lloc que tu vols.
Versió
Section titled “Versió”Quan executes un contenidor a partir d’una imatge pots dir exactament quina versió vols executar.
Per tant, a més de poder dir exactament la versió d’apache que vull, puc tenir vàries versions a la vegada en ports diferents i servint el mateix lloc web!
A https://hub.docker.com/_/httpd pots trobar totes les versions.
Què tal la 2.2.34 del 2017?
$ docker run --rm -d --name apache-old -p 8001:80 --mount type=bind,src="$(pwd)"/site,dst=/usr/local/apache2/htdocs,readonly=true httpd:2.2.34
I perquè no fas servir nginx?
$ docker run --rm -d --name nginx -p 8002:80 --mount type=bind,src="$(pwd)"/site,dst=/usr/share/nginx/html,readonly=true nginx
Fixa’t que nginx fa servir un directori diferent a apache.
Tens 3 servidors web servint el mateix contingut a ports diferents.
$ curl localhost:8000Encara estic fora :-)$ curl localhost:8001Encara estic fora :-)$ curl localhost:8002Encara estic fora :-)
Certificats
Section titled “Certificats”Si no saps com funcionen els certificats mira aquesta activitat: {% link “/security/certificate/” %}
Apache
Section titled “Apache”Crea una carpeta server i dins de la carpeta baixa l’script apache.sh
: https://gitlab.com/xtec/smx-6/-/raw/main/certs/apache.sh.
$ curl https://gitlab.com/xtec/smx-6/-/raw/main/certs/apache.sh -o apache.sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 1570 100 1570 0 0 3363 0 --:--:-- --:--:-- --:--:-- 3369
Aquest script executa un servidor apache amb un certificat autofirmat en els ports 8080 (HTTP) i 8443 (HTTPS).
Atenció! L’script crea un contenidor amb el nom apache, i no pot haver cap contenidor amb aquest nom.
Executa l’script i mira el contingut que s’ha generat:
$ chmod u+x apache.sh$ ./apache.sh...a423ee4e93007fa64220b1e638d368c13fdcd55ee000325a4b4c90d2d5ed7b13$ lsapache.sh certs html httpd-ssl.conf httpd.conf site
En aquest cas, a més del lloc web en la carpeta html, tenim uns arxius de configuració externs al contenidor que es munten en punts concrets per modificar el comportament del servidor.
La carpeta certs
té els certificats, la carpeta html
el contingut, i httpd-ssl.conf
i httpd.conf
són fitxers de configuració.
I el que és més important, tenim agrupats els únics fitxers que són necessaris per configurar un apache amb connexió HTTPS on nosaltres volem.
Pots verificar que el servidor funciona correctament, amb redirecció del port 8080 (HTTP) al ports 8443 (HTTPS):
$ curl -I localhost:8080<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>307 Temporary Redirect</title></head><body><h1>Temporary Redirect</h1><p>The document has moved <a href="https://localhost:8443/">here</a>.</p></body></html>
Si mires les capçaleres HTTP pots veure que el servidor torna un resposta 307 Temporary Redirect
:
$ curl -I localhost:8080HTTP/1.1 307 Temporary RedirectDate: Tue, 21 May 2024 21:04:38 GMTServer: Apache/2.4.59 (Unix) OpenSSL/3.0.11Location: https://localhost:8443/Content-Type: text/html; charset=iso-8859-1
Executa curl
amb les opcions -L
(segueix el redirect) i -k
(no valida el certificat), i verifica que funciona:
$ curl -L -k localhost:8080<p>Add content to html folder</p>
Atura (stop) el contenidor apache.
Obre l’script apache.sh
, i mira que hi fa per entendre que hauries de fer tu manualment.
A continuació baixa aquest script que executa un servidor nginx amb un certificat autofirmat en els ports 8080 (HTTP) i 8443 (HTTPS): https://gitlab.com/xtec/smx-6/-/raw/main/certs/nginx.sh.
Executa l’script.
Si fas un ls
pots veure que l’única diferència que hi ha respecte apache, és que nginx necessita el seu propi fitxer de configuració nginx.conf
, la resta és el mateix.
$ lsapache.sh certs html httpd-ssl.conf httpd.conf nginx.conf nginx.sh site
Pots verificar que funciona igual que apache:
$ curl -L -k localhost:8080<p>Add content to html folder</p>
D’aquesta manera tens separat el que és particular del que és genèrica.
Pots passar de nginx a apache en un moment.
Obre l’script nginx.sh
i mira que fa per entendre que hauries de fer tu manualment.
Còpies
Section titled “Còpies”Pots realitzar còpies del host al contenidor i a la inversa amb l’ordre docker cp
:
Crea un servidor web caddy amb un volum amb la mateixa ordre:
$ docker run --rm -d --name caddy -p 80:80 -v caddy-data:/data caddy19fdc78f78b9eeb8feee71ec9535676fc125fc89efcc744c546710c274d1882a$ docker volume ls | grep caddylocal caddy-data
Verifica que el servidor funciona:
$ curl -s localhost | head -n 10<!DOCTYPE html><html><head> <title>Caddy works!</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="icon" href="data:,"> <style> * { box-sizing: border-box;
Enlloc de muntar una carpeta o entra dins el servidor per modificar el fitxer index.html
podem crear un fitxer (si no el tinc creat) i copiar-lo al servidor:
$ echo "Hello Caddy!" > index.html$ docker cp index.html caddy:/usr/share/caddy/index.htmlSuccessfully copied 2.05kB to caddy:/usr/share/caddy/index.html$ curl localhostHello Caddy!
També es pot copiar del contenidor al servidor, i fer còpies recursives.
Volums
Section titled “Volums”Si vull copiar el contingut d’un volum, primer l’haig de montar en un contenidor.
Si el volum és local, pots accedir directament al directori amb sudo
, però els contenidors poden estar en altres dispositius mitjançant btrfs, ZFS, etc.
Per tant, has de muntar el volum en un contenidor.
Montem el volum wiki
en un contenidor alpine
:
$ docker run -d --rm --name wiki -v wiki-nature:/wiki alpine tail -f /dev/null8b56c20ad2b6badc5b33e8aeab28397ec280fcc41f5817aa21cec51a619fe304
Ja pots copiar del contenidor:
$ docker cp wiki:/wiki/data/pages/wiki .Successfully copied 29.7kB to /home/david/docker/.$ ls wikidokuwiki.txt syntax.txt welcome.txt
Referències
Section titled “Referències”El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.
©2022-2025 xtec.dev