Skip to main content


Volumes


Os volumes no Docker são uma maneira de persistir e compartilhar dados entre contêineres e o host. Eles fornecem um mecanismo flexível para armazenar dados gerados ou consumidos por aplicativos em contêineres Docker. Eles são fundamentais para garantir uma cópia segura de um volume existente. Os volumes asseguram segurança e conveniência quando surge a necessidade de recuperar um volume contendo arquivos e informações importantes.


Os Containers de dados são empregados para isolar dados e facilitar a comunicação entre múltiplos contêineres, de maneira descomplicada, compartilhando os mesmos dados entre eles. Para essa finalidade, é designado um volume dentro desses contêineres, que será acessado por outros contêineres.


Nesse cenário, não é preciso criar um diretório específico persistente, pois um volume padrão é automaticamente criado dentro da estrutura do Docker. A vantagem disso é evitar a necessidade de gerenciar diretamente esses diretórios, visto que todas as conexões são direcionadas para o container de dados e não para um diretório específico.


Os volumes são armazenados em uma parte do sistema de arquivos do host que é gerenciada pelo Docker (/var/lib/docker/volumes/ no Linux). Processos que não são do Docker não devem modificar esta parte do sistema de arquivos. As montagens tmpfs são armazenadas apenas na memória do sistema do host e nunca são gravadas no sistema de arquivos do host.



Quando usar Volumes?


Como já foi dito, os volumes são a forma preferida de persistir dados em contêineres e serviços Docker. Alguns casos de uso são:


  • Quando precisamos compartilhar dados entre múltiplos contêineres em execução.
    Quando esse contêiner para ou é removido, o volume ainda existe. Múltiplos contêineres podem montar o mesmo volume simultaneamente, seja em modo de leitura-escrita ou somente leitura. Volumes são removidos apenas quando você os remove explicitamente.

  • Quando precisamos fazer backup
    Quase sempre precisamos fazer backup, restaurar ou migrar dados de um host Docker para outro, aqui novamente podemos usar volumes. Você pode parar os contêineres que usam o volume, então fazer o backup do diretório do volume (como /var/lib/docker/volumes/<volume-nome>).



Bind mounts


Bind mounts são um recurso do Docker que permite montar um diretório ou arquivo do sistema de arquivos do host diretamente dentro de um contêiner Docker. Isso significa que você pode vincular um diretório ou arquivo existente em seu sistema de arquivos local ao sistema de arquivos do contêiner.


Os Bind mounts têm funcionalidade limitada em comparação com os volumes. Quando você usa um bind mount, um arquivo ou diretório no sistema do host é montado em um contêiner. O arquivo ou diretório é referenciado pelo seu caminho completo no sistema do host. O arquivo ou diretório não precisa existir no sistema do host do Docker antecipadamente. Ele é criado sob demanda se ainda não existir.


As montagens de vinculação são rápidas, mas dependem da estrutura de diretórios específica disponível no sistema de arquivos do host. Se você estiver desenvolvendo novas aplicações Docker, considere usar volumes nomeados (named volumes) em vez disso. Você não pode usar comandos CLI do Docker para gerenciar diretamente montagens de vinculação.


Importante

Os Bind mounts permitem acesso de escrita a arquivos no sistema do host por padrão. Uma implicação significativa do uso de bind mounts é a capacidade de processos em execução dentro de um contêiner alterarem o sistema de arquivos do host. Isso inclui a criação, modificação ou exclusão de arquivos ou diretórios importantes do sistema.


Essa capacidade pode ser poderosa, mas também apresenta implicações de segurança, pois os processos dentro do contêiner podem afetar processos que não são do Docker no sistema do host.



Quando usar Bind mounts?


Alguns dos casos onde Bind mount são bons, incluem:


  • Compartilhar arquivos de configuração da máquina host com os contêineres. Um exemplo comum é o Docker usar bind mounts para fornecer resolução DNS aos contêineres, montando o /etc/resolv.conf da máquina host em cada contêiner.

  • Compartilhar código-fonte ou artefatos de compilação entre um ambiente de desenvolvimento no host Docker e um contêiner. Por exemplo, você pode montar um diretório no contêiner para compartilhar o código-fonte entre o host Docker e o contêiner. Isso permite que os artefatos reconstruídos sejam acessados pelo contêiner a cada nova construção do projeto no host Docker.


Volume vs Bind Mount

Quando é criado um volume no Docker, esse volume é uma entidade separada que pode ser compartilhada entre vários containers. Isso permite que os dados persistam mesmo que os containers sejam destruídos. Por outro lado, um bind mount direto é específico para um único container e não pode ser compartilhado com outros containers.


Um volume é nada mais que um Bind Mount que pode ser usado por muitos containers simultaneamente. Enquanto que um bind mount direto, só pode ser usado por um único container.



Docker volumes


O comando docker volume é usado para gerenciar volumes no Docker. Com este comando, você pode criar, listar, inspecionar e remover volumes. Aqui estão algumas operações comuns que você pode realizar usando o comando docker volume:


ComandoDescrição
docker volume create VOLUMECria um novo volume com o nome especificado.
docker volume lsLista todos os volumes disponíveis no sistema.
docker volume inspect VOLUMEExibe detalhes sobre um volume específico, como seu nome, driver de armazenamento e opções de montagem.
docker volume rm VOLUMERemove um volume específico. Observe que você não pode remover um volume em uso por um contêiner em execução.
docker volume prune VOLUMEÉ usado para remover volumes Docker que não estão sendo usados por nenhum contêiner.

Terminal
# Montando um diretório com bind-mounts. Modo detalhado:
docker run -it -w 'app' --mount type=bind,source=$(pwd)/my-pc-dir,target=/app alpine sh

# Montando um diretório com bind-mounts. Modo curto:
docker run -it -w 'app' -v /tmp/my-pc-dir:/app alpine sh

# Executando o container e montando um volume. Modo detalhado:
docker run -d --mount type=volume,source=app-vol,target=/app alpine

# Executando o container e montando um volume. Modo curto:
docker run -d -v app-vol:/app alpine

# Montar um volume, sintaxe:
docker container run -d --volumes-from VOLUME_NAME --name IMAGE ID

# Criando uma imagem e montando o volume como apenas leitura:
docker container run -ti --mount type=bind,src=/root/docker/,dst=/volume,ro ubuntu


Data-Only Container


É um container apenas para prover volumes para outros containers, parecido com um samba, NFS server dentre outros. Essa abordagem era mais útil nas primeiras versões do Docker, quando o gerenciamento de volumes não era tão avançado quanto é hoje. Atualmente, com as funcionalidades nativas de volumes do Docker, os Data-Only Containers são considerados obsoletos ou desnecessários na maioria dos casos, mas vou descrever eles apenas para conhecimento.


O comando abaixo vai criar um contêiner com um volume chamado /dbdados. O volume será criado internamente no contêiner e não será associado a nenhum diretório no sistema de arquivos do host. O contêiner será mantido em execução apenas para manter o volume, já que o comando executado (/bin/true) não realiza nenhuma operação significativa.

Terminal
\# docker create -v /dbdados --name dbdados mysql /bin/true

O comando acima cria um novo container chamado dbdados com um volume /dbdados associado, baseado na imagem do MySQL. O comando /bin/true é executado para manter o contêiner em execução, já que não faz nada significativo.


Para usar o volume da dos existente:

Terminal
docker container run -d --volumes-from VOLUME_NAME --name IMAGE ID

Para usar um diretório específico use o passo a passo abaixo.

Terminal
# Crie a pasta volume no /tmp:
╼ $ mkdir /tmp/volume

# Criando uma imagem e montando o volume (volume vazio):
╼ $ docker container run -ti --mount type=bind,src=/tmp/volume,dst=/tmp/volume ubuntu

# Criando uma imagem e montando o volume (volume cheio):
\# docker container run -ti --mount type=bind,src=/root/docker/,dst=/volume ubuntu

╼ $ df -h
Filesystem Size Used Avail Use% Mounted on
overlay 902G 595G 261G 70% /
tmpfs 64M 0 64M 0% /dev
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
shm 64M 0 64M 0% /dev/shm
/dev/sda1 902G 595G 261G 70% /volume
tmpfs 7.8G 0 7.8G 0% /proc/asound
tmpfs 7.8G 0 7.8G 0% /proc/acpi
tmpfs 7.8G 0 7.8G 0% /proc/scsi
tmpfs 7.8G 0 7.8G 0% /sys/firmware


# Criando uma imagem e montando o volume como apenas leitura:
\# docker container run -ti --mount type=bind,src=/root/docker/,dst=/volume,ro ubuntu

O comando acima cria um novo contêiner a partir da imagem do Ubuntu. Um volume é montado no contêiner usando a opção --mount. Neste caso, o tipo de montagem é bind, o que significa que um diretório específico no sistema de arquivos do host (/tmp/volume) é montado dentro do contêiner no mesmo local (/tmp/volume).


Qualquer alteração feita nos arquivos dentro deste diretório no contêiner também será refletida no sistema de arquivos do host e vice-versa. Este é um volume de bind, onde o diretório no host é vinculado diretamente ao diretório no contêiner.



Storage drivers


Os storage drivers são componentes cruciais na arquitetura do Docker, pois determinam como os dados são manipulados e armazenados no sistema de arquivos do contêiner. Cada storage driver implementa uma estratégia específica para lidar com a persistência de dados, a eficiência de armazenamento e o desempenho de E/S.


Existem vários storage drivers disponíveis no Docker, e a escolha do driver apropriado depende de vários fatores, como o sistema operacional do host, o ambiente de implantação, as características do sistema de arquivos subjacente e os requisitos de desempenho e segurança.


Alguns exemplos comuns de storage drivers incluem:



AUFS (Another Union File System)

Este foi o primeiro filesystem disponível para o Docker, ele funciona em nível de arquivo (não em bloco), tendo múltiplos diretórios que é apresentado ao S.O como apenas um único ponto de montagem.


Escrever em arquivos grandes causa lentidão na performance porque deve ser copiado o arquivo para a camada superior de escrita, sua busca é feito através do PATH, o problema é que, para cada camada, ele vai buscar os diretórios dentro do PATH, ou seja, um PATH com 2 diretórios serão pesquisados estes 2 diretórios em todas as camadas, até achar o que procura ou concluir que não existe.


Quando um arquivo é deletado, ele não é realmente deletado, ele é apenas renomeado para .wh.<nome> e fica indisponível para o container, já que não da para apagar por ser read-only.h



Device Mapper

Há uma semelhança muito grande entre AUFS e Device Mapper, o DM (Device Mapper) foi criado pela Red Hat e permite técnicas como RAID e LVM graças ao mapeamento de blocos físicos para lógicos. Ele corrige alguns problemas do AUFS, como o problema de copiar arquivos grandes quando formos alterar, a cópia é feita no nível de bloco, em teria, o problema de performance não ocorre mais.



OverlayFS e OverlayFS2

O OverlayFS é uma versão melhorada do AUFS, sua segunda versão é recomendada pela equipe do Docker. Sua segunda versão veio com multilayer, page caching sharing, ou seja, múltiplos containers acessando o mesmo arquivo e dividem a mesma entrada no arquivo de paginação, economizando mais memoria.


Como ele é a nível de arquivo, ainda temos o problema de copiar para camada superior, porém, após copiado, ele permanece lá, desta forma edições futuras serão mais rápidos.


BRTFS

Trabalha em nível de bloco, suporte inúmeras tecnologias avançadas de storage e suporte copy-on-write snapshots. Só é suportado na versão CE para Debian-like e EE para Suse Linux Enterprise Server.



VFS

Este é o driver mais básico e geralmente é usado apenas para fins de teste ou em ambientes onde outros storage drivers não estão disponíveis ou são incompatíveis.



NFS


O uso de volumes com NFS (Network File System) no Docker permite compartilhar dados entre contêineres e máquinas usando um sistema de arquivos em rede. Isso é útil para armazenar dados persistentes em um local centralizado, acessível por vários contêineres.


Primeiro temos que instalar o cliente NFS na máquina onde o Docker está rodando:

Terminal
# No Ubuntu/Debian:
sudo apt install nfs-common

# No CentOS/RHEL:
sudo yum install nfs-utils

Agora nós podemos criar um volume Docker que monta um diretório NFS usando o comando docker volume create. Abaixo podemos ver o comando de criação do Volume Docker usando NFS:

Terminal
docker volume create \
--driver local \
--opt type=nfs4 \
--opt o=addr=<nfs-server-ip>,rw,nolock \
--opt device=:/path/on/nfs \
nfs_volume

É obrigatório incluir o caractere : no caminho do diretório ao configurar a montagem no NFS, como em :/path/on/nfs. Esse caractere separa o endereço IP do servidor do caminho exportado, resultando na sintaxe completa: <nfs-server-ip>:/path/on/nfs.


Depois de criar o volume, você pode montá-lo em um contêiner:

Terminal
docker run -d \
--name app \
--mount source=nfs_volume,target=/app/data \
my-app:latest

Você também pode configurar volumes NFS em arquivos Compose.

version: '3.8'
services:
app:
image: my-app:latest
volumes:
- nfs_volume:/app/data

volumes:
nfs_volume:
driver: local
driver_opts:
type: "nfs4"
o: "addr=192.168.1.100,rw,nolock"
device: ":/data"

É fundamental garantir que o servidor NFS e o diretório exportado possuam permissões adequadas para o usuário e grupo utilizados pelo contêiner, assegurando acesso e operação sem interrupções. Além disso, o NFS deve ser implementado em redes de baixa latência para evitar problemas de desempenho. Embora um servidor mais robusto reduza eventuais gargalos, problemas de processamento são raramente perceptíveis em configurações bem otimizadas.


Recomenda-se configurar o NFS com estratégias de alta disponibilidade, como replicação ou backups regulares, para minimizar o risco de perda de dados. Adicionalmente, restringir o acesso ao servidor NFS a IPs confiáveis é uma prática essencial de segurança. A adoção de autenticação robusta e o uso de firewalls complementam essas medidas, protegendo o ambiente contra acessos não autorizados.