# Controlador de almacenamiento Device Mapper (obsoleto)


> **Obsoleto (Deprecated)**
>
> El controlador Device Mapper [está obsoleto](/engine/deprecated/#device-mapper-storage-driver)
> y se ha eliminado en Docker Engine v25.0. Si estás utilizando Device Mapper,
> debes migrar a un controlador de almacenamiento compatible antes de actualizar a Docker
> Engine v25.0. Lee la página de [controladores de almacenamiento de Docker](/engine/storage/drivers/device-mapper-driver/select-storage-driver/)
> para conocer los controladores compatibles.

Device Mapper es un marco de trabajo basado en el kernel que respalda muchas tecnologías avanzadas de gestión de volúmenes en Linux. El controlador de almacenamiento `devicemapper` de Docker aprovecha las capacidades de aprovisionamiento dinámico (thin provisioning) y snapshots de este marco para la gestión de imágenes y contenedores. Este artículo se refiere al controlador de almacenamiento de Device Mapper como `devicemapper` y al marco del kernel como _Device Mapper_.

Para los sistemas en los que es compatible, el soporte de `devicemapper` está incluido en el kernel Linux. Sin embargo, se requiere una configuración específica para utilizarlo con Docker.

El controlador `devicemapper` utiliza dispositivos de bloque dedicados a Docker y opera a nivel de bloque, en lugar de a nivel de archivo. Estos dispositivos se pueden ampliar añadiendo almacenamiento físico a tu host Docker, y ofrecen un mejor rendimiento que el uso de un sistema de archivos a nivel del sistema operativo (OS).

## Requisitos previos

- `devicemapper` es compatible con Docker Engine - Community en CentOS, Fedora, SLES 15, Ubuntu, Debian o RHEL.
- `devicemapper` requiere que los paquetes `lvm2` y `device-mapper-persistent-data` estén instalados.
- Cambiar el controlador de almacenamiento hace que los contenedores que ya hayas creado dejen de estar accesibles en el sistema local. Usa `docker save` para guardar los contenedores y envía las imágenes existentes a Docker Hub o a un registro privado para que no tengas que volver a crearlas más tarde.

## Configurar Docker con el controlador de almacenamiento `devicemapper`

Antes de seguir estos procedimientos, primero debes cumplir con todos los [requisitos previos](#requisitos-previos).

### Configurar el modo `loop-lvm` para pruebas

Esta configuración solo es adecuada para pruebas. El modo `loop-lvm` utiliza un mecanismo de bucle de retorno o 'loopback' que permite leer y escribir en archivos del disco local como si fueran un disco físico o dispositivo de bloques real.

Sin embargo, la adición del mecanismo loopback y la interacción con la capa del sistema de archivos del sistema operativo implican que las operaciones de E/S pueden ser lentas y consumir muchos recursos. El uso de dispositivos loopback también puede introducir condiciones de carrera.

No obstante, la configuración del modo `loop-lvm` puede ayudar a identificar problemas básicos (como la falta de paquetes en el espacio de usuario, controladores del kernel, etc.) antes de intentar la configuración más compleja requerida para habilitar el modo `direct-lvm`. Por lo tanto, el modo `loop-lvm` solo debe usarse para realizar pruebas básicas antes de configurar `direct-lvm`.

Para sistemas de producción, consulta [Configurar el modo direct-lvm para producción](#configurar-el-modo-direct-lvm-para-produccion).

1. Detén Docker.

   ```console
   $ sudo systemctl stop docker
   ```

2. Edita `/etc/docker/daemon.json`. Si aún no existe, créalo. Suponiendo que el archivo estuviera vacío, añade el siguiente contenido.

   ```json
   {
     "storage-driver": "devicemapper"
   }
   ```

   Consulta todas las opciones de almacenamiento para cada controlador en la [documentación de referencia del demonio](/reference/cli/dockerd/#options-per-storage-driver)

   Docker no se iniciará si el archivo `daemon.json` contiene un JSON mal formado.

3. Inicia Docker.

   ```console
   $ sudo systemctl start docker
   ```

4. Verifica que el demonio esté utilizando el controlador de almacenamiento `devicemapper`. Usa el comando `docker info` y busca `Storage Driver`.

   ```console
   $ docker info

     Containers: 0
       Running: 0
       Paused: 0
       Stopped: 0
     Images: 0
     Server Version: 17.03.1-ce
     Storage Driver: devicemapper
     Pool Name: docker-202:1-8413957-pool
     Pool Blocksize: 65.54 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file: /dev/loop0
     Metadata file: /dev/loop1
     Data Space Used: 11.8 MB
     Data Space Total: 107.4 GB
     Data Space Available: 7.44 GB
     Metadata Space Used: 581.6 KB
     Metadata Space Total: 2.147 GB
     Metadata Space Available: 2.147 GB
     Thin Pool Minimum Free Space: 10.74 GB
     Udev Sync Supported: true
     Deferred Removal Enabled: false
     Deferred Deletion Enabled: false
     Deferred Deleted Device Count: 0
     Data loop file: /var/lib/docker/devicemapper/data
     Metadata loop file: /var/lib/docker/devicemapper/metadata
     Library Version: 1.02.135-RHEL7 (2016-11-16)
   <...>
   ```

   Este host se está ejecutando en modo `loop-lvm`, el cual **no** es compatible con sistemas de producción. Esto se indica por el hecho de que `Data loop file` y `Metadata loop file` son archivos ubicados bajo `/var/lib/docker/devicemapper`. Estos son archivos dispersos (sparse files) montados en loopback. Para sistemas de producción, consulta [Configurar el modo direct-lvm para producción](#configurar-el-modo-direct-lvm-para-produccion).


### Configurar el modo direct-lvm para producción

Los hosts de producción que utilizan el controlador de almacenamiento `devicemapper` deben usar el modo `direct-lvm`. Este modo utiliza dispositivos de bloque para crear el thin pool. Esto es más rápido que usar dispositivos loopback, utiliza los recursos del sistema de manera más eficiente y los dispositivos de bloque pueden crecer según sea necesario. Sin embargo, requiere más configuración que el modo `loop-lvm`.

Una vez que hayas cumplido con los [requisitos previos](#requisitos-previos), sigue los pasos a continuación para configurar Docker para usar el controlador de almacenamiento `devicemapper` en modo `direct-lvm`.

> [!WARNING]
> Cambiar el controlador de almacenamiento hace que los contenedores que ya hayas creado dejen
> de estar accesibles en el sistema local. Usa `docker save` para guardar los contenedores y
> envía las imágenes existentes a Docker Hub o a un registro privado para que no tengas que
> volver a crearlas más tarde.

#### Permitir que Docker configure el modo direct-lvm

Docker puede gestionar el dispositivo de bloques por ti, simplificando la configuración del modo `direct-lvm`. **Esto es adecuado únicamente para instalaciones nuevas de Docker.** Solo puedes utilizar un único dispositivo de bloques. Si necesitas utilizar varios dispositivos de bloques, debes [configurar el modo direct-lvm manualmente](#configurar-el-modo-direct-lvm-manualmente) en su lugar. Las siguientes opciones de configuración están disponibles:

| Opción                          | Descripción                                                                                                                                                                        | ¿Requerido? | Predeterminado | Ejemplo                            |
|:--------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------|:---------------|:-----------------------------------|
| `dm.directlvm_device`           | La ruta al dispositivo de bloques a configurar para `direct-lvm`.                                                                                                                  | Sí          |                | `dm.directlvm_device="/dev/xvdf"`  |
| `dm.thinp_percent`              | El porcentaje de espacio a utilizar para almacenamiento a partir del dispositivo de bloques proporcionado.                                                                         | No          | 95             | `dm.thinp_percent=95`              |
| `dm.thinp_metapercent`          | El porcentaje de espacio a utilizar para el almacenamiento de metadatos a partir del dispositivo de bloques proporcionado.                                                         | No          | 1              | `dm.thinp_metapercent=1`           |
| `dm.thinp_autoextend_threshold` | El umbral en el que lvm debería extender automáticamente el thin pool, expresado como porcentaje del espacio de almacenamiento total.                                              | No          | 80             | `dm.thinp_autoextend_threshold=80` |
| `dm.thinp_autoextend_percent`   | El porcentaje en el que se debe incrementar el thin pool cuando se activa una extensión automática (autoextend).                                                                   | No          | 20             | `dm.thinp_autoextend_percent=20`   |
| `dm.directlvm_device_force`     | Si se debe formatear el dispositivo de bloques incluso si ya existe un sistema de archivos en él. Si se establece en `false` y hay un sistema de archivos presente, se registra un error y el sistema de archivos se deja intacto. | No          | false          | `dm.directlvm_device_force=true`   |

Edita el archivo `daemon.json` y establece las opciones correspondientes, luego reinicia Docker para que los cambios surtan efecto. La siguiente configuración de `daemon.json` establece todas las opciones de la tabla anterior.

```json
{
  "storage-driver": "devicemapper",
  "storage-opts": [
    "dm.directlvm_device=/dev/xdf",
    "dm.thinp_percent=95",
    "dm.thinp_metapercent=1",
    "dm.thinp_autoextend_threshold=80",
    "dm.thinp_autoextend_percent=20",
    "dm.directlvm_device_force=false"
  ]
}
```

Consulta todas las opciones de almacenamiento para cada controlador en la [documentación de referencia del demonio](/reference/cli/dockerd/#options-per-storage-driver)

Reinicia Docker para que los cambios surtan efecto. Docker invoca los comandos para configurar el dispositivo de bloques por ti.

> [!WARNING]
> Cambiar estos valores después de que Docker haya preparado el dispositivo de bloques por ti
> no está admitido y provocará un error.

Aún necesitas [realizar tareas de mantenimiento periódicas](#gestionar-devicemapper).

#### Configurar el modo direct-lvm manualmente

El procedimiento a continuación crea un volumen lógico configurado como un thin pool para usarlo como respaldo para el grupo de almacenamiento. Asume que tienes un dispositivo de bloques libre en `/dev/xvdf` con suficiente espacio disponible para completar la tarea. El identificador del dispositivo y los tamaños de los volúmenes pueden variar en tu entorno, por lo que debes sustituir tus propios valores a lo largo del procedimiento. El procedimiento también asume que el demonio de Docker está en estado detenido (`stopped`).

1.  Identifica el dispositivo de bloques que deseas utilizar. El dispositivo se encuentra bajo `/dev/` (como `/dev/xvdf`) y necesita suficiente espacio libre para almacenar las imágenes y las capas de los contenedores para las cargas de trabajo que ejecuta ese host. Una unidad de estado sólido (SSD) es ideal.

2.  Detén Docker.

    ```console
    $ sudo systemctl stop docker
    ```

3.  Instala los siguientes paquetes:

    - **RHEL / CentOS**: `device-mapper-persistent-data`, `lvm2` y todas las dependencias

    - **Ubuntu / Debian / SLES 15**: `thin-provisioning-tools`, `lvm2` y todas las dependencias

4.  Crea un volumen físico en tu dispositivo de bloques del paso 1, utilizando el comando `pvcreate`. Sustituye el nombre de tu dispositivo en lugar de `/dev/xvdf`.

    > [!WARNING]
    > Los siguientes pasos son destructivos, por lo que debes asegurarte de haber especificado el dispositivo correcto.

    ```console
    $ sudo pvcreate /dev/xvdf

    Physical volume "/dev/xvdf" successfully created.
    ```

5.  Crea un grupo de volúmenes llamado `docker` en el mismo dispositivo, utilizando el comando `vgcreate`.

    ```console
    $ sudo vgcreate docker /dev/xvdf

    Volume group "docker" successfully created
    ```

6.  Crea dos volúmenes lógicos llamados `thinpool` y `thinpoolmeta` usando el comando `lvcreate`. El último parámetro especifica la cantidad de espacio libre permitido para la expansión automática de los datos o metadatos si el espacio escasea, como una medida de contención temporal. Estos son los valores recomendados.

    ```console
    $ sudo lvcreate --wipesignatures y -n thinpool docker -l 95%VG

    Logical volume "thinpool" created.

    $ sudo lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG

    Logical volume "thinpoolmeta" created.
    ```

7.  Convierte los volúmenes en un thin pool y en una ubicación de almacenamiento de metadatos para el thin pool, utilizando el comando `lvconvert`.

    ```console
    $ sudo lvconvert -y \
    --zero n \
    -c 512K \
    --thinpool docker/thinpool \
    --poolmetadata docker/thinpoolmeta

    WARNING: Converting logical volume docker/thinpool and docker/thinpoolmeta to
    thin pool's data and metadata volumes with metadata wiping.
    THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)
    Converted docker/thinpool to thin pool.
    ```

8.  Configura la autoextensión de los thin pools a través de un perfil de `lvm`.

    ```console
    $ sudo vi /etc/lvm/profile/docker-thinpool.profile
    ```

9.  Especifica los valores de `thin_pool_autoextend_threshold` y `thin_pool_autoextend_percent`.

    `thin_pool_autoextend_threshold` es el porcentaje de espacio utilizado antes de que `lvm` intente extender automáticamente el espacio disponible (100 = deshabilitado, no recomendado).

    `thin_pool_autoextend_percent` es la cantidad de espacio a añadir al dispositivo al extenderse automáticamente (0 = deshabilitado).

    El siguiente ejemplo añade un 20% más de capacidad cuando el uso del disco alcanza el 80%.

    ```text
    activation {
      thin_pool_autoextend_threshold=80
      thin_pool_autoextend_percent=20
    }
    ```

    Guarda el archivo.

10. Aplica el perfil de LVM utilizando el comando `lvchange`.

    ```console
    $ sudo lvchange --metadataprofile docker-thinpool docker/thinpool

    Logical volume docker/thinpool changed.
    ```

11. Asegúrate de que el monitoreo del volumen lógico esté habilitado.

    ```console
    $ sudo lvs -o+seg_monitor

    LV       VG     Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor
    thinpool docker twi-a-t--- 95.00g             0.00   0.01                             not monitored
    ```

    Si la salida en la columna `Monitor` indica, como se muestra arriba, que el volumen `not monitored` (no está monitoreado), entonces el monitoreo debe habilitarse explícitamente. Sin este paso, la extensión automática del volumen lógico no se llevará a cabo, independientemente de la configuración del perfil aplicado.

    ```console
    $ sudo lvchange --monitor y docker/thinpool
    ```

    Verifica de nuevo que el monitoreo esté habilitado ejecutando el comando `sudo lvs -o+seg_monitor` por segunda vez. La columna `Monitor` ahora debería indicar que el volumen lógico está siendo monitoreado (`monitored`).

12. Si alguna vez has ejecutado Docker en este host antes, o si `/var/lib/docker/` existe, muévelo a otra ubicación para que Docker pueda utilizar el nuevo pool de LVM para almacenar el contenido de las imágenes y los contenedores.

    ```console
    $ sudo su -
    # mkdir /var/lib/docker.bk
    # mv /var/lib/docker/* /var/lib/docker.bk
    # exit
    ```

    Si alguno de los siguientes pasos falla y necesitas restaurar la configuración anterior, puedes eliminar `/var/lib/docker` y reemplazarlo por `/var/lib/docker.bk`.

13. Edita `/etc/docker/daemon.json` y configura las opciones necesarias para el controlador de almacenamiento `devicemapper`. Si el archivo estaba vacío previamente, ahora debería contener el siguiente contenido:

    ```json
    {
        "storage-driver": "devicemapper",
        "storage-opts": [
        "dm.thinpooldev=/dev/mapper/docker-thinpool",
        "dm.use_deferred_removal=true",
        "dm.use_deferred_deletion=true"
        ]
    }
    ```

14. Inicia Docker.

    **systemd**:

    ```console
    $ sudo systemctl start docker
    ```

    **service**:

    ```console
    $ sudo service docker start
    ```

15. Verifica que Docker esté utilizando la nueva configuración mediante `docker info`.

    ```console
    $ docker info

    Containers: 0
     Running: 0
     Paused: 0
     Stopped: 0
    Images: 0
    Server Version: 17.03.1-ce
    Storage Driver: devicemapper
     Pool Name: docker-thinpool
     Pool Blocksize: 524.3 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file:
     Metadata file:
     Data Space Used: 19.92 MB
     Data Space Total: 102 GB
     Data Space Available: 102 GB
     Metadata Space Used: 147.5 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
     Thin Pool Minimum Free Space: 10.2 GB
     Udev Sync Supported: true
     Deferred Removal Enabled: true
     Deferred Deletion Enabled: true
     Deferred Deleted Device Count: 0
     Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    ```

    Si Docker está configurado correctamente, `Data file` y `Metadata file` estarán vacíos, y el nombre del pool será `docker-thinpool`.

16. Una vez que hayas verificado que la configuración es correcta, puedes eliminar el directorio `/var/lib/docker.bk` que contiene la configuración anterior.

    ```console
    $ sudo rm -rf /var/lib/docker.bk
    ```

## Gestionar devicemapper

### Monitorear el thin pool

No dependas únicamente de la autoextensión de LVM. El grupo de volúmenes se extiende automáticamente, pero el volumen aún puede llenarse. Puedes monitorear el espacio libre en el volumen utilizando `lvs` o `lvs -a`. Considera utilizar una herramienta de monitoreo a nivel del sistema operativo, como Nagios.

Para ver los registros (logs) de LVM, puedes utilizar `journalctl`:

```console
$ sudo journalctl -fu dm-event.service
```

Si te encuentras con problemas recurrentes con el thin pool, puedes establecer la opción de almacenamiento `dm.min_free_space` a un valor (que representa un porcentaje) en `/etc/docker/daemon.json`. Por ejemplo, establecerlo en `10` garantiza que las operaciones fallen con una advertencia cuando el espacio libre esté en el 10% o menos. Consulta las [opciones del controlador de almacenamiento en la referencia del demonio de Engine](/reference/cli/dockerd/#daemon-storage-driver).

### Incrementar la capacidad en un dispositivo en ejecución

Puedes incrementar la capacidad del pool en un dispositivo thin-pool en ejecución. Esto es útil si el volumen lógico de datos está lleno y el grupo de volúmenes está a su máxima capacidad. El procedimiento específico depende de si estás utilizando un [thin pool loop-lvm](#redimensionar-un-thin-pool-loop-lvm) o un [thin pool direct-lvm](#redimensionar-un-thin-pool-direct-lvm).

#### Redimensionar un thin pool loop-lvm

Para redimensionar un thin pool `loop-lvm`, puedes [utilizar la utilidad device_tool](#utilizar-la-utilidad-device_tool) o, en su lugar, [utilizar las utilidades del sistema operativo](#utilizar-las-utilidades-del-sistema-operativo).

##### Utilizar la utilidad device_tool

Un script aportado por la comunidad llamado `device_tool.go` está disponible en el repositorio de GitHub [moby/moby](https://github.com/moby/moby/tree/master/contrib/docker-device-tool). Puedes usar esta herramienta para redimensionar un thin pool `loop-lvm`, evitando el largo proceso mencionado anteriormente. No se garantiza el funcionamiento de esta herramienta, pero de cualquier forma solo deberías usar `loop-lvm` en sistemas que no sean de producción.

Si no deseas utilizar `device_tool`, puedes [redimensionar el thin pool manualmente](#utilizar-las-utilidades-del-sistema-operativo) en su lugar.

1.  Para usar la herramienta, clona el repositorio de GitHub, accede a `contrib/docker-device-tool` y sigue las instrucciones en el `README.md` para compilar la herramienta.

2.  Utiliza la herramienta. El siguiente ejemplo redimensiona el thin pool a 200GB.

    ```console
    $ ./device_tool resize 200GB
    ```

##### Utilizar las utilidades del sistema operativo

Si no deseas [utilizar la utilidad device_tool](#utilizar-la-utilidad-device-tool), puedes redimensionar un thin pool `loop-lvm` manualmente siguiendo este procedimiento.

En el modo `loop-lvm`, se utiliza un dispositivo loopback para almacenar los datos y otro para almacenar los metadatos. El modo `loop-lvm` solo se admite para pruebas debido a que presenta importantes inconvenientes de rendimiento y estabilidad.

Si estás utilizando el modo `loop-lvm`, la salida de `docker info` muestra las rutas de los archivos para `Data loop file` y `Metadata loop file`:

```console
$ docker info |grep 'loop file'

 Data loop file: /var/lib/docker/devicemapper/data
 Metadata loop file: /var/lib/docker/devicemapper/metadata
```

Sigue estos pasos para aumentar el tamaño del thin pool. En este ejemplo, the thin pool es de 100 GB y se incrementa a 200 GB.

1.  Lista los tamaños de los dispositivos.

    ```console
    $ sudo ls -lh /var/lib/docker/devicemapper/

    total 1175492
    -rw------- 1 root root 100G Mar 30 05:22 data
    -rw------- 1 root root 2.0G Mar 31 11:17 metadata
    ```

2.  Aumenta el tamaño del archivo `data` a 200 GB utilizando el comando `truncate`, el cual sirve para aumentar **o** disminuir el tamaño de un archivo. Ten en cuenta que disminuir el tamaño es una operación destructiva.

    ```console
    $ sudo truncate -s 200G /var/lib/docker/devicemapper/data
    ```

3.  Verifica que el tamaño del archivo haya cambiado.

    ```console
    $ sudo ls -lh /var/lib/docker/devicemapper/

    total 1.2G
    -rw------- 1 root root 200G Apr 14 08:47 data
    -rw------- 1 root root 2.0G Apr 19 13:27 metadata
    ```

4.  El archivo loopback ha cambiado en disco pero no en memoria. Lista el tamaño del dispositivo loopback en memoria, en GB. Recárgalo y luego vuelve a listar el tamaño. Después de la recarga, el tamaño es de 200 GB.

    ```console
    $ echo $[ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 ]

    100

    $ sudo losetup -c /dev/loop0

    $ echo $[ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 ]

    200
    ```

5.  Recarga el thin pool de devicemapper.

    a. Obtén primero el nombre del pool. El nombre del pool es el primer campo, delimitado por `:`. Este comando lo extrae.

    ```console
    $ sudo dmsetup status | grep ' thin-pool ' | awk -F ': ' {'print $1'}
    docker-8:1-123141-pool
    ```

    b. Vuelca la tabla de device mapper para el thin pool.

    ```console
    $ sudo dmsetup table docker-8:1-123141-pool
    0 209715200 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing
    ```

    c. Calcula los sectores totales del thin pool utilizando el segundo campo de la salida. El número se expresa en sectores de 512 bytes. Un archivo de 100 GB tiene 209715200 sectores de 512 bytes. Si duplicas este número a 200 GB, obtienes 419430400 sectores de 512 bytes.

    d. Recarga el thin pool con el nuevo número de sectores utilizando los siguientes tres comandos `dmsetup`.

    ```console
    $ sudo dmsetup suspend docker-8:1-123141-pool
    $ sudo dmsetup reload docker-8:1-123141-pool --table '0 419430400 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing'
    $ sudo dmsetup resume docker-8:1-123141-pool
    ```

#### Redimensionar un thin pool direct-lvm

Para extender un thin pool `direct-lvm`, primero debes conectar un nuevo dispositivo de bloques al host Docker y tomar nota del nombre que el kernel le asigne. En este ejemplo, el nuevo dispositivo de bloques es `/dev/xvdg`.

Sigue este procedimiento para extender un thin pool `direct-lvm`, sustituyendo tu dispositivo de bloques y otros parámetros para adaptarlos a tu situación.

1.  Recopila información sobre tu grupo de volúmenes.

    Usa el comando `pvdisplay` para encontrar los dispositivos de bloque físico actualmente en uso por tu thin pool, y el nombre del grupo de volúmenes.

    ```console
    $ sudo pvdisplay |grep 'VG Name'

    PV Name               /dev/xvdf
    VG Name               docker
    ```

    En los siguientes pasos, sustituye el nombre de tu dispositivo de bloques o grupo de volúmenes según corresponda.

2.  Extiende el grupo de volúmenes utilizando el comando `vgextend` con el `VG Name` del paso anterior y el nombre de tu **nuevo** dispositivo de bloques.

    ```console
    $ sudo vgextend docker /dev/xvdg

    Physical volume "/dev/xvdg" successfully created.
    Volume group "docker" successfully extended
    ```

3.  Extiende el volumen lógico `docker/thinpool`. Este comando utiliza el 100% del volumen de inmediato, sin autoextensión. Para extender el thinpool de metadatos en su lugar, utiliza `docker/thinpool_tmeta`.

    ```console
    $ sudo lvextend -l+100%FREE -n docker/thinpool

    Size of logical volume docker/thinpool_tdata changed from 95.00 GiB (24319 extents) to 198.00 GiB (50688 extents).
    Logical volume docker/thinpool_tdata successfully resized.
    ```

4.  Verifica el nuevo tamaño del thin pool utilizando el campo `Data Space Available` en la salida de `docker info`. Si en su lugar extendiste el volumen lógico `docker/thinpool_tmeta`, busca `Metadata Space Available`.

    ```bash
    Storage Driver: devicemapper
     Pool Name: docker-thinpool
     Pool Blocksize: 524.3 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file:
     Metadata file:
     Data Space Used: 212.3 MB
     Data Space Total: 212.6 GB
     Data Space Available: 212.4 GB
     Metadata Space Used: 286.7 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
    <...>
    ```

### Activar `devicemapper` después de reiniciar

Si reinicias el host y descubres que el servicio `docker` no se pudo iniciar, busca el error "Non existing device". Necesitas reactivar los volúmenes lógicos con este comando:

```console
$ sudo lvchange -ay docker/thinpool
```

## Cómo funciona el controlador de almacenamiento `devicemapper`

> [!WARNING]
> No manipules directamente ningún archivo o directorio dentro de
> `/var/lib/docker/`. Docker se encarga de gestionar estos archivos y directorios.

Usa el comando `lsblk` para ver los dispositivos y sus pools desde el punto de vista del sistema operativo:

```console
$ sudo lsblk

NAME                    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                    202:0    0    8G  0 disk
└─xvda1                 202:1    0    8G  0 part /
xvdf                    202:80   0  100G  0 disk
├─docker-thinpool_tmeta 253:0    0 1020M  0 lvm
│ └─docker-thinpool     253:2    0   95G  0 lvm
└─docker-thinpool_tdata 253:1    0   95G  0 lvm
  └─docker-thinpool     253:2    0   95G  0 lvm
```

Usa el comando `mount` para ver el punto de montaje que está utilizando Docker:

```console
$ mount |grep devicemapper
/dev/xvda1 on /var/lib/docker/devicemapper type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
```

Cuando utilizas `devicemapper`, Docker almacena el contenido de las imágenes y capas en el thinpool, y lo expone a los contenedores montándolo en subdirectorios de `/var/lib/docker/devicemapper/`.

### Capas de imágenes y contenedores en disco

El directorio `/var/lib/docker/devicemapper/metadata/` contiene metadatos sobre la propia configuración de Devicemapper y sobre cada capa de imagen y contenedor existente. El controlador de almacenamiento `devicemapper` utiliza snapshots, y estos metadatos incluyen información sobre dichos snapshots. Estos archivos están en formato JSON.

El directorio `/var/lib/docker/devicemapper/mnt/` contiene un punto de montaje para cada capa de imagen y contenedor existente. Los puntos de montaje de las capas de imagen están vacíos, pero el punto de montaje de un contenedor muestra el sistema de archivos del contenedor tal como aparece desde dentro de este.


### Capas de imágenes y uso compartido

El controlador de almacenamiento `devicemapper` utiliza dispositivos de bloque dedicados en lugar de sistemas de archivos formateados, y opera en los archivos a nivel de bloque para obtener el máximo rendimiento durante las operaciones copy-on-write (CoW).

#### Snapshots

Otra característica de `devicemapper` es el uso de snapshots (a veces también llamados _dispositivos dinámicos_ o _dispositivos virtuales_), que almacenan las diferencias introducidas en cada capa como thin pools muy pequeños y ligeros. Los snapshots ofrecen muchos beneficios:

- Las capas comunes compartidas entre contenedores se almacenan en el disco una sola vez, a menos que sean de escritura. Por ejemplo, si tienes 10 imágenes diferentes basadas en `alpine`, la imagen `alpine` y todas sus imágenes padre se almacenan una sola vez cada una en el disco.

- Los snapshots son una implementación de la estrategia copy-on-write (CoW). Esto significa que un archivo o directorio determinado solo se copia a la capa de escritura del contenedor cuando ese contenedor lo modifica o lo elimina.

- Debido a que `devicemapper` opera a nivel de bloque, se pueden modificar múltiples bloques en una capa de escritura de forma simultánea.

- Se pueden realizar copias de seguridad de los snapshots utilizando utilidades estándar a nivel del sistema operativo. Basta con hacer una copia de `/var/lib/docker/devicemapper/`.

#### Flujo de trabajo de Devicemapper

Cuando inicias Docker con el controlador de almacenamiento `devicemapper`, todos los objetos relacionados con las capas de imágenes y contenedores se almacenan en `/var/lib/docker/devicemapper/`, que está respaldado por uno o más dispositivos a nivel de bloque, ya sean dispositivos loopback (solo para pruebas) o discos físicos.

- El _dispositivo base_ (base device) es el objeto de nivel más bajo. Este es el propio thin pool. Puedes examinarlo mediante `docker info`. Contiene un sistema de archivos. Este dispositivo base es el punto de partida para cada capa de imagen y contenedor. El dispositivo base es un detalle de implementación de Device Mapper, no una capa de Docker.

- Los metadatos sobre el dispositivo base y cada capa de imagen o contenedor se almacenan en `/var/lib/docker/devicemapper/metadata/` en formato JSON. Estas capas son snapshots copy-on-write, lo que significa que están vacías hasta que divergen de sus capas padres.

- La capa de escritura de cada contenedor se monta en un punto de montaje en `/var/lib/docker/devicemapper/mnt/`. Existe un directorio vacío para cada capa de imagen de solo lectura y cada contenedor detenido.

Cada capa de imagen es un snapshot de la capa inferior. La capa más baja de cada imagen es un snapshot del dispositivo base que existe en el pool. Al ejecutar un contenedor, este es un snapshot de la imagen en la que se basa. El siguiente ejemplo muestra un host Docker con dos contenedores en ejecución. El primero es un contenedor `ubuntu` y el segundo es un contenedor `busybox`.

![Capas de imágenes de Ubuntu y Busybox](/engine/storage/drivers/device-mapper-driver/images/two_dm_container.webp?w=450&h=100)

## Cómo funcionan las lecturas y escrituras de contenedores con `devicemapper`

### Lectura de archivos

Con `devicemapper`, las lecturas ocurren a nivel de bloque. El siguiente diagrama muestra el proceso general para leer un solo bloque (`0x44f`) en un contenedor de ejemplo.

![Lectura de un bloque con devicemapper](/engine/storage/drivers/device-mapper-driver/images/dm_container.webp?w=650)

Una aplicación realiza una solicitud de lectura del bloque `0x44f` en el contenedor. Debido a que el contenedor es un snapshot dinámico de una imagen, no tiene el bloque, pero tiene un puntero al bloque en la imagen padre más cercana donde sí existe, y lee el bloque desde allí. El bloque ahora reside en la memoria del contenedor.

### Escritura de archivos

**Escribir un archivo nuevo**: Con el controlador `devicemapper`, la escritura de nuevos datos en un contenedor se realiza mediante una operación *allocate-on-demand* (asignación bajo demanda). Cada bloque del nuevo archivo se asigna en la capa de escritura del contenedor y el bloque se escribe allí.

**Actualizar un archivo existente**: El bloque correspondiente al archivo se lee desde la capa más cercana donde exista. Cuando el contenedor escribe en el archivo, solo los bloques modificados se escriben en la capa de escritura del contenedor.

**Eliminar un archivo o directorio**: Cuando eliminas un archivo o directorio en la capa de escritura de un contenedor, o cuando una capa de imagen elimina un archivo que existe en su capa padre, el controlador de almacenamiento `devicemapper` intercepta los futuros intentos de lectura sobre ese archivo o directorio y responde que no existe.

**Escribir y luego eliminar un archivo**: Si un contenedor escribe en un archivo y posteriormente lo elimina, todas esas operaciones ocurren en la capa de escritura del contenedor. En ese caso, si utilizas `direct-lvm`, los bloques se liberan. Si utilizas `loop-lvm`, es posible que los bloques no se liberen. Esta es otra razón para no utilizar `loop-lvm` en producción.

## Rendimiento de Device Mapper y Docker

- **Impacto en el rendimiento de `allocate-on-demand`**:

  El controlador de almacenamiento `devicemapper` utiliza una operación `allocate-on-demand` para asignar nuevos bloques desde el thin pool a la capa de escritura del contenedor. Cada bloque es de 64 KB, por lo que esta es la cantidad mínima de espacio que se utiliza para una escritura.

- **Impacto en el rendimiento de copy-on-write**: La primera vez que un contenedor modifica un bloque específico, ese bloque se escribe en la capa de escritura del contenedor. Debido a que estas escrituras ocurren a nivel del bloque y no del archivo, el impacto en el rendimiento se minimiza. Sin embargo, escribir una gran cantidad de bloques aún puede afectar negativamente al rendimiento, y el controlador de almacenamiento `devicemapper` podría tener un rendimiento inferior al de otros controladores en este escenario. Para cargas de trabajo con uso intensivo de escritura, debes usar volúmenes de datos, que omiten el controlador de almacenamiento por completo.

### Buenas prácticas de rendimiento

Ten en cuenta estos aspectos para maximizar el rendimiento al utilizar el controlador de almacenamiento `devicemapper`.

- **Utiliza `direct-lvm`**: El modo `loop-lvm` no es eficiente y nunca debe usarse en producción.

- **Utiliza almacenamiento rápido**: Las unidades de estado sólido (SSD) proporcionan lecturas y escrituras más rápidas que los discos mecánicos.

- **Uso de memoria**: `devicemapper` consume más memoria que algunos otros controladores de almacenamiento. Cada contenedor iniciado carga una o más copias de sus archivos en memoria, dependiendo de cuántos bloques del mismo archivo se estén modificando al mismo tiempo. Debido a la presión de memoria, el controlador `devicemapper` puede no ser la opción adecuada para ciertas cargas de trabajo en casos de uso de alta densidad.

- **Utiliza volúmenes para cargas de trabajo con uso intensivo de escritura**: Los volúmenes proporcionan el mejor y más predecible rendimiento para cargas de trabajo con uso intensivo de escritura. Esto se debe a que omiten el controlador de almacenamiento y no incurren en ninguna de las posibles sobrecargas introducidas por el aprovisionamiento dinámico y copy-on-write. Los volúmenes tienen otros beneficios, como permitirte compartir datos entre contenedores y persistir incluso cuando ningún contenedor en ejecución los está utilizando.

  > [!NOTE]
  >
  > Al utilizar `devicemapper` y el controlador de registros `json-file`, los archivos de registro generados por un contenedor se siguen almacenando en el directorio dataroot de Docker, por defecto `/var/lib/docker`. Si tus contenedores generan muchos mensajes de registro, esto puede provocar un aumento en el uso del disco o la imposibilidad de administrar tu sistema debido a un disco lleno. Puedes configurar un [controlador de registro](/engine/logging/configure/) para almacenar los registros de tus contenedores de forma externa.

## Información relacionada

- [Volúmenes](/engine/storage/volumes/)
- [Entender las imágenes, contenedores y controladores de almacenamiento](/engine/storage/drivers/)
- [Seleccionar un controlador de almacenamiento](/engine/storage/drivers/device-mapper-driver/select-storage-driver/)

