# Volumi

Per impostazione predefinita, tutte le operazioni eseguite all'interno di un container Docker vengono scritte in un layer scrivibile del container stesso. Questo approccio presenta due principali limitazioni: innanzitutto, i dati scritti in questo layer vengono persi quando il container viene eliminato; inoltre, tali dati sono strettamente legati a uno specifico container, rendendone difficile lo spostamento o la condivisione dei dati con altri container.

Docker offre due soluzioni per garantire la persistenza dei dati:

- `bind mounts`: consentono uno scambio bidirezionale tra una cartella (o un file) definita sull'host e una cartella (o file) defina all'interno del container. Questa soluzione è particolarmente utile quando si desidera rendere disponibili all'interno del container risorse presenti sull'host, come file di configurazione. La sintassi, nel file `docker-compose.yml` é la seguente: `./config/nginx:/etc/nginx/conf.d`. Prima il percorso, relativo o assoluto, sull'host e poi il percorso assoluto nel container in cui questa directory deve essere montata. Opzionalmente, é possibile montare la cartella in sola lettura, utilizzando l'opzione `:ro`

- `volumi`: rappresentano il metodo migliore per garantire la **persistenza dei dati**. I volumi possono essere condivisi tra più container e offrono grande flessibilità, poiché non richiedono che il sistema host disponga di un path specifico da montare nel container. I volumi sono gestiti direttamente da Docker

I volumi, quando Docker è eseguito come utente root, sono mappati nella directory `/var/lib/docker/volumes`. Se Docker è eseguito in modalitá rootless, in `/home/user/.local/share/docker/volumes`, mentre con Podman sono localizzati in `/home/user/share/containers/storage/volumes`.

> Per migrare i dati su un altro host, basta semplicemente migrare il contenuto di queste directory e ricreare il volume associato.

La sintassi, come si vede dall'esempio, é leggermente diversa rispetto ai bind mounts:

```yml
services:
  mealie:
    image: ghcr.io/mealie-recipes/mealie:v1.11.0
    container_name: mealie
    restart: always
    ports:
        - "9925:9000"
    deploy:
      resources:
        limits:
          memory: 500M
    volumes:
      - mealie-data:/app/data/
    environment:
      # Set Backend ENV Variables Here
      ALLOW_SIGNUP: false
      PUID: 1000
      PGID: 1000
      TZ: Europe/Rome
      MAX_WORKERS: 1
      WEB_CONCURRENCY: 1
      BASE_URL: https://localhost

volumes:
  mealie-data:
```

## Comandi principali

Per creare un volume da associare successivamente a uno o più container, è disponibile il comando `docker volume create`. Questo comando genera un **volume anonimo**, identificato da un hash alfanumerico generato da Docker. Per creare un volume con un nome specifico, si utilizza il comando `docker volume create volume_name`.

I volumi sono entità indipendenti che possono esistere anche senza essere associati a un container.

A meno che non siano implementati limiti di quota, il volume crescerà in dimensione all'aumentare dei dati contenuti.

### Elencare i volumi

Per visualizzare l'elenco dei volumi esistenti, esiste il comando `docker volume ls`.

### Rimuovere i volumi

Per rimuovere **tutti i volumi anonimi non in uso da alcun container**, si utilizza il comando `docker volume prune`. Per eliminare tutti i volumi inutilizzati, si può utilizzare `docker volume prune -a`.

### Ispezionare i volumi

Per ispezionare un volume specifico, si utilizza il comando `docker volume inspect <volume_name>` oppure `docker volume inspect <hash>`.

L'associazione tra il volume e il container che lo utilizza non è registrata nel volume stesso, ma nel container. In altre parole, il volume non riporta i suoi utilizzatori; sono i container a registrare il volume che utilizzano. Pertanto, per trovare l'associazione, si può utilizzare il comando `docker inspect <container_name>`.

## Copiare i dati

Docker utilizza un `filesystem overlay2` per gestire i layer dei container. Questo filesystem permette di sovrapporre più layer, consentendo di mantenere un layer di base immutabile e di applicare modifiche in layer superiori. Quando un container viene avviato, Docker crea una directory chiamata `UpperDir`. Questa directory contiene tutte le modifiche apportate al filesystem del container rispetto al layer di base. In altre parole, qualsiasi file creato, modificato o eliminato all'interno del container sarà registrato in UpperDir. In particolare, all'interno di UpperDir, c'è una directory chiamata `diff` che contiene tutte le differenze rispetto al layer di base. Ad esempio, se si crea un nuovo file all'interno del container, questo file sarà presente nella directory diff di UpperDir. Pertanto, i file creati sono sempre disponibili in tale percorso.

- `LowerDir`: rappresenta i layer sottostanti, che contengono i dati originali dell'immagine. Questi layer non possono essere modificati direttamente; invece, le modifiche vengono registrate nel layer superiore `UpperDir`
- `MergedDir`: è la vista combinata di tutti i layer, che consente di visualizzare i file come se fossero in un'unica directory. Questo è ciò che gli utenti vedono quando accedono al filesystem del container
- `WorkDir`: è una directory temporanea utilizzata da OverlayFS per gestire le operazioni di unione dei file

```txt
root@laptop:~# docker run --rm -it -d --name ubuntu ubuntu
82b1eaab3995a3e5c7c482e41dbc4c80a291521fe6712e1b9ba6f8ed867e2afc
root@laptop:~# docker exec -it ubuntu bash
root@82b1eaab3995:/# touch LEGGIMI.txt
root@82b1eaab3995:/# exit
```

Successivamente, è possibile ispezionare il container per ottenere informazioni dettagliate sulla sua configurazione e sui suoi mountpoint:

```bash
root@dadopc:~# docker container inspect ubuntu

[...]
        "GraphDriver": {
            "Data": {
                "ID": "82b1eaab3995a3e5c7c482e41dbc4c80a291521fe6712e1b9ba6f8ed867e2afc",
                "LowerDir": "/var/lib/docker/overlay2/c3da0b1ac3995e0ed4103ffa7137361dd07a4e40a1979f0e3e0f083a05da6416-init/diff:/var/lib/docker/overlay2/fcdf120da8d033d61a0c71068494bfe8ef0d70e989c7264aab6ea2ddf3fe4870/diff",
                "MergedDir": "/var/lib/docker/overlay2/c3da0b1ac3995e0ed4103ffa7137361dd07a4e40a1979f0e3e0f083a05da6416/merged",
                "UpperDir": "/var/lib/docker/overlay2/c3da0b1ac3995e0ed4103ffa7137361dd07a4e40a1979f0e3e0f083a05da6416/diff",
                "WorkDir": "/var/lib/docker/overlay2/c3da0b1ac3995e0ed4103ffa7137361dd07a4e40a1979f0e3e0f083a05da6416/work"
            },
            "Name": "overlay2"
```

Il comando `ls` può essere utilizzato per visualizzare il contenuto della directory `diff`, dove sono memorizzati i file creati all'interno del container.

```bash
root@laptop:~# ls -lh /var/lib/docker/overlay2/c3da0b1ac3995e0ed4103ffa7137361dd07a4e40a1979f0e3e0f083a05da6416/diff
total 0
-rw-r--r-- 1 root root  0 Jul 31 20:45 LEGGIMI.txt
drwx------ 1 root root 26 Jul 31 20:45 root
```

In alternativa, è possibile utilizzare il comando `docker cp` per copiare i dati da e verso un container. È necessario fornire due argomenti: il percorso sorgente all'interno del container e il percorso di destinazione nel filesystem locale (o viceversa).

```bash
root@laptop:~# docker cp ubuntu:/LEGGIMI.txt .
```
