Skip to content

Emmagatzematge

Si vols començar amb un entorn net, esborra-ho tot:

Terminal window
$ docker system prune
WARNING! 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” %}

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” %}

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:

Terminal window
$ sudo mkdir /var/fast
$ sudo chmod 777 /var/fast

Ara crea un sistema de fitxers tmpfs de 1024 MB i nom de dispositiu ramdisk:

Terminal window
$ sudo mount -t tmpfs -o size=1024m ramdisk /var/fast

Pots veure que la unitat ramdisk s’ha muntat correctament:

Terminal window
$ mount | grep ramdisk
ramdisk on /var/fast type tmpfs (rw,relatime,size=1048576k,inode64)

Prova de crear un fitxer, veuras que no notaras la diferencia:

Terminal window
$ 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.

Terminal window
$ sudo umount /var/fast
$ ls -l /var/fast/
total 0

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:

  1. ImageFS – Les imatges que s’han descarregat es munten en diferents punts del sistema de fitxers del contenidor.

  2. In-memory storage – Un disc RAM com el que hem vist abans

  3. Bind mounts – Un directori concret del host

  4. 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” %}

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:

Terminal window
$ 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:

Terminal window
$ docker exec -it apache bash
...$ echo "Hello!" > htdocs/index.html
...$ exit
exit
$ curl localhost
Hello!

Una altra opció és crear una carpeta www fora del contenidor amb un fitxer index.html i altre contingut.

Terminal window
$ mkdir www
$ echo "Bye!" > www/index.html

Eliminem el contenidor que està en execució:

Terminal window
$ docker stop apache
apache

Creem un contenidor nou montant el directori /usr/local/apache2/htdocs a la nostra carpeta www.

Terminal window
$ docker run --rm -d --name apache -p 80:80 --mount type=bind,source="$(pwd)"/www,target=/usr/local/apache2/htdocs httpd
9dacc8d3d17cd2a4347732ca785e4a8f57fe2031b3baaae96a3399c14c9985c9

Si fas un curl a localhost pots veure que ara respon amb el teu fitxer index.html no amb el del contenidor:

Terminal window
$ curl localhost
Bye!

Modifica el fitxer index.html i verifica que el servidor apache contesta amb el nou contingut:

Terminal window
$ echo "Patufet"> www/index.html
$ curl localhost
Patufet

Entra dins el contenidor, modifica el fitxer index.html, surt del contenidor i verifica que desde fora també s’ha modificat:

Terminal window
$ docker exec -it apache bash
...$ cat htdocs/index.html
Patufet
...$ echo "Patufet" > htdocs/index.html
...$ exit
$ cat www/index.html
Patufet

Amb l’ordre docker inspect pots verificar en la secció Mount que el muntatge d’enllaç s’ha creat correctament:

Terminal window
{% 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:

Terminal window
$ docker run --rm -d --name apache2 -p 8080:80 --mount type=bind,source="$(pwd)"/www,target=/usr/local/apache2/htdocs httpd
292f7b72277524fc656593b9504676e782e50e7d407eff6686155376ae699082
$ curl localhost:80
Patufet
$ curl localhost:8080
Patufet

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:

Terminal window
$ docker run --rm -d --name nginx -p 3000:80 --mount type=bind,source="$(pwd)"/www,target=/usr/share/nginx/html nginx
...
c1f360dbc7e2ca97ca74648441f6a62bcadaf029954dfb23bf63361993df0e4a
$ curl localhost:3000
Patufet

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:

Terminal window
{% raw %}$ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"{% endraw %}
CONTAINER ID NAMES PORTS
20c8ebb1885d nginx 0.0.0.0:3000->80/tcp, :::3000->80/tcp
292f7b722775 apache2 0.0.0.0:8080->80/tcp, :::8080->80/tcp
9dacc8d3d17c 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:

Terminal window
$ docker stop apache apache2 nginx
apache
apache2
nginx

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:

Terminal window
$ 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à:

Terminal window
$ docker stop memory
memory
$ docker start memory
memory
$ 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

{% 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:

Terminal window
$ docker volume create wiki-nature
wiki-nature
$ docker volume ls
DRIVER VOLUME NAME
local 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.

Terminal window
$ 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/.

  1. Edita la primera pàgina amb algun contingut.

  2. Para el contenidor (aquest s’eliminarà perquè has fet servir l’opció --rm)

Terminal window
$ docker stop wiki
wiki
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ad7832d4d2c8 alpine "/bin/sh" 24 minutes ago Up 20 minutes memory
  1. Pots verificar que les pàgines estan guardades al volum i no es perden.
Terminal window
$ sudo ls /var/lib/docker/volumes/wiki-nature/_data
  1. Si vols torna a veure o editar la wiki només has de tornar a arrencar un altre contenidor dokuwiki muntant el volum:
Terminal window
$ docker run --rm -d --name wiki -p 80:8080 --volume wiki-nature:/bitnami/dokuwiki bitnami/dokuwiki
c9794ef60a22dac1e2a35dce8cc1285b68b499a0b925d541c86e0d2d4dfcdb22

Pots veure que el contenidor té un ID diferent i que el contingut s’ha guardat:

{% image “dokuwiki2.png” %}

  1. Crea un volum wiki-football i genera contingut creant un contenidor.
Terminal window
$ docker volume create wiki-football
$ docker run --rm -d --name wiki-football -p 90:8080 --volume wiki-football:/bitnami/dokuwiki bitnami/dokuwiki
a12f77e9b2d9fcf93e1d0cc4502869386fad1fdad1656af15470a8ab3e1a1908

Pots veure que:

  1. Pots tenir dos dokuwiki funcionant a la vegada en ports diferents.

  2. 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).

Terminal window
{% raw %}$ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"{% endraw %}
CONTAINER ID NAMES PORTS
a12f77e9b2d9 wiki-football 8443/tcp, 0.0.0.0:90->8080/tcp, :::90->8080/tcp
c9794ef60a22 wiki 8443/tcp, 0.0.0.0:80->8080/tcp, :::80->8080/tcp
$ docker volume ls
DRIVER VOLUME NAME
local wiki-football
local wiki-nature

Com has vist abans pots veure tots els volums que tens en el sistema amb l’ordre docker volume ls:

Terminal window
$ docker volume ls
DRIVER VOLUME NAME
local wiki-football
local wiki-nature

Per suprimir un volum has d’executar l’ordre docker volume rm:

Terminal window
$ docker volume rm wiki-nature
Error response from daemon: remove wiki-nature: volume is in use - [c9794ef60a22dac1e2a35dce8cc1285b68b499a0b925d541c86e0d2d4dfcdb22]

Però primer has d’aturar el contenidor:

Terminal window
$ docker stop wiki
wiki
$ docker volume rm wiki-nature
wiki-nature

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:

Terminal window
$ docker run --rm -d --name apache -p 8000:80 httpd
ad5087500ed6abe77f6226bac5ef6693c8f71b8e2aaf3b0ce8e92a498417109a
$ 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:

Terminal window
$ docker exec -it apache bash
... $ echo "Hello World!" > htdocs/index.html
... $ exit
exit
$ curl localhost:8000
Hello 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:

Terminal window
$ docker stop apache
apache
$ curl localhost:8000
curl: (7) Failed to connect to localhost port 8000 after 0 ms: Connection refused

Crea el teu lloc web al host: site

Terminal window
$ 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:

Terminal window
$ docker run --rm -d --name apache -p 8000:80 --mount type=bind,src="$(pwd)"/site,dst=/usr/local/apache2/htdocs,readonly=true httpd
2cde52ea8c9087bd9fbee769696e447a022044b0cb3bd55b462a8605636a2e43
$ curl localhost:8000
Estic fora

Si modifiques el contingut del fitxer site/index.html del host el servidor respondrà amb el nou fitxer:

Terminal window
$ echo "Encara estic fora :-)" > site/index.html
$ curl localhost:8000
Encara 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.

Terminal window
$ 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.

Terminal window
$ 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.

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?

Terminal window
$ 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?

Terminal window
$ 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.

Terminal window
$ curl localhost:8000
Encara estic fora :-)
$ curl localhost:8001
Encara estic fora :-)
$ curl localhost:8002
Encara estic fora :-)

Si no saps com funcionen els certificats mira aquesta activitat: {% link “/security/certificate/” %}

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.

Terminal window
$ 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 Speed
100 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:

Terminal window
$ chmod u+x apache.sh
$ ./apache.sh
...
a423ee4e93007fa64220b1e638d368c13fdcd55ee000325a4b4c90d2d5ed7b13
$ ls
apache.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):

Terminal window
$ 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:

Terminal window
$ curl -I localhost:8080
HTTP/1.1 307 Temporary Redirect
Date: Tue, 21 May 2024 21:04:38 GMT
Server: Apache/2.4.59 (Unix) OpenSSL/3.0.11
Location: 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:

Terminal window
$ 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.

Terminal window
$ ls
apache.sh certs html httpd-ssl.conf httpd.conf nginx.conf nginx.sh site

Pots verificar que funciona igual que apache:

Terminal window
$ 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.

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:

Terminal window
$ docker run --rm -d --name caddy -p 80:80 -v caddy-data:/data caddy
19fdc78f78b9eeb8feee71ec9535676fc125fc89efcc744c546710c274d1882a
$ docker volume ls | grep caddy
local caddy-data

Verifica que el servidor funciona:

Terminal window
$ 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:

Terminal window
$ echo "Hello Caddy!" > index.html
$ docker cp index.html caddy:/usr/share/caddy/index.html
Successfully copied 2.05kB to caddy:/usr/share/caddy/index.html
$ curl localhost
Hello Caddy!

També es pot copiar del contenidor al servidor, i fer còpies recursives.

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:

Terminal window
$ docker run -d --rm --name wiki -v wiki-nature:/wiki alpine tail -f /dev/null
8b56c20ad2b6badc5b33e8aeab28397ec280fcc41f5817aa21cec51a619fe304

Ja pots copiar del contenidor:

Terminal window
$ docker cp wiki:/wiki/data/pages/wiki .
Successfully copied 29.7kB to /home/david/docker/.
$ ls wiki
dokuwiki.txt syntax.txt welcome.txt

El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.

©2022-2025 xtec.dev