# Usando Volumes

O container possui seu próprio sistemas de pastas para organização dos arquivos. Estas pastas, no entanto, não são visíveis para a máquina hospedeira (host). E o pior: quando o container é extinto, os dados que estavam nestas pastas se perdem também. A maneira de preservar os dados é adicionar pastas externas ao container, mapeando-as como se fossem nativas. E para tal usamos os volumes.

Os volumes são versáteis e adiciona novas possibilidades ao ambiente criado por um container:

  • Ao excluirmos o container, o volume permanece inalterado, preservando os dados, arquivos de parametros, etc.;
  • É possível compartilhar um mesmo volume entre containêres, deixando os dados visíveis para ambos;
  • Um volume pode estar localizado em uma outra máquina, na rede local ou em nuvem;
  • Um volume pode ser acoplado e desacplado ao container.

TIP

Para situações mais imediatas é possível conectar uma pasta local em um container com o comando -v ou com --mount type=bind

# Conectando uma pasta ao iniciar o container

Para ligar um volume basta usar o parametro v e informar a localização da pasta no servidor, separar por : e informar a pasta no container. As pastas serão criadas, caso não existam e substituídas, caso já exista no container

sudo docker run -v /pasta/pasta_hospedeiro:/pasta_container --name=nome-container -it nome_imagem [comando_container]

Ou para ficar mais legível:

sudo docker run -v /pasta/pasta_hospedeiro:/pasta_container \
                 --name=nome-container \
                 -it nome_imagem [comando_container]

Exemplo:

sudo docker run -v /tmp/pasta_hospedeiro:/pasta_container  \
                 --name=alpine_sandbox-06 \
                 -it alpine /bin/ash


[marcos@localhost ~]$ sudo docker run -v /tmp/pasta_hospedeiro:/pasta_container  \
>                  --name=alpine_sandbox-06 \
>                  -it alpine /bin/ash
/ # ls
bin  etc   lib     mnt  pasta_container  root  sbin  sys  usr
dev  home  media   opt  proc             run   srv   tmp  var
/ # ls -ld /pasta_container
drwxr-xr-x    2 root     root            40 Nov 15 10:11 /pasta_container

Verificando em outro terminal:

[marcos@localhost ~]$ ls /tmp
dropbox-antifreeze-ngXrsG  ssh-BJo2lg5gQv5v  pasta_hospedeiro   systemd-private-2d4a70

A partir da versão 17.06 o Docker começou a utilizar o parâmeto --mount que é mais descritivo. E esta sintaxe deve ser adotada. Assim, o comando:

sudo docker run -v /pasta/pasta_hospedeiro:/pasta_container \
                 --name=nome-container \
                 -it nome_imagem [comando_container]

Deverá ser substituído por:

sudo docker run --mount type=bind,source=/pasta/pasta_hospedeiro,target=/pasta_container \
                --name=nome-container \
                -it nome_imagem [comando_container]

Exemplo:

sudo docker run --mount type=bind,source=/home/marcos/docker.images/bind/,target=/pasta_container \
                --name=alpine_sandbox-07 \
                -it alpine /bin/ash

(executando o container)

marcos@localhost ~]$ sudo docker run --mount type=bind,source=/home/marcos/docker.images/bind/,target=/pasta_container \
>                 --name=alpine_sandbox-07 \
>                 -it alpine /bin/ash
/ # ls /pasta_container/
freeplane-icon.png  freeplane_logo.jpg
/ #

(verificando na pasta local)

[marcos@localhost ~]$ ls /home/marcos/docker.images/bind/
freeplane-icon.png  freeplane_logo.jpg
[marcos@localhost ~]$ 

WARNING

A ligação de pastas locais ao container, torna-o menos portátil, visto que implica na existencia da mesma estrutura de arquivos na máquina host.

# Objeto Volume

O volume pode ser criado com o compartilhamento de pastas durante a inicialização de um container com a chamada a RUN ou mesmo com o comando VOLUME em um dockerfile. Mas também, pode ser criado sem que esteja associado a qualquer container.

# O comando VOLUME

Para gerenciar a criação de volumes existe o comando volume com os seguintes parâmetros:

Comando Descrição
create Cria um volume
inspect Lista informações sobre um ou mais volumes
ls Lista os volumes criados
prune Remove todos os volumes locais não utilizados
rm Remove um ou mais volumes

# Criando um volume

Para criar um volume chamado docker01.vol:

sudo docker volume create nome_volume

Exemplo:

sudo docker volume create docker01.vol

[marcos@localhost ~]$ sudo docker volume create docker01.vol
docker01.vol

# Inspecionando o volume criado

Para ler as iformações referentes ao volume chamado docker01.vol:

sudo docker volume inspect docker01.vol

[marcos@localhost ~]$ sudo docker volume inspect docker01.vol
[
    {
        "CreatedAt": "2019-11-15T11:02:09-02:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/docker01.vol/_data",
        "Name": "docker01.vol",
        "Options": {},
        "Scope": "local"
    }
]

# Listando os volume de um host

Para listar os volumes existentes no servidor:

sudo docker volume ls

[marcos@localhost ~]$ sudo docker volume ls
DRIVER              VOLUME NAME
local               226d88056414e07c663082f2cae3010cdb86a635a8fe84e513d645efa49a67b8
local               798f57d1a9f44a6b4c5193921c87a181663c140bad761d2fc8339c0d6dcb1b31
local               docker01.vol
local               dados_oper.vol

# Removendo volumes

Use o parametro prune para remover todos os volumes que não estão em uso:

sudo docker volume prune

[marcos@localhost ~]$ sudo docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
docker.vol
dados_oper.vol

Total reclaimed space: 0B
[marcos@localhost ~]$ 

Ou use rm para remover nominalmente um ou mais volumes:

sudo docker volume rm docker02.vol

# Volumes Anexados

# Anexando um volume

Ao criar um container é possível anexar um volume existente:

sudo docker container create --name=nome-container -it --mount source=nome-volume,target=/nome-pasta-container nome-imagem

sudo docker container create --name=volume-sandbox -it --mount source=docker02.vol,target=/meu_volume alpine

marcos@localhost ~]$ sudo docker volume create docker03.vol
docker03.vol
[marcos@localhost ~]$ sudo docker container create --name=volume-sandbox -it --mount source=docker03.vol,target=/meu_volume  alpine /bin/ash
e247e0d455f0459a10eb9c3045a6e52ad75468097e2e8b6a96e0c6f8d4d29f39

Inspecionando o container para verficar o volume anexado:

marcos@localhost ~]$ docker container inspect volume-sandbox
        ... (linhas retiradas)
        "Mounts": [
            {
                "Type": "volume",
                "Name": "docker03.vol",
                "Source": "/var/lib/docker/volumes/docker03.vol/_data",
                "Destination": "/meu_volume",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ...    

# Compartilhando arquivos entre contêineres

Para testar o compartilhamento, serão usados dois contêineres (volume-sandbox-01, volume-sandbox-02) e um volume (docker04.vol):

  • Criando o volume, os contêineres e iniciando-os:
	sudo docker volume create docker04.vol
	sudo docker container create --name=volume-sandbox-01 -it \
		--mount source=docker04.vol,target=/meu_volume  alpine
	sudo docker container create --name=volume-sandbox-02 -it \
		--mount source=docker04.vol,target=/meu_volume  alpine
	sudo docker container start volume-sandbox-01
	sudo docker container start volume-sandbox-02
  • Conectando ao primeiro container. Criando um arquivo texto leiame.txt:
	[marcos@localhost ~]$ sudo docker exec -it volume-sandbox-01 /bin/ash
	/ # ls
	bin         dev         etc         home        lib         media       meu_volume  mnt         opt         proc        root        run         sbin        srv         sys         tmp         usr         var
	/ # cd meu_volume/
	/meu_volume # echo "Fui criado a partir de volume-sandbox-01" > leiame.txt
	/meu_volume # ls
	leiame.txt
  • Conectando ao segundo container. Verificando a existência do leiame.txt na pasta meu_volume:
	[marcos@localhost ~]$ sudo docker exec -it volume-sandbox-02 /bin/ash
	/ # ls
	bin         dev         etc         home        lib         media       meu_volume  mnt         opt         proc        root        run         sbin        srv         sys         tmp         usr         var
	/ # cat meu_volume/leiame.txt 
	Fui criado a partir de volume-sandbox-01

# Copiando arquivos do hospedeiro para o volume

Copiando o arquivo arquivo-do-host.txt do hospdeiro para a pasta meu_volume no container volume-sandbox-01:

`sudo docker container cp arquivo-do-host.txt volume-sandbox-01:/meu_volume`

# Verificando o ponto de montagem do volume criado

sudo docker volume inspect docker04.vol

[marcos@localhost ~]$ sudo docker volume inspect docker04.vol
[
    {
        "CreatedAt": "2019-11-15T12:36:13-02:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/docker04.vol/_data",
        "Name": "docker04.vol",
        "Options": {},
        "Scope": "local"
    }
]
[marcos@localhost ~]$ sudo ls /var/lib/docker/volumes/docker04.vol/_data
arquivo-do-host.txt  leiame.txt

Os arquivos arquivo-do-host.txt e leiame.txt estão na pasta _/var/lib/docker/volumes/docker04.vol/data

O docker possui plugins para permitir que o ponto de montagem seja alterado. Podem ser usados links simbólicos para tornar o acesso aos pontos de montagem mais simples.

  • Crie uma pasta para receber os links para seus volumes

sudo mkdir home/marcos/docker.images/volume/

  • Crie dentro da mesma, uma pasta com o nome do volume desejado

sudo mkdir /home/marcos/docker.images/volume/docker04.vol sudo mkdir /home/marcos/docker.images/volume/docker04.vol/dados

Fique Atento

Se já existem arquivos no volume, copie-os para a pasta criada e remova-os do destino!

  • Crie o link simbólico

sudo ln -s /home/marcos/docker.images/volume/docker04.vol /var/lib/docker/volumes/docker04.vol/_data

sudo ln -s /home/marcos/docker.images/volume/docker04.vol/dados /var/lib/docker/volumes/docker04.vol/_data

[marcos@localhost ~]$ sudo ln -s /home/marcos/docker.images/volume/docker04.vol/dados /var/lib/docker/volumes/docker04.vol/_data
[marcos@localhost ~]$ sudo docker exec -it volume-sandbox-01 /bin/ash
/ # ls meu_volume/
dados