Como lidar com o armazenamento persistente (por exemplo, bancos de dados) no Docker

993

Como as pessoas lidam com o armazenamento persistente dos seus contêineres do Docker?

Atualmente, estou usando esta abordagem: construa a imagem, por exemplo, para PostgreSQL e inicie o contêiner com

docker run --volumes-from c0dbc34fd631 -d app_name/postgres

IMHO, que tem a desvantagem, que eu nunca devo (por acidente) excluir o contêiner "c0dbc34fd631".

Outra idéia seria montar os volumes do host "-v" no contêiner, no entanto, o ID do usuário no contêiner não corresponde necessariamente ao ID do usuário do host e, em seguida, as permissões podem ser alteradas.

Nota: Em vez de --volumes-from 'cryptic_id'você também pode usar --volumes-from my-data-containeronde my-data-containerestá um nome que você atribuiu a um contêiner somente de dados, por exemplo docker run --name my-data-container ...(veja a resposta aceita)

juwalter
fonte
Desculpe, eu expressei isso errado, pretendia dizer: todas as minhas instâncias futuras dessa imagem dependem desse contêiner. Se eu excluir esse contêiner por acidente, estou com problemas.
juwalter
@AntonStrogonoff - sim, erro de expressão - eu quis dizer: preciso garantir que nunca excluirei esse (possivelmente) contêiner antigo, porque a referência do armazenamento "persistente" também desapareceria
juwalter
deveria ser --name. você tem-name
Shammel Lee

Respostas:

986

Docker 1.9.0 e superior

Usar API de volume

docker volume create --name hello
docker run -d -v hello:/container/path/for/volume container_image my_command

Isso significa que o padrão de contêiner somente de dados deve ser abandonado em favor dos novos volumes.

Na verdade, a API de volume é apenas uma maneira melhor de atingir o que era o padrão de contêiner de dados.

Se você criar um contêiner com um -v volume_name:/container/fs/pathDocker, criará automaticamente um volume nomeado para você, que pode:

  1. Ser listado através do docker volume ls
  2. Ser identificado através do docker volume inspect volume_name
  3. Backup feito como um diretório normal
  4. Backup feito como antes através de uma --volumes-fromconexão

A nova API de volume adiciona um comando útil que permite identificar volumes pendentes:

docker volume ls -f dangling=true

E depois remova-o pelo nome:

docker volume rm <volume name>

Como o @mpugach sublinha nos comentários, você pode se livrar de todos os volumes pendentes com um belo one-liner:

docker volume rm $(docker volume ls -f dangling=true -q)
# Or using 1.13.x
docker volume prune

Docker 1.8.xe abaixo

A abordagem que parece funcionar melhor na produção é usar um contêiner apenas de dados .

O contêiner apenas de dados é executado em uma imagem de barebones e, na verdade, não faz nada, exceto expor um volume de dados.

Em seguida, você pode executar qualquer outro contêiner para ter acesso aos volumes do contêiner de dados:

docker run --volumes-from data-container some-other-container command-to-execute
  • Aqui você pode obter uma boa imagem de como organizar os diferentes contêineres.
  • Aqui há uma boa visão de como os volumes funcionam.

Em este post não é uma boa descrição do chamado recipiente como padrão de volume que esclarece o principal ponto de ter dados somente recipientes .

A documentação do Docker agora tem a descrição DEFINITIVA do contêiner como padrão de volume / s .

A seguir, é apresentado o procedimento de backup / restauração do Docker 1.8.xe abaixo.

CÓPIA DE SEGURANÇA:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: remova o contêiner ao sair
  • --volumes-from DATA: anexa aos volumes compartilhados pelo contêiner DATA
  • -v $ (pwd): / backup: bind monta o diretório atual no contêiner; para escrever o arquivo tar
  • busybox: uma imagem pequena e simples - boa para manutenção rápida
  • tar cvf /backup/backup.tar / data: cria um arquivo tar não compactado de todos os arquivos no diretório / data

RESTAURAR:

# Create a new data container
$ sudo docker run -v /data -name DATA2 busybox true
# untar the backup files into the new container᾿s data volume
$ sudo docker run --rm --volumes-from DATA2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
data/
data/sven.txt
# Compare to the original container
$ sudo docker run --rm --volumes-from DATA -v `pwd`:/backup busybox ls /data
sven.txt

Aqui está um bom artigo do excelente Brian Goff explicando por que é bom usar a mesma imagem para um contêiner e um contêiner de dados.

tommasop
fonte
8
É uma ferramenta diferente para uma necessidade diferente. --volumes-frompermite compartilhar espaço em disco, --linkcompartilhar serviços.
Tommasop 21/05
3
Há outro projeto nos trabalhos especificamente voltados para esse tipo de coisa, talvez adicione-o a esta resposta como uma referência a ser observada? github.com/ClusterHQ/flocker
Andre
9
Os contêineres de dados não têm nenhum significado e são uma péssima ideia! Contêiner significa apenas algo quando um processo está sendo executado, caso contrário, é apenas uma parte do sistema de arquivos host. Você pode simplesmente montar um volume com -v, que é a única e melhor opção. Você tem controle sobre o sistema de arquivos e o disco físico que usa.
Boynux
11
Sim, a partir do Docker 1.9, a criação de volumes nomeados com a API de volumes ( docker volume create --name mydata) é preferível a um contêiner de volume de dados. O pessoal do Docker sugere que os Data Volume Containers “ não são mais considerados um padrão recomendado ”, “os volumes nomeados devem poder substituir os volumes somente de dados na maioria dos casos (se não todos) ” e “ não há razão para usar. contêineres somente para dados ".
Quinn Comendant 27/02
8
@ codificação, estou triste, você está triste, em parte porque você está julgando respostas com um atraso de 3 anos e em parte porque a resposta está substancialmente correta em toda a sua história. Se você tem algum conselho à vontade para comentar para que eu possa integrar a resposta e ajudar as pessoas a não ficar triste
tommasop
75

No Docker versão v1.0 , a ligação de uma montagem de um arquivo ou diretório na máquina host pode ser feita pelo comando fornecido:

$ docker run -v /host:/container ...

O volume acima pode ser usado como armazenamento persistente no host executando o Docker.

amitmula
fonte
3
Esta deve ser a resposta recomendada, pois é muito menos complexa do que a abordagem volume-recipiente que tem mais votos no momento
insitusec
2
Eu gostaria que houvesse um sinalizador para especificar um mapeamento host-uid: container-uid e host-gid: container-gid ao usar este comando de montagem de volume.
Rampion
35

A partir do Docker Compose 1.6, agora há suporte aprimorado para volumes de dados no Docker Compose. O seguinte arquivo de composição criará uma imagem de dados que persistirá entre as reinicializações (ou mesmo a remoção) dos contêineres pai:

Aqui está o anúncio do blog: Componha 1.6: Novo arquivo de composição para definir redes e volumes

Aqui está um exemplo de arquivo de composição:

version: "2"

services:
  db:
    restart: on-failure:10
    image: postgres:9.4
    volumes:
      - "db-data:/var/lib/postgresql/data"
  web:
    restart: on-failure:10
    build: .
    command: gunicorn mypythonapp.wsgi:application -b :8000 --reload
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    links:
      - db

volumes:
  db-data:

Tanto quanto posso entender: Isso criará um contêiner de volume de dados ( db_data) que persistirá entre as reinicializações.

Se você executar: docker volume lsdeverá ver seu volume listado:

local               mypthonapp_db-data
...

Você pode obter mais alguns detalhes sobre o volume de dados:

docker volume inspect mypthonapp_db-data
[
  {
    "Name": "mypthonapp_db-data",
    "Driver": "local",
    "Mountpoint": "/mnt/sda1/var/lib/docker/volumes/mypthonapp_db-data/_data"
  }
]

Alguns testes:

# Start the containers
docker-compose up -d

# .. input some data into the database
docker-compose run --rm web python manage.py migrate
docker-compose run --rm web python manage.py createsuperuser
...

# Stop and remove the containers:
docker-compose stop
docker-compose rm -f

# Start it back up again
docker-compose up -d

# Verify the data is still there
...
(it is)

# Stop and remove with the -v (volumes) tag:

docker-compose stop
docker=compose rm -f -v

# Up again ..
docker-compose up -d

# Check the data is still there:
...
(it is).

Notas:

  • Você também pode especificar vários drivers no volumesbloco. Por exemplo, você pode especificar o driver do Flocker para db_data:

    volumes:
      db-data:
        driver: flocker
    
  • À medida que melhoram a integração entre o Docker Swarm e o Docker Compose (e possivelmente começam a integrar o Flocker ao ecossistema do Docker (ouvi um boato de que o Docker comprou o Flocker), acho que essa abordagem deve se tornar cada vez mais poderosa.

Isenção de responsabilidade: essa abordagem é promissora e estou sendo usada com sucesso em um ambiente de desenvolvimento. Eu ficaria apreensivo em usar isso na produção ainda!

toast38coza
fonte
Flocker foi desligado e não há muita atividade na repo github
Krishna
17

Caso não esteja claro na atualização 5 da resposta selecionada, a partir do Docker 1.9, você poderá criar volumes que possam existir sem estar associado a um contêiner específico, tornando obsoleto o padrão "contêiner somente de dados".

Consulte Contêineres somente de dados obsoletos com o docker 1.9.0? # 17798 .

Eu acho que os mantenedores do Docker perceberam que o padrão de contêiner somente de dados era um cheiro de design e decidiram tornar os volumes uma entidade separada que pode existir sem um contêiner associado.

ben_frankly
fonte
13

Enquanto isso ainda faz parte do Docker que precisa de algum trabalho , você deve colocar o volume no Dockerfile com a instrução VOLUME para não precisar copiar os volumes de outro contêiner.

Isso tornará seus contêineres menos interdependentes e você não precisará se preocupar com a exclusão de um contêiner que afeta outro.

Tim Dorr
fonte
O argumento do outro lado é que os contêineres "apenas dados" acabam sendo a referência de último recurso para o volume de dados (o Docker destrói volumes de dados assim que o último contêiner que faz referência ao volume é removido docker rm)
WineSoaked
2
Este guia oficial do Docker sugere o contrário: docs.docker.com/userguide/dockervolumes/… "Os volumes de dados são projetados para persistir dados, independentemente do ciclo de vida do contêiner. Portanto, o Docker nunca exclui automaticamente os volumes quando você remove um contêiner. Volumes de "coleta de lixo" que não são mais referenciados por um contêiner ".
21415 Alex
12

Ao usar o Docker Compose , basta anexar um volume nomeado, por exemplo:

version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - db_data:/var/lib/mysql:rw
    environment:
      MYSQL_ROOT_PASSWORD: root
volumes:
  db_data:
Czar Pino
fonte
9

A resposta do @ tommasop é boa e explica algumas das mecânicas do uso de contêineres somente de dados. Mas como alguém que inicialmente pensou que os contêineres de dados eram tolos quando se podia ligar um monte ao volume (como sugerido por várias outras respostas), mas agora percebe que, de fato, os contêineres somente de dados são muito legais, posso sugerir o meu próprio postagem no blog sobre este tópico: Por que os Docker Data Containers (Volumes!) são bons

Consulte também: minha resposta à pergunta " Qual é a (melhor) maneira de gerenciar permissões para volumes compartilhados do Docker? " Para obter um exemplo de como usar contêineres de dados para evitar problemas como permissões e mapeamento uid / gid com o host.

Para resolver uma das preocupações originais do OP: que o contêiner de dados não deve ser excluído. Mesmo que o contêiner de dados seja excluído, os dados em si não serão perdidos enquanto qualquer contêiner tiver uma referência a esse volume, ou seja, qualquer contêiner que montou o volume --volumes-from. Portanto, a menos que todos os contêineres relacionados sejam parados e excluídos (pode-se considerar isso o equivalente a um acidente rm -fr /), os dados estão seguros. Você sempre pode recriar o contêiner de dados executando --volumes-fromqualquer contêiner que tenha uma referência a esse volume.

Como sempre, faça backups!

ATUALIZAÇÃO: O Docker agora possui volumes que podem ser gerenciados independentemente de contêineres, o que facilita ainda mais o gerenciamento.

Raman
fonte
9

Existem vários níveis de gerenciamento de dados persistentes, dependendo de suas necessidades:

  • Armazene no seu host
    • Use o sinalizador -v host-path:container-pathpara manter os dados do diretório de contêiner em um diretório de host.
    • Os backups / restaurações acontecem executando um contêiner de backup / restauração (como tutumcloud / dockup) montado no mesmo diretório.
  • Crie um contêiner de dados e monte seus volumes no contêiner do aplicativo
    • Crie um contêiner que exporte um volume de dados, use --volumes-frompara montar esses dados no contêiner do aplicativo.
    • Faça backup / restaure o mesmo que a solução acima.
  • Use um plug-in de volume do Docker que faça backup de um serviço externo / de terceiros
    • Os plug-ins de volume do Docker permitem que sua fonte de dados venha de qualquer lugar - NFS, AWS (S3, EFS e EBS)
    • Dependendo do plug-in / serviço, você pode anexar um ou vários contêineres a um único volume.
    • Dependendo do serviço, os backups / restaurações podem ser automatizados para você.
    • Embora isso possa ser complicado de fazer manualmente, algumas soluções de orquestração - como o Rancher - o integram e são fáceis de usar.
    • O comboio é a solução mais fácil para fazer isso manualmente.
Will Stern
fonte
8

Se você deseja mover seus volumes, também deve consultar o Flocker .

No README:

O Flocker é um gerenciador de volume de dados e uma ferramenta de gerenciamento de cluster Docker de vários hosts. Com ele, você pode controlar seus dados usando as mesmas ferramentas usadas para seus aplicativos sem estado, aproveitando o poder do ZFS no Linux.

Isso significa que você pode executar seus bancos de dados, filas e armazenamentos de valores-chave no Docker e movê-los com a mesma facilidade que o resto do seu aplicativo.

Johann Romefort
fonte
1
Obrigado Johann. Trabalho no ClusterHQ e gostaria apenas de observar que fomos além do armazenamento baseado em ZFS. Agora você pode usar o Flocker com armazenamento como Amazon EBS ou Google Persistent Disk. Aqui está uma lista completa de opções de armazenamento: docs.clusterhq.com/en/latest/supported/...
ferrantim
1
O Flocker foi interrompido e não deve ser usado portworx.com/…
jesugmz 9/09/18
5

Depende do seu cenário (isso não é realmente adequado para um ambiente de produção), mas aqui está uma maneira:

Criando um container MySQL Docker

Esta essência é usar um diretório em seu host para persistência de dados.

ben schwartz
fonte
6
Graças a Ben, no entanto - um dos problemas que eu posso ver com essa abordagem: o recurso do sistema de arquivos (diretório, arquivos) seria de propriedade de um uid do contêiner docker / lxc (guest) - um que poderia colidir com um uid no host ...
juwalter 15/12/2013
1
Eu acho que você é bastante seguro, pois é executado pela raiz, mas eu concordo que é um hack - adequado para testes locais de integração dev / efêmera na melhor das hipóteses. Esta é definitivamente uma área que eu gostaria de ver surgir mais padrões / pensamentos. Você deve verificar / postar esta pergunta no grupo docker-dev do google
ben schwartz
Ben, obrigado por esta solução! Eu não chamaria isso de hack, mas parece muito mais confiável do que o contêiner como volume . Você vê alguma desvantagem no caso em que os dados são usados ​​apenas no contêiner? (UID não importa neste caso)
johndodo
1

Estou apenas usando um diretório predefinido no host para manter os dados do PostgreSQL. Além disso, é possível migrar facilmente as instalações existentes do PostgreSQL para contêineres do Docker: https://crondev.com/persistent-postgresql-inside-docker/

Alen Komljen
fonte
0

Minha solução é usar o novo docker cp, que agora pode copiar dados de contêineres, não importa se está em execução ou não, e compartilhar um volume de host no mesmo local exato em que o aplicativo de banco de dados está criando seus arquivos de banco de dados dentro do contêiner . Essa solução dupla funciona sem um contêiner somente de dados, diretamente do contêiner do banco de dados original.

Portanto, meu script systemd init está executando o trabalho de fazer backup do banco de dados em um arquivo no host. Coloquei um carimbo de data / hora no nome do arquivo para nunca reescrever um arquivo.

Está fazendo isso no ExecStartPre:

ExecStartPre=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStartPre=-/bin/bash -c '/usr/bin/tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStartPre.tar.gz /home/core/sql/mysql --remove-files'

E está fazendo a mesma coisa no ExecStopPost também:

ExecStopPost=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStopPost=-/bin/bash -c 'tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStopPost.tar.gz /home/core/sql/mysql --remove-files'

Além disso, expus uma pasta do host como um volume ao mesmo local exato em que o banco de dados está armazenado:

mariadb:
  build: ./mariadb
  volumes:
    - $HOME/server/mysql/:/var/lib/mysql/:rw

Funciona muito bem na minha VM (eu construo uma pilha LEMP para mim): https://github.com/DJviolin/LEMP

Mas eu simplesmente não sei se é uma solução "à prova de balas" quando sua vida depende dela (por exemplo, loja virtual com transações em possíveis milissegundos)?

Aos 20 minutos e 20 segundos deste vídeo oficial do Docker, o apresentador faz o mesmo com o banco de dados:

Introdução ao Docker

"Para o banco de dados, temos um volume, para garantir que, conforme o banco de dados sobe e desce, não perdemos dados quando o contêiner do banco de dados parou."

Lanti
fonte
O que você quer dizer com "... aproveite ..." ? E "... transações em qualquer milissegundo possível" ?
Peter Mortensen
0

Use a Reivindicação de volume persistente (PVC) do Kubernetes, que é uma ferramenta de gerenciamento e agendamento de contêineres do Docker:

Volumes Persistentes

As vantagens de usar o Kubernetes para essa finalidade são as seguintes:

  • Você pode usar qualquer armazenamento, como NFS ou outro armazenamento, e mesmo quando o nó está inoperante, o armazenamento não precisa estar.
  • Além disso, os dados em tais volumes podem ser configurados para serem retidos mesmo após a destruição do próprio contêiner - para que possam ser recuperados, se necessário, por outro contêiner.
Santanu Dey
fonte