Normalmente, os problemas de permissão com uma montagem de volume do host ocorrem porque o uid / gid dentro do contêiner não tem acesso ao arquivo de acordo com as permissões uid / gid do arquivo no host. No entanto, este caso específico é diferente.
O ponto no final da string de permissão drwxr-xr-x.
, indica que o SELinux está configurado. Ao usar uma montagem de host com o SELinux, você precisa passar uma opção extra para o final da definição de volume:
- A
z
opção indica que o conteúdo da montagem de ligação é compartilhado entre vários contêineres.
- A
Z
opção indica que o conteúdo da montagem de ligação é privado e não compartilhado.
Seu comando de montagem de volume ficaria assim:
sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash
Veja mais sobre montagens de host com o SELinux em: https://docs.docker.com/storage/#configure-the-selinux-label
Para outras pessoas que veem esse problema com contêineres em execução como um usuário diferente, é necessário garantir que o uid / gid do usuário dentro do contêiner tenha permissões para o arquivo no host. Nos servidores de produção, isso geralmente é feito controlando o uid / gid no processo de criação da imagem para corresponder a um uid / gid no host que tem acesso aos arquivos (ou melhor ainda, não use montagens de host na produção).
Um volume nomeado é geralmente preferido para hospedar montagens porque inicializará o diretório de volumes a partir do diretório de imagens, incluindo qualquer propriedade e permissão de arquivo. Isso acontece quando o volume está vazio e o contêiner é criado com o volume nomeado.
Os usuários do MacOS agora têm o OSXFS, que lida com o uid / gid automaticamente entre o host e os contêineres do Mac. Um lugar em que não ajuda são os arquivos de dentro da VM incorporada que são montados no contêiner, como /var/lib/docker.sock.
Para ambientes de desenvolvimento em que o host uid / gid pode mudar por desenvolvedor, minha solução preferida é iniciar o contêiner com um ponto de entrada em execução como raiz, corrigir o uid / gid do usuário dentro do contêiner para corresponder ao volume do host uid / gid e então use gosu
para soltar da raiz para o usuário do contêiner para executar o aplicativo dentro do contêiner. O script importante para isso está fix-perms
nos meus scripts de imagem base, que podem ser encontrados em: https://github.com/sudo-bmitch/docker-base
A parte importante do fix-perms
script é:
# update the uid
if [ -n "$opt_u" ]; then
OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
NEW_UID=$(stat -c "%u" "$1")
if [ "$OLD_UID" != "$NEW_UID" ]; then
echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
usermod -u "$NEW_UID" -o "$opt_u"
if [ -n "$opt_r" ]; then
find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
fi
fi
fi
Isso coloca o uid do usuário dentro do contêiner, o uid do arquivo e, se não corresponderem, chama usermod
para ajustar o uid. Por fim, ele faz uma busca recursiva para corrigir os arquivos que não mudaram os uids. Eu gosto disso melhor do que executar um contêiner com um -u $(id -u):$(id -g)
sinalizador, porque o código do ponto de entrada acima não exige que cada desenvolvedor execute um script para iniciar o contêiner, e quaisquer arquivos fora do volume que pertencem ao usuário terão suas permissões corrigidas.
Você também pode fazer com que o docker inicialize um diretório de host de uma imagem usando um volume nomeado que executa uma montagem de ligação. Esse diretório deve existir com antecedência e você precisa fornecer um caminho absoluto para o diretório do host, diferente dos volumes do host em um arquivo de composição que podem ser caminhos relativos. O diretório também deve estar vazio para a janela de encaixe inicializá-lo. Existem três opções diferentes para definir um volume nomeado para uma montagem de ligação:
# create the volume in advance
$ docker volume create --driver local \
--opt type=none \
--opt device=/home/user/test \
--opt o=bind \
test_vol
# create on the fly with --mount
$ docker run -it --rm \
--mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
foo
# inside a docker-compose file
...
volumes:
bind-test:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/test
...
Por fim, se você tentar usar espaços de nome de usuário, verá que os volumes do host têm problemas de permissão porque os uid / gid dos contêineres são alterados. Nesse cenário, provavelmente é mais fácil evitar volumes de host e usar apenas volumes nomeados.