Como o Docker Swarm implementa o compartilhamento de volume?

97

O Docker Swarm pode gerenciar dois tipos de armazenamento:

volume e bind

Embora bindnão seja sugerido pela documentação do Docker, uma vez que cria uma ligação entre um diretório local (em cada nó de enxame) para uma tarefa, a volumeimplementação não é mencionada, então não entendo como os volumes são compartilhados entre as tarefas.

  • Como o Docker Swarm compartilha volumes entre os nós?
  • Onde são salvos os volumes (em um gerente? E se houver mais de um gerente?)
  • Não há problema entre os nós se estiver sendo executado em máquinas diferentes em redes diferentes?
  • Isso cria uma VPN?
alessandro308
fonte
1
O Swarm compartilha volumes? Há cerca de um ano lidei com o docker swarm, mas acho que o swarm NÃO é responsável por compartilhar volumes entre os nós. Se você deseja que seus nós compartilhem o mesmo volume, você deve usar plug-ins de volume como o azure volumedriver.
Munchkin

Respostas:

68

O que você está perguntando é uma pergunta comum. Os dados de volume e os recursos do que esse volume pode fazer são gerenciados por um driver de volume. Assim como você pode usar diferentes drivers de rede como overlay, bridgeou host, você pode usar diferentes drivers de volume.

O Docker e o Swarm só vêm com o localdriver padrão pronto para uso. Ele não tem conhecimento do Swarm e apenas criará novos volumes para seus dados em qualquer nó em que suas tarefas de serviço estejam agendadas. Geralmente não é isso que você deseja.

Você quer um plugin de driver de terceiros que reconheça o Swarm e garanta que o volume que você criou para uma tarefa de serviço esteja disponível no nó certo no momento certo. As opções incluem o uso de "Docker para AWS / Azure" e seu driver CloudStor incluído ou a solução REX-Ray de código aberto popular .

Existem muitos drivers de volume de terceiros, que você pode encontrar na Docker Store .

Bret Fisher
fonte
o hadoop pode funcionar como um volume compartilhado?
stackit de
57

O modo Swarm em si não faz nada de diferente com os volumes, ele executa qualquer comando de montagem de volume fornecido no nó onde o contêiner está sendo executado. Se a montagem do seu volume for local para esse nó, seus dados serão salvos localmente nesse nó. Não há funcionalidade integrada para mover dados entre nós automaticamente.

Existem algumas soluções de armazenamento distribuído baseadas em software como GlusterFS, e o Docker tem uma chamada Infinit que ainda não é GA e o desenvolvimento ficou em segundo plano em relação à integração do Kubernetes em EE.

O resultado típico é que você precisa gerenciar a replicação de armazenamento em seu aplicativo (por exemplo, etcd e outros algoritmos baseados em jangada) ou realizar suas montagens em um sistema de armazenamento externo (com sorte, com seu próprio HA). A montagem de um sistema de armazenamento externo tem duas opções, baseado em bloco ou arquivo. O armazenamento baseado em bloco (por exemplo, EBS) normalmente vem com melhor desempenho, mas é limitado para ser montado apenas em um único nó. Para isso, você normalmente precisará de um driver de plugin de volume de terceiros para dar ao seu docker node acesso a esse armazenamento de bloco. O armazenamento baseado em arquivo (por exemplo, EFS) tem desempenho inferior, mas é mais portátil e pode ser montado simultaneamente em vários nós, o que é útil para um serviço replicado.

O armazenamento de rede baseado em arquivo mais comum é o NFS (este é o mesmo protocolo usado pelo EFS). E você pode montá-lo sem nenhum driver de plugin de terceiros. O driver de plug-in de volume infelizmente chamado "local" fornecido com o docker oferece a opção de passar quaisquer valores que você deseja para o comando de montagem com as opções do driver e, sem opções, o padrão é armazenar volumes no diretório docker / var / lib / docker / volumes. Com opções, você pode passar os parâmetros NFS, e ele vai até realizar uma pesquisa de DNS no nome do host NFS (algo que você não tem com NFS normalmente). Aqui está um exemplo das diferentes maneiras de montar um sistema de arquivos NFS usando o driver de volume local:

  # create a reusable volume
  $ docker volume create --driver local \
      --opt type=nfs \
      --opt o=nfsvers=4,addr=192.168.1.1,rw \
      --opt device=:/path/to/dir \
      foo

  # or from the docker run command
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=192.168.1.1\",volume-opt=device=:/host/path \
    foo

  # or to create a service
  $ docker service create \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=192.168.1.1\",volume-opt=device=:/host/path \
    foo

  # inside a docker-compose file
  ...
  volumes:
    nfs-data:
      driver: local
      driver_opts:
        type: nfs
        o: nfsvers=4,addr=192.168.1.1,rw
        device: ":/path/to/dir"
  ...

Se você usar o exemplo de composição de arquivo no final, observe que as alterações em um volume (por exemplo, atualizar o caminho ou endereço do servidor) não são refletidas nos volumes nomeados existentes enquanto eles existirem. Você precisa renomear seu volume ou excluí-lo para permitir que o swarm o recrie com novos valores.

O outro problema comum que vejo na maioria dos usos do NFS é o "root squash" habilitado no servidor. Isso resulta em problemas de permissão quando os containers em execução como root tentam gravar arquivos no volume. Você também tem problemas de permissão UID / GID semelhantes, em que o UID / GID do contêiner é aquele que precisa de permissões para gravar no volume, o que pode exigir a propriedade do diretório e as permissões a serem ajustadas no servidor NFS.

BMitch
fonte
9

Minha solução para AWS EFS, que funciona:

  1. Crie o EFS (não se esqueça de abrir a porta NFS 2049 no grupo de segurança)
  2. Instale o pacote nfs-common:

    sudo apt-get install -y nfs-common

  3. Verifique se seu efs funciona:

    mkdir efs-test-point
    sudo chmod go + rw efs-test-point
    sudo mount -t nfs -o nfsvers = 4.1, rsize = 1048576, wsize = 1048576, difícil, timeo = 600, retrans = 2, noresvport [YOUR_EFS_DNS]: / efs-test-point
    toque efs-test-point / 1.txt
    sudo umount efs-test-point /
    ls -la efs-test-point /

    diretório deve estar vazio

    sudo mount -t nfs -o nfsvers = 4.1, rsize = 1048576, wsize = 1048576, difícil, timeo = 600, retrans = 2, noresvport [YOUR_EFS_DNS]: / efs-test-point

    ls -la efs-test-point/

    arquivo 1.txt deve existir

  4. Configure o arquivo docker-compose.yml:

    Serviços:
      sidekiq:
        volumes:
          - uploads_tmp_efs: / home / application / public / uploads / tmp
      ...
    volumes:
      uploads_tmp_efs:
        motorista: local
        driver_opts:
          tipo: nfs
          o: addr = [YOUR_EFS_DNS], nfsvers = 4.1, rsize = 1048576, wsize = 1048576, hard, timeo = 600, retrans = 2
          dispositivo: [YOUR_EFS_DNS]: /

super_p
fonte
6

Minha solução para nosso enxame hospedado localmente: cada nó de trabalho montou um nfs-share, fornecido por nosso servidor de arquivos em /mnt/docker-data. Quando eu defino os volumes em meus arquivos de composição de serviços, eu defino o dispositivo para algum caminho em /mnt/docker-data, por exemplo:

volumes:
  traefik-logs:
    driver: local
    driver_opts:
      o: bind
      device: /mnt/docker-data/services/traefik/logs
      type: none

Com esta solução, o docker cria o volume em cada nó, o serviço é implantado e - surpresa - já existem dados, porque é o mesmo caminho, que foi usado pelo volume no outro nó.

Se você olhar mais de perto o sistema de arquivos nodes, verá que as montagens para a montagem do meu servidor de arquivos são criadas em /var/lib/docker/volumes, veja aqui:

root@node-3:~# df -h
Dateisystem                                                                                                   Größe Benutzt Verf. Verw% Eingehängt auf
[...]
fs.mydomain.com:/srv/shares/docker-data/services/traefik/logs                                 194G    141G   53G   73% /var/lib/docker/volumes/traefik_traefik-logs/_data
tigu
fonte
0

por padrão, o swarm sempre procurará pelo driver de volume local, então a melhor maneira é

  1. criar compartilhamento nfs, ou seja yum -y install nfs-utils
  2. exporte-o em / etc / exports como abaixo, /root/nfshare 192.168.1.0/24(rw,sync,no_root_squash)
  3. abra as portas necessárias, no meu caso fiz abaixo, firewall-cmd --permanent --add-service mountd ; firewall-cmd --permanent --add-service rpc-bind ; firewall-cmd --permanent --add-service nfs ; firewall-cmd --zone=public --permanent --add-port 2049/tcp
  4. montar o compartilhamento recém-criado nos nós de trabalho do docker e, em seguida,
  5. docker service create --name my-web --replicas 3 -p 80:80 --mount 'type=volume,source=nfshare,target=/usr/share/nginx/html/,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/root/nfshare,"volume-opt=o=addr=192.168.1.8,rw"' nginx:latest
  6. no exemplo acima eu criei nfshare no host 192.168.1.8 e exportei usando o arquivo / etc / exports
  7. daemon (s) iniciado (s) systemctl start nfs-server rpcbind & systemctl enable nfs-server rpcbind
  8. exportfs -r para que as alterações tenham efeito
  9. / root / nfshare tem meu próprio index.html 10.verifique a entrada da unidade de volume com cuidado, pode ser externo também e funcionou para mim
  10. para mais referência https://docs.docker.com/storage/volumes/
ganesh
fonte