Moby: Adicione a capacidade de montar o volume como usuário diferente do root

Criado em 17 out. 2013  ·  157Comentários  ·  Fonte: moby/moby

Caso de uso: monte um volume do host para o container para uso pelo apache como usuário www.
O problema é que atualmente todas as montagens são montadas como root dentro do container.
Por exemplo, este comando
docker run -v /tmp:/var/www ubuntu stat -c "%U %G" /var/www
imprimirá "raiz raiz"

Eu preciso montá-lo como usuário www dentro do container.

areapi arekernel arevolumes exexpert kinenhancement

Comentários muito úteis

Posso dizer não - forçando os usuários a adicionar um script auxiliar que não

#!/bin/sh
chown -R redis:redis /var/lib/redis
exec sudo -u redis /usr/bin/redis-server

(obrigado @bfirsh pelo seu exemplo)

é bem terrível.

Isso significa que o contêiner deve ser iniciado como root, em vez de ser executado como o usuário redis pretendido. (como @aldanor aludiu)

e isso significa que um usuário não pode fazer algo como:

docker run -v /home/user/.app_cfg/ -u user application_container application :(

Todos 157 comentários

Se você chown o volume (no lado do host) antes de montá-lo, ele funcionará.
Nesse caso, você poderia fazer:

mkdir /tmp/www
chown 101:101 /tmp/www
docker run -v /tmp/www:/var/www ubuntu stat -c "%U %G" /var/www

(Assumindo que 101:101 é o UID:GID do usuário www-data em seu contêiner.)

Outra possibilidade é fazer o bind-mount, então chown dentro do container.

@mingfang O chown não funcionará para você?

Seria útil ter um atalho para isso. Muitas vezes me pego escrevendo scripts run que apenas definem as permissões em um volume:

https://github.com/orchardup/docker-redis/blob/07b65befbd69d9118e6c089e8616d48fe76232fd/run

E se você não tiver os direitos de chown ?

Um script auxiliar que chown o volume resolveria esse problema? Este scirpt pode ser o ENTRYPOINT do seu Dockerfile.

Posso dizer não - forçando os usuários a adicionar um script auxiliar que não

#!/bin/sh
chown -R redis:redis /var/lib/redis
exec sudo -u redis /usr/bin/redis-server

(obrigado @bfirsh pelo seu exemplo)

é bem terrível.

Isso significa que o contêiner deve ser iniciado como root, em vez de ser executado como o usuário redis pretendido. (como @aldanor aludiu)

e isso significa que um usuário não pode fazer algo como:

docker run -v /home/user/.app_cfg/ -u user application_container application :(

Existe _one_ maneira de fazê-lo funcionar, mas você precisa se preparar com antecedência dentro do seu Dockrfile.

RUN mkdir -p /var/lib/redis ; chown -R redis:redis /var/lib/redis
VOLUME ["/var/lib/redis"]
ENTRYPOINT ["usr/bin/redis-server"]
USER redis

(Eu não testei este exemplo, estou trabalhando em um contêiner de cromo que é exibido em um contêiner _separate_ X11 que .... )

E é claro que esse método só funciona para novos volumes diretos, não para vincular
montado ou volumes-de volumes. ;)

Além disso, vários contêineres usando volumes-from terão uid/gid diferentes para o mesmo usuário, o que também complica as coisas.

@SvenDowideit @tianon esse método também não funciona. Exemplo completo:

FROM ubuntu
RUN groupadd -r redis    -g 433 && \
useradd -u 431 -r -g redis -d /app -s /sbin/nologin -c "Docker image user" redis 
RUN mkdir -p /var/lib/redis
RUN echo "thing" > /var/lib/redis/thing.txt
RUN chown -R redis:redis /var/lib/redis
VOLUME ["/var/lib/redis"]
USER redis
CMD /bin/ls -lah /var/lib/redis

Duas execuções, com e sem um volume -v:

bash-3.2$ docker run -v `pwd`:/var/lib/redis voltest 
total 8.0K
drwxr-xr-x  1 root root  102 Aug  7 21:30 .
drwxr-xr-x 28 root root 4.0K Aug  7 21:26 ..
-rw-r--r--  1 root root  312 Aug  7 21:30 Dockerfile
bash-3.2$ docker run  voltest 
total 12K
drwxr-xr-x  2 redis redis 4.0K Aug  7 21:30 .
drwxr-xr-x 28 root  root  4.0K Aug  7 21:26 ..
-rw-r--r--  1 redis redis    6 Aug  7 21:26 thing.txt
bash-3.2$ 

Estamos enfrentando um problema que seria resolvido por isso (eu acho). Temos um compartilhamento NFS para os diretórios pessoais de nossos desenvolvedores. Os desenvolvedores querem montar /home/dev/git/project no Docker, mas não podem porque temos o Root Squash habilitado.

Isso proíbe o root de acessar /home/dev/git/project então, quando tento executar a montagem do docker /home/dev/git/project , recebo um erro lstat permission denied .

@frankamp Isso ocorre porque a preferência atual do docker é não modificar as coisas do host que não estão sob o controle do próprio Docker.

Sua definição de "VOLUME" está sendo substituída por seu -v pwd`:/var/lib/reds`.
Mas em sua segunda execução, ele está usando um volume controlado pelo docker, que é criado em /var/lib/docker. Quando o contêiner é iniciado, o docker está copiando os dados da imagem para o volume e, em seguida, chowning o volume com o uid:gid do diretório para o qual o volume foi especificado.

Não tenho certeza se há muito que pode ser feito aqui e, infelizmente, as montagens de ligação não suportam (até onde eu sei) a montagem como um uid/gid diferente.

Minha solução para isso foi fazer o que SvenDowideit fez acima (criar novo usuário e chown na frente no dockerfile), mas em vez de montar o volume do host, use um contêiner somente de dados e copie o volume do host que eu queria montar no recipiente com tar cf - . | docker run -i --volumes-from app_data app tar xvf - -C /data . Isso se tornará um pouco mais fácil quando https://github.com/docker/docker/pull/13171 for mesclado (e docker cp funciona nos dois sentidos), mas talvez possa se tornar uma alternativa para -v host_dir:container_dir , ou seja. talvez -vc host_dir:container_dir , (vc para cópia de volume), em que o conteúdo do host_dir seria copiado para o contêiner de dados. Embora eu não possa dizer que entendo por que / como os arquivos copiados herdam as permissões do usuário do contêiner, pelo que posso dizer que eles fazem, e esta é a única solução razoável que consegui encontrar que não destrói a portabilidade.

E o acl?

Existe alguma correção ou solução alternativa? Eu me deparo com o mesmo problema com o OpenShift, a pasta montada é de propriedade de root: root e imagens pré-criadas não funcionarão.

Estou procurando uma solução também. Se todos os volumes montados forem de propriedade de root , será impossível executar seus contêineres do Docker com qualquer usuário que não seja root .

Bem, você pode tentar s6-overlay . Ele inclui recursos que são especificamente direcionados para ajudar a contornar esses tipos de problemas.

@dreamcat4 : Obrigado pelo ponteiro. A correção de propriedade e permissões parece uma solução interessante, mas eu não teria que executar meu contêiner do Docker como root para que isso funcionasse?

@brikis98 Sim, isso é verdade. No entanto, o s6-overlay também possui outro recurso, que permite descartar as permissões novamente ao iniciar seus servidores / daemons.

@dreamcat4 Ah, entendi, obrigado.

Eu tenho o mesmo uid/gid dentro e fora de um container e é isso que recebo:

nonroot$ ls -l .dotfiles/
ls: cannot access .dotfiles/byobu: Permission denied
ls: cannot access .dotfiles/config: Permission denied
ls: cannot access .dotfiles/docker: Permission denied
ls: cannot access .dotfiles/vim: Permission denied
ls: cannot access .dotfiles/bashrc: Permission denied
ls: cannot access .dotfiles/muse.yml: Permission denied
ls: cannot access .dotfiles/my.cnf: Permission denied
ls: cannot access .dotfiles/profile: Permission denied
total 0
-????????? ? ? ? ?            ? bashrc
d????????? ? ? ? ?            ? byobu
d????????? ? ? ? ?            ? config
d????????? ? ? ? ?            ? docker
-????????? ? ? ? ?            ? muse.yml
-????????? ? ? ? ?            ? my.cnf
-????????? ? ? ? ?            ? profile
d????????? ? ? ? ?            ? vim
nonroot$ ls -l .ssh
ls: cannot access .ssh/authorized_keys: Permission denied
total 0
-????????? ? ? ? ?            ? authorized_keys
nonroot$

@darkermatter você poderia abrir um problema separado?

não é um problema, mas isso não é relevante aqui?

@darkermatter esta é uma solicitação de recurso, não um relatório de bug, misturar seu caso com outros casos dificulta o acompanhamento da discussão, além disso, seu problema pode não estar diretamente relacionado

@thaJeztah bem, como @frankamp e outros fizeram, eu estava simplesmente demonstrando o que acontece depois de executar chmod, etc. dentro do Dockerfile. Vou arquivá-lo como um relatório de bug, mas é relevante para esta discussão.

semelhante ao que @ebuchman propôs, sem copiar um volume de host, você pode criar primeiro um contêiner somente de dados, que faz um
chown 1000:1000 /volume-mount como root quando começou.
Por exemplo, na sintaxe do docker compose v2

version: '2'
services:
  my-beautiful-service:
    ...
    depends_on:
      - data-container
    volumes_from:
      - data-container

  data-container:
    image: same_base_OS_as_my-beautiful-service
    volumes:
      - /volume-mount
    command: "chown 1000:1000 /volume-mount"

Dessa forma, seu contêiner pode ser executado como usuário não root. O contêiner somente de dados é executado apenas uma vez.
Supondo que você conheça o uid e o gid que my-beautiful-service usa de antemão. Geralmente é 1.000.100.

Sendo que você pode (em 1.11) especificar opções de montagem para um volume para usar em seu docker volume create , eu diria que isso parece muito próximo de estar pronto para fechar.

Você não pode simplesmente especificar uid/gid diretamente porque isso não é suportado com montagens de ligação, mas muitos sistemas de arquivos que você pode usar com as novas opções de montagem podem funcionar com opções uid/gid.

Acho que o problema ainda é resolvido nos casos em que você deseja montar uma unidade CIFS dentro do seu contêiner, mas talvez isso deva ser outro tíquete?

@michaeljs1990 Você pode fazer isso, mas não por contêiner (a menos que você crie volumes separados para cada combinação uid/gid desejada).

@ cpuguy83 , você poderia esclarecer como se deve usar docker volume create para evitar esse problema?

Acabei de me deparar com esse problema hoje com o docker 1.11 e tive que fazer alguns ajustes dolorosos para convencer a imagem do docker a me permitir gravar em arquivos em uma unidade montada. Seria muito bom se eu nunca mais precisasse fazer isso de novo, muito menos tentar explicar para outra pessoa.

Não tenho certeza se é isso que você está perguntando, mas...

FROM busybox
RUN mkdir /hello && echo hello > /hello/world && chown -R 1000:1000 /hello

Construa acima da imagem nomeada como "teste"

$ docker volume create --name hello
$ docker run -v hello:/hello test ls -lh /hello

Tanto /hello quanto /hello/world no exemplo acima seriam de propriedade de 1000:1000

Eu vejo. Então, fiz algo parecido, mas um pouco diferente, o que pode valer a pena compartilhar. Basicamente, adicionei um usuário ao Dockerfile que compartilhou meu UID, GID, nome de usuário e grupo para o usuário fora do contêiner. Todos os <...> são coisas substituídas por valores relevantes.

FROM <some_image>
RUN groupadd -g <my_gid> <my_group> && \
    useradd -u <my_uid> -g <my_gid> <my_user>

Depois disso, pode-se alternar usando USER ou usando su em algum momento posterior (por exemplo, script de ponto de entrada ou ao usar um shell). Isso me permitiu escrever no volume montado, pois eu era o mesmo usuário que o criou. Além disso, pode-se usar chown dentro do contêiner para garantir que você tenha permissões para coisas relevantes. Além disso, instalar sudo geralmente é uma jogada inteligente ao fazer isso também.

Embora resolva o problema, não sei se o adoro, pois isso precisaria ser feito para qualquer usuário. Além disso, eu codifiquei coisas (eca!), mas talvez os modelos possam ser usados ​​para tornar isso um pouco mais suave. Gostaria de saber se esse calço poderia ser absorvido em docker run alguma forma. Se já existe uma maneira melhor de fazer isso, eu estaria muito interessado em saber o que é.

Existe uma opção para mapear usuários de host uids/gids com usuários de contêiner uids/gids com --userns-remap . Pessoalmente não experimentei. Veja uma boa discussão sobre este tópico http://stackoverflow.com/questions/35291520/docker-and-userns-remap-how-to-manage-volume-permissions-to-share-data-betwee .

@cpuguy83 :

Você não pode simplesmente especificar uid/gid diretamente porque isso não é suportado com montagens de ligação, mas muitos sistemas de arquivos que você pode usar com as novas opções de montagem podem funcionar com opções uid/gid.

Quais sistemas de arquivos você está pensando que podem aceitar argumentos uid/gid? Eu sei que o FAT pode, mas isso parece tão hacky quanto qualquer outra coisa proposta neste tópico.

IMO, o Docker tem duas opções:

  1. Suporte oficial para montar volumes como um usuário/grupo especificado (usando o nome de usuário/grupo definido dentro do contêiner, não exigindo que o host tenha esse conhecimento dos componentes internos do contêiner).
  2. Ou... livre-se da diretiva USER (e dos sinalizadores de tempo de execução associados).

Ser capaz de executar como um usuário não root enquanto só consegue montar volumes pertencentes ao root é um erro. O compartilhamento de uid/gid entre host e container é outro defeito.

Os volumes @mehaase assumem a propriedade do que já estiver no caminho no contêiner. Se o local no contêiner for de propriedade do root, o volume obterá o root. Se o local no contêiner pertencer a outra coisa, o volume obterá isso.

Algum tipo de solução alternativa para isso seria ótimo. A menos que o contêiner o espere especificamente, fica _muito_ difícil adicionar volumes a contêineres padrão como elasticsearch, redis, couchDB e muitos outros sem escrever um Dockerfile personalizado que defina as permissões. Isso torna o comando docker run -v ou a diretiva volume: no docker-compose inútil.

@chrisfosterelli por que inútil? Eu não acho que seja fora do comum definir as propriedades dos arquivos/diretórios que você espera usar.

@ cpuguy83 Porque não parece ser possível definir a propriedade sem usar um Dockerfile personalizado que defina permissões e volumes, e é por isso que acho que eles não são úteis para definir volumes. Não estou vinculando contêineres ao meu sistema de arquivos host, se isso for relevante.

@chrisfosterelli Mas todos esses Dockerfiles padrão devem ter as permissões já definidas.

Eu acho que o @chrisfosterelli está tentando dizer, @cpuguy83 , (e por favor me corrija se eu estiver errado @chrisfosterelli) é que ficou claro que essas variáveis ​​(UID, GID, etc.) tempo de execução (especialmente wrt para arquivos de propriedade interna e de volumes montados), mas não temos uma maneira de fazer isso atualmente. A resposta até agora parece ser que eles não deveriam ser determinados em tempo de execução, mas isso é ignorar o problema fundamental de usabilidade apresentado por tal sugestão. Novamente, se eu estiver entendendo mal alguma coisa, sinta-se à vontade para me corrigir.

@jakirkham Eu não devo estar entendendo qual é o problema de usabilidade.
Os arquivos estão na imagem, eles devem ter a propriedade e as permissões necessárias para que o aplicativo seja executado. Não tem nada a ver com o volume em si. O volume apenas assume o que foi definido na imagem.

@ cpuguy83 Eu fiz um pouco mais de escavação e o isolei para isso: Digamos que eu tenha um contêiner elasticsearch que criará um diretório /data ao iniciar (se nenhum dado estiver presente), então use docker run -v /data elasticsearch . O diretório /data torna-se propriedade de root:root e o daemon que é executado como elasticsearch dentro do contêiner agora falhará ao iniciar porque não pode gravar em /data .

Seria ideal se eu pudesse definir esse volume para pertencer ao elasticsearch sem precisar de um Dockerfile personalizado... embora eu ache que você possa argumentar que esse tipo de problema deve ser resolvido na imagem upstream.

@chrisfosterelli há algumas conversas nas listas de discussão do kernel sobre ter uma sobreposição como driver que pode alterar a propriedade, mas não há muito que possamos fazer sem algo assim. Estou curioso, você pode apenas fazer com que todos os arquivos em seu mundo de volume leiam e escrevam e defina umasks apropriadamente para que novos arquivos também sejam? (ainda não tentei).

@justincormack Acredito que sim, mas acho que não funciona quando espero que o contêiner crie os dados no volume (em vez do host). Eu entendo que isso é um problema estranho, então estou resolvendo isso corrigindo-o no próprio Dockerfile upstream para mkdir -p && chmod o diretório.

@chrisfosterelli é por isso que eu disse definir o umask, se o seu umask for 000 (no contêiner), todos os novos arquivos serão criados com permissões 666 ou 777 , e se o ponto de montagem é 777 para começar, deve estar ok? Se as permissões são sempre de leitura e gravação do mundo, uid e gid não deveriam importar?

@justincormack Sim, parece correto ... como posso fazer isso ao criar um contêiner docker com um volume não montado em host?

@chrisfosterelli hmm, essa é uma boa pergunta. Parece-me que as permissões em um novo volume são o que o umask padrão daria, então você pode tentar executar o daemon do docker com um 000 umask e ver se o volume é gravável em todo o mundo. Talvez devêssemos ter algumas opções de permissões em docker volume create .

(você pode corrigi-lo com um contêiner raiz que fez chmod e saiu também, mas isso é feio)

Em criar não é bom. O problema é que, se o contêiner não tiver o caminho, o caminho será criado com root. Isso poderia ser feito como qualquer que seja o usuário passado.

@ cpuguy83 Acho que faria mais sentido criá-lo conforme o usuário passasse com -u, pois provavelmente seria o usuário tentando escrever o volume de qualquer maneira de dentro do contêiner, certo?

Consegui montar como o usuário de minha escolha usando as etapas abaixo:

  • Crie o usuário dentro do Docker com o mesmo UID/GID do usuário que possui os arquivos no host.
  • Crie os pontos de montagem com antecedência e mostre-os ao usuário de destino no contêiner

Citação @chrisfosterelli :

Eu fiz um pouco mais de escavação e o isolei para isso: Digamos que eu tenha um contêiner elasticsearch que criará um diretório /data ao inicializar (se nenhum dado estiver presente), então use docker run -v /data elasticsearch. O diretório /data torna-se propriedade de root:root e o daemon que é executado como elasticsearch dentro do contêiner agora falhará ao iniciar porque não pode gravar em /data.

Este é um excelente exemplo! Eu tenho um exemplo semelhante com a imagem Solr. O Solr precisa de um ou mais "núcleos", cada um dos quais é uma coleção de arquivos de configuração relacionados e fragmentos de índice. Cada núcleo é colocado dentro de um diretório com um nome especificado pelo usuário. Por exemplo, se eu quiser criar um núcleo chamado products , o caminho seria /opt/solr/server/solr/products . O nome do núcleo é escolhido por mim, então o mantenedor da imagem Solr não pode pré-criar este diretório na imagem.

Quero que meus dados de índice sejam salvos para que eu possa atualizar minha imagem para um Solr mais recente sem precisar reindexar todos os meus documentos, mas se eu montar um volume para /opt/solr/server/solr/products , ele será de propriedade de root e Solr (executando como solr ) não podem realmente escrever nada nele. O diretório pai /opt/solr/server/solr contém outros arquivos, então também não posso montar um volume lá. (Na linguagem mais recente do Docker, acredito que meus volumes são chamados de "volumes nomeados", ou seja, volumes que não são montados em um caminho especificado no host, mas são totalmente gerenciados pelo Docker para mim.)

Falei sobre isso com o mantenedor da imagem Solr e existem algumas soluções alternativas (e ele fez algumas alterações na imagem para ajudar), mas é tudo muito complicado e requer alterações caso a caso na imagem upstream. Ter o recurso discutido neste tópico tornaria _todas as imagens_ mais extensíveis sem a necessidade de criar um novo Dockerfile.

@ctindel talvez... se o diretório ainda não existir.

@ cpuguy83 Isso é verdade, eu concordo. Esse foi definitivamente o meu caso de uso. Não parece fazer sentido criar o diretório como root se ele não existir quando um ID de usuário tiver sido explicitamente especificado para executar o contêiner.

@ cpuguy83 funciona apenas para o volume nomeado.

@kamechen O que funciona?

@ cpuguy83 Quando você usa um volume nomeado, os arquivos são montados no usuário que você precisa

@eciuca Bom.... depende. Se o volume nomeado estava vazio ou os dados no volume nomeado foram criados pelo mesmo usuário que você precisava.

Já houve uma solução para o problema levantado por @andrewmichaelsmith?

Estamos enfrentando um problema que seria resolvido por isso (eu acho). Temos um compartilhamento NFS para os diretórios pessoais de nossos desenvolvedores. Os desenvolvedores querem montar /home/dev/git/project no Docker, mas não podem porque temos o Root Squash habilitado.

Isso proíbe o root de acessar /home/dev/git/project, portanto, quando tento executar a montagem do docker /home/dev/git/project, recebo um erro de permissão negada lstat.

Eu acho que é possível contornar isso usando bindfs .
Usando -v ... do docker para montar o volume em um local temporário e, em seguida, o bindfs para montá-lo onde for necessário como outro usuário.

@piccaso , a maneira como eu entendi @andrewmichaelsmith é que o problema é que a montagem de ligação no lado do host falha por causa do rootsquash. Mas o bindfs ainda pode ser usado como uma solução alternativa, mas desta vez no lado do host. Primeiro, no host, você monta o compartilhamento nfs em um local temporário como um usuário não root usando FUSE e, em seguida, monta essa pasta temporária no docker com -v ... .

Lembre-se de que o bindfs (pelo menos com o FUSE) tem um pouco de sobrecarga de CPU.

Sim, bindfs é muito indesejável. É mais lento do que os sistemas de arquivos CoW.
Há algum trabalho sendo feito no kernel para permitir a mudança de uid/gid na montagem que pode ajudar.

Há algum trabalho sendo feito no kernel para permitir a mudança de uid/gid na montagem que pode ajudar.

Isso provavelmente também ajudará a resolver o caso de uso em que quero remapear uid/gid dentro do contêiner. A própria montagem executada pelo daemon docker ainda seria executada como root no host. Meu entendimento é que com o Kernel as montagens de bind só podem ser criadas como root. Não tenho certeza se há trabalho para mudar isso para permitir que as montagens sejam executadas por usuários não root (eu sei pouco sobre a maneira como o Linux lida com montagens para julgar se o mesmo faz sentido).

@NikolausDemmel Duvido que isso mude. A syscall mount requer CAP_SYS_ADMIN, que não é algo dado a um usuário não root, ou mesmo algo que damos ao usuário root de um container.

@cpuguy83 Obrigado pelo esclarecimento. Isso significa que a montagem de volumes docker em pastas de host que são montagens NFS com root-squash não funcionará no futuro previsível (devido a limitações da mount syscall como você diz), exceto pelo uso de soluções alternativas como FUSE com bindfs .

Desculpe, isso foi um pouco OT, já que o OP estava perguntando sobre a alteração do UID/GID dentro do contêiner. Mas é meio que o outro lado da moeda e surgiu na discussão acima. Só queria esclarecer essa distinção.

Estou executando o Docker para Mac e montei um volume, mas não consigo obter as permissões definidas para o serviço da Web para acessar os arquivos. Como eu consertaria isso? Tentei alterar as permissões e definir o grupo como pessoal, mas parece que a Alpine não tem um grupo de funcionários.

Desculpe se este não é o melhor lugar para colocá-lo, estou lutando há dias e não conseguia pensar em um lugar melhor.

@NikolausDemmel : Estamos tentando usar o Docker para alguns trabalhos de bioinformática. Temos vários sistemas de arquivos enormes montados com raiz esmagada via NFS. Lemos em grandes sequências de dados (fastq) e escrevemos um arquivo BAM um pouco menor com as leituras genômicas alinhadas ao armazenamento de dados. Atualmente, podemos usar o docker fazendo a imagem personalizada para criar um usuário dentro do contêiner e usar USER no final para fazê-lo funcionar, mas isso é problemático por alguns motivos:

  1. Se quisermos usar a imagem do Docker de outra pessoa, temos que reconstruir com um Dockerfile personalizado
  2. Precisamos criar uma imagem de encaixe personalizada para cada usuário local ou usar uma única conta de "serviço" e não poderemos distinguir entre as atividades do usuário no FS.

O Bindfs ou userNS podem nos deixar contornar isso?

Acho que estou com o mesmo problema, meu caso de uso é:
As imagens do Docker contêm nossas ferramentas de compilação portáteis para um determinado projeto, usamos montagem de volume com caminhos relativos com algo como docker run -v ./:/src/ image ou o equivalente em um arquivo de composição do docker. Uma compilação é iniciada automaticamente e novos arquivos são gerados em uma subpasta no volume vinculado.
Às vezes, gostamos de usar esses arquivos criados do host, mas o fato de eles ainda pertencerem ao usuário no docker, em vez do usuário do host que executou o docker, tende a tornar as coisas complicadas.

Estou fazendo algo particularmente errado aqui?

@rlabrecque veja meu post anterior sobre a correspondência do ID do usuário do docker com o do host. Eu usei essa abordagem e funciona muito bem para nós. Basicamente, execute HOST_UID=$(id -u) e HOST_GID=$(id -g) e gere um Dockerfile que expanda $HOST_GID e $HOST_UID nos dois comandos abaixo:

RUN groupadd -g $HOST_GID mygroup
RUN useradd -l -u $HOST_UID -g mygroup myuser

Use o Dockerfile gerado com os IDs preenchidos para construir sua imagem.

@haridsv Eu fiz algo semelhante e funciona muito bem no Linux. Mas isso não parece funcionar para mim no Windows: os arquivos dentro da montagem ainda são de propriedade do root.

Eu resolvi isso usando inotifywait . Você precisará instalar inotify-tools para executá-lo dentro de sua imagem docker. É possível executá-lo em seu sistema host, mas eu queria uma solução portátil.

RUN export DEBIAN_FRONTEND=noninteractive \
  && apt -y update \
  && apt -y install inotify-tools \
  && inotifywait -m -r /mount -e create --format '%w%f' \
    | while read f; do chown $(stat -c '%u' /mount):$(stat -c '%g' /mount) $f; done

Isso funciona instruindo o inotifywait a observar quaisquer novos arquivos ou diretórios criados no diretório /mount. Quando detecta um, ele altera a propriedade para o mesmo usuário e grupo da pasta /mount. Usei a representação inteira de ambos, caso o usuário/grupo do host não exista no container. Dentro do container não importa quem o possui, pois tudo roda como root. Fora do contêiner, o sistema de arquivos do host mostra a mesma propriedade de qualquer diretório que foi montado em /mount.

Eu o projetei deliberadamente para definir apenas a propriedade de arquivos e diretórios recém-criados, a fim de preservar a propriedade de arquivos e diretórios pré-existentes. É mais seguro do que explodir tudo isso com uma instrução chown -R toda vez que o sistema de arquivos é montado. Se as permissões uniformes funcionarem para o seu projeto e você quiser uma solução mais simples que seja executada com mais eficiência, consulte inotify-hookable .

Aviso: Como um inotify watch será estabelecido por subdiretório, é possível que a quantidade máxima de inotify watchs por usuário seja atingida. O máximo padrão é 8192; ele pode ser aumentado gravando em /proc/sys/fs/inotify/max_user_watches.

Usamos um script do lado do host para chown o volume sendo montado, o que evita a necessidade de reconstruir a imagem:

#!/bin/bash
set -e

DOCKER_IMAGE=<docker_image>
COMMAND=<internal_command>

DOCKER_USER=docker-user
DOCKER_GROUP=docker-group

HOME_DIR=/work
WORK_DIR="$HOME_DIR/$(basename $PWD)"

PARAMS="$PARAMS -it --rm"
PARAMS="$PARAMS -v $PWD:$WORK_DIR"
PARAMS="$PARAMS -w $WORK_DIR"

USER_ID=$(id -u)
GROUP_ID=$(id -g)

run_docker()
{
  echo \
    groupadd -f -g $GROUP_ID $DOCKER_GROUP '&&' \
    useradd -u $USER_ID -g $DOCKER_GROUP $DOCKER_USER '&&' \
    chown $DOCKER_USER:$DOCKER_GROUP $WORK_DIR '&&' \
    sudo -u $DOCKER_USER HOME=$HOME_DIR $COMMAND
}

if [ -z "$DOCKER_HOST" ]; then
    docker run $PARAMS $DOCKER_IMAGE "$(run_docker) $*"
else
    docker run $PARAMS $DOCKER_IMAGE $COMMAND "$*"
fi

que tal usar ACLs do sistema de arquivos no diretório do host? Dessa forma, você pode dizer ao sistema de arquivos para aplicar permissões específicas a arquivos recém-criados dentro do diretório. Se você definir a ACL no nível do host, se você modificar os dados do contêiner, isso também acontecerá.

@thaJeztah @justincormack @cpuguy83

@kamechen parece estar certo de que os volumes nomeados "simplesmente funcionam". No caso dos volumes nomeados, as permissões existentes "ficam pela culatra" e alteram as permissões de volume, e eu, pessoalmente, considero isso um bug (#28041).

@thegecko , por que não levar essa abordagem adiante e não criar usuários em um ponto de entrada?

Aqui está meu exemplo, ele detecta um proprietário do diretório montado, cria um usuário com o mesmo UID e executa o comando desse usuário:

Dockerfile

FROM ubuntu

RUN mkdir /project
VOLUME /project

ENV GOSU_VERSION 1.9
RUN set -x \
    && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
    && dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
    && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
    && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc" \
    && export GNUPGHOME="$(mktemp -d)" \
    && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
    && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
    && rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \
    && chmod +x /usr/local/bin/gosu \
    && gosu nobody true \
    && apt-get purge -y --auto-remove ca-certificates wget

ADD entrypoint.sh /

ENTRYPOINT ["/entrypoint.sh"]

CMD /project/run.sh

entrypoint.sh

#!/bin/sh

USER=dockeruser
VOLUME=/project
UID="$(stat -c '%u' $VOLUME)" && \
useradd --uid "$UID" "$USER" && \
ls -l "$VOLUME" && \
exec gosu "$USER" "$@"

run.sh

#!/bin/sh

echo "Running as \"$(id -nu)\""

Quando eu executo sudo docker build -t test . && sudo docker run --rm -v /tmp/docker-test/:/project test:latest ele gera:

total 12
-rw-r--r-- 1 dockeruser dockeruser 990 Dec 12 10:55 Dockerfile
-rwxr-xr-x 1 dockeruser dockeruser 156 Dec 12 11:03 entrypoint.sh
-rwxr-xr-x 1 dockeruser dockeruser  31 Dec 12 11:01 run.sh
Running as "dockeruser"

Alguém já considerou esta questão? Certificar-se de que seus volumes tenham o mesmo gid e uid que seus contêineres dificulta o gerenciamento de seus contêineres para não usar root. As melhores práticas do Docker recomendam não executar serviços com root, se possível, mas não ter que configurar o gid e o uid no host, bem como os contêineres, anulam a facilidade de uso que tornou o Docker popular?

@AndreasBackx Usar volumes apenas funciona supondo que a imagem tenha dados no caminho em que você está montando.
O uso de binds usa o UID/GID do caminho do host.

Atualmente, não há como (como em nenhum suporte ao kernel) mapear ou alterar o UID/GID de um arquivo/dir para outra coisa sem alterar o original, a menos que use algo como FUSE, que é terrivelmente lento.

Mas vamos dar um passo atrás por um momento.
O Docker não está realmente dificultando as coisas aqui.
O UID/GID no contêiner é o mesmo que o UID/GID no host... mesmo que os nomes de usuário/grupo não correspondam, o UID/GID é o que importa aqui.
Assim como sem o docker, você precisa criar um uid/gid que deseja usar para seus serviços e usá-lo fora da convenção.
Lembre-se, um uid/gid não precisa existir em /etc/passwd ou /etc/group para que a propriedade do arquivo seja definida para ele.

@cpuguy83 obrigado pela explicação.

Eu me deparei com esse problema hoje ao criar um pipeline node , meu UID de usuário do host é 1000 e a imagem node cria um usuário personalizado com esse UID específico , há até um problema sobre isso

Eu usaria o usuário do nó e seguiria em frente, mas parece um pouco sujo. Eu realmente compartilho o que você escreveu @cpuguy83 sobre "vamos voltar um pouco", mas às vezes pode se tornar um problema difícil de resolver.

Acabei de descobrir a opção -o em usermod para permitir IDS duplicados, parece uma opção legítima.

RUN usermod -o -u 1000 <user>

Não tenho certeza por que isso não foi corrigido de maneira razoável.

docker run -it -u 1000:4211 -v /home/web/production/nginx_socks:/app/socks -e SOCKS_PATH=/app/socks --name time_master  time_master

acesse para ver:

drwxr-xr-x    8 geodocr_ geodocr       4096 Jun  4 18:51 .
drwxr-xr-x   57 root     root          4096 Jun  6 21:17 ..
-rwxrwx---    1 geodocr_ geodocr        140 Jun  4 18:49 .env
-rwxrwx--x    1 geodocr_ geodocr         78 Jun  4 18:49 entrypoint.sh
drwxrwxr-x    2 geodocr_ geodocr       4096 Jun  4 18:51 handlers
-rwxrwx---    1 geodocr_ geodocr        242 Jun  4 18:49 requirements.txt
-rwxrwx---    1 geodocr_ geodocr       1270 Jun  4 18:49 server.py
drwxr-xr-x    2 root     root          4096 Jun  6 21:00 socks
drwxr-xr-x   10 geodocr_ geodocr       4096 Jun  4 18:51 utils

O dockefile faz especificamente

RUN adduser  -D -u 1000 $USER 
#
RUN addgroup $GROUP -g 4211 
#
RUN addgroup $USER $GROUP 
RUN mkdir /app/socks
USER $USER  
#

Não faz sentido que este volume seja montado como root, quando nem o usuário no container está selecionado, nem o usuário que está executando o comando selecionado. Eu poderia entender se o comando RUN foi montado como o usuário que está executando o comando, ou o usuário que possui o diretório, ou mesmo o usuário que está especificado no Dockerfile.

Nenhum deles é root, então montar como root parece ser um bug.

Também acabei de verificar, criando um volume e montando-o funciona. Então ainda é um bug.

@disarticulate Se você quiser que o caminho do host seja algo diferente da raiz, altere o caminho do host.

Acho que isso não foi mencionado antes, mas esse bug é particularmente irritante quando você confia no Docker para criar o volume do host para você. O Docker parece sempre criar o volume do host com root, mesmo quando o diretório em que você está montando tem um proprietário diferente.

Parece que a coisa correta a fazer aqui seria criar o volume com permissões de propriedade pertencentes ao USER da imagem.

@jalaziz o que deve fazer quando o usuário do contêiner não existe no host? Um dos principais benefícios dos contêineres é que você não precisa expor suas dependências (incluindo usuários) ao host.

@taybin Eu esperaria que o Docker apenas criasse a pasta com o uid:gid do usuário do contêiner OU se a pasta existir dentro do contêiner, ele criaria a pasta host com o mesmo uid:gid e mask.

OBSERVAÇÃO: não espero permissões de alteração do Docker se a pasta já existir no host.

@taybin Exatamente como @frol descreveu. Ele deve usar apenas o uid:gid do contêiner.

No entanto, isso revela meu problema geral com a abordagem atual. Eu tenho que saber o uid que o contêiner usa para permitir gravações e definir permissões nos diretórios do host com base nesse uid:gid. Se um autor upstream alterar o uid, as permissões serão interrompidas. Tudo parece muito frágil.

No meu caso, eu não tinha necessariamente controle explícito sobre qual imagem do Docker estava sendo usada (não podia simplesmente editar um Dockerfile ao meu gosto).

Então, eu tentei isso:

docker run -it -u $(id -u $USER):$(id -g $USER) -v $(pwd):/src -w /src node:latest npm run build

Que cria uma pasta chamada ./built-app . No entanto, o proprietário ainda era root com permissões estritas.

Minha solução foi essa:

docker run -it -v $(pwd):/src -w /src node:latest /bin/bash -c "npm run build; chmod -R 777 ./built-app"

Que ainda tem root proprietário, mas permissões relaxadas. Então meu sistema operacional host (Ubuntu) conseguiu acessar ./built-app sem privilégios sudo.

@ rms1000watt você tentou o seguinte comando?

docker run -it -v $(pwd):/src -w /src node:latest /bin/bash -c "npm run build; chown -R ${UID}:${GID} ./built-app"

Isso deve funcionar, pois usaria UID e GID do seu host diretamente nos próprios arquivos. Usar chmod -R 777 geralmente é uma prática ruim.

@saada Opa! Boa decisão. Vou dar-lhe um tiro.

Eu poderia realizar minha abordagem lendo isso e entendendo como _UID e GID funcionam em contêineres do Docker_
https://medium.com/@mccode/understanding -how-uid-and-gid-work-in-docker-containers-c37a01d01cf

Basicamente, há um único kernel e um único pool compartilhado de uids e gids, o que significa que a raiz da sua máquina local é a mesma que a raiz do seu contêiner, ambos compartilham o mesmo UID


Eu tenho um servidor apache e quero compartilhar meus arquivos de webapp com o contêiner apache para modificá-lo no host (desenvolvimento, alterá-los usando um editor de texto) e ver os resultados por um processo em execução no contêiner. Às vezes esse processo, escrever novos arquivos e se eu não alterar o comportamento padrão com os privilégios que os arquivos são gerados pelo usuário root e meu usuário local não pode mais modificá-los.

O que eu fiz foi gerar uma imagem personalizada adicionando isso no meu dockerfile:

RUN adduser -D -u 1002 dianjuar -G www-data
USER dianjuar

Talvez para tornar meu docker-compose.yml portátil para que qualquer pessoa possa usá-lo é preciso colocar alguns parâmetros no processo de construção.

Aqui está um padrão de contêiner para atribuir o userid/groupid em tempo de execução de uma maneira que seja facilmente portátil. https://github.com/Graham42/mapped-uid-docker

Do jeito que eu segui:

1- crie o diretório no servidor host
2- altere suas permissões para o usuário que possui userid e groupid = 1000
3- correr docker-compose up
verifiquei o recipiente e está tudo bem.

Nota: Eu estava usando o usuário root no servidor host e suponho que se eu estivesse usando um usuário não root que tenha uid = 1000 eu seria capaz de montar o volume sem me preocupar com a permissão, mas ainda não testei. Alguém seguiu um caminho semelhante?

Problema típico:

  • enxame docker, então CAPP_ADD não está disponível, o bind-mount não é uma solução
  • dois contêineres de duas imagens diferentes compartilham o mesmo volume, portanto, bancos de dados de usuários/grupos diferentes em ambos
  • por exemplo, deve-se ter direitos de acesso www-data (ou seja, vamos criptografar o downloader de certificados)
  • o outro também usa www-data (ou seja, nginx)
  • mas um terceiro requer acesso do usuário openldap (ou seja, servidor openldap)
  • tão simples chmod também não é uma solução

Isso significa que eu tenho um servidor web, que obtém certificados SSL para seus domínios do let's encrpt e um servidor OpenLDAP para o mesmo domínio, onde quero reutilizar os certificados.

Existem outras combinações que se deparam exatamente com o mesmo problema.

Alguma idéia de como resolver isso?

Como você resolveria isso sem o Docker? Este não é um Docker específico
problema.

Em sex, 12 de janeiro de 2018 às 10h24, Marc Wäckerlin [email protected]
escreveu:

Problema típico:

  • enxame docker, então CAPP_ADD não está disponível, o bind-mount não é um
    solução
  • dois contêineres de duas imagens diferentes compartilham o mesmo volume, então
    diferentes bancos de dados de usuários/grupos em ambos
  • por exemplo, deve-se ter direitos de acesso www-data (ou seja, vamos criptografar
    baixador de certificados)
  • o outro também usa www-data (ou seja, nginx)
  • mas um terceiro requer acesso do usuário openldap (ie openldap
    servidor)
  • tão simples chmod também não é uma solução

Isso significa que eu tenho um servidor web, que obtém certificados SSL para seus domínios
de vamos encrpt e um servidor OpenLDAP para o mesmo domínio, onde eu quero
para reutilizar os certificados.

Existem outras combinações que se deparam exatamente com o mesmo problema.

Alguma idéia de como resolver isso?


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/moby/moby/issues/2259#issuecomment-357267193 ou silenciar
o segmento
https://github.com/notifications/unsubscribe-auth/AAwxZgyvdCwGGVkUqCxK9nDFw1zxSKjUks5tJ3kXgaJpZM4BGxv9
.

--

  • Brian Goff

Mesmo sem swarm, consegui resolver no docker: bind-mount.

É um problema específico do docker-swarm, porque não há CAP_ADD.

As montagens de ligação @mwaeckerlin não podem mapear para diferentes IDs de usuário.
Mas mesmo com o swarm você pode ligar a montagem.... por que o CAP_ADD é necessário?

Sem CAP_ADD, a montagem dentro do docker falha.

Mas ao escrever meu comentário, acabei de obter uma solução possível, mas infelizmente isso exige alterar o Dockerfile em ambas as imagens, para que não funcione para a biblioteca ou outras imagens de terceiros:

  • crie um grupo com um ID de grupo comum explicitamente gven em todos os Dockerfiles
  • dar direitos ao grupo

@mwaeckerlin Por que você precisa montar dentro do contêiner?

Porque não posso especificar um usuário/grupo com a opção de encaixe -v .

A ideia especificada acima foi: Bind-mount dentro do container, então chown no destino não deve alterar a fonte.

@mwaeckerlin Se você mudar, mudou em todos os lugares. Este é o cerne do problema nesta edição.
Chowning/Chmoding um arquivo/diretório montado em bind muda os dois lugares.

Também não há necessidade de poder montar dentro do contêiner, você pode --mount type=bind,source=/foo,target=/bar

Sim, acabei de testar fora do docker, então a ideia acima está errada.

O principal problema, que tenho visto com frequência no docker, é que os usuários, grupos não são idênticos em imagens diferentes, mesmo quando o mesmo nome de usuário ou nome de grupo existe em ambos, eles geralmente têm ids diferentes.

Aqui algo assim ajudaria pelo menos em alguns casos: --mount type=bind,source=/foo,target=/bar,user=me,group=mine

Alguma recomendação ou prática recomendada em relação a este tópico: usuário de volume compartilhado por usuários diferentes em imagens diferentes no docker swarm?

  1. Não compartilhe volumes
  2. Sincronize seu uid/gids
  3. Certifique-se de que as permissões sejam permissivas o suficiente para todos que estão compartilhando
  4. Use montagens de fusíveis no host para vincular a diferentes uid/gids para cada contêiner

Você pode detalhar o ponto 4?
Um exemplo prático talvez de como fazer isso?

Em sex, 12 de janeiro de 2018, 17:27 Brian Goff, [email protected] escreveu:

>

  1. Não compartilhe volumes
  2. Sincronize seu uid/gids
  3. Certifique-se de que as permissões sejam permissivas o suficiente para todos que estão compartilhando
  4. Use montagens de fusíveis no host para vincular a diferentes uid/gids para cada
    recipiente


Você está recebendo isso porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/moby/moby/issues/2259#issuecomment-357282169 ou silenciar
o segmento
https://github.com/notifications/unsubscribe-auth/AHSjvgjb0BFbJhZ1VWM-pLGfa7tRBvDNks5tJ4VPgaJpZM4BGxv9
.

Usando algo como https://bindfs.org/ -- existe pelo menos um plugin de volume do Docker que já o implementa (https://github.com/lebokus/docker-volume-bindfs é o primeiro resultado que encontrei via Google) .

eu não posso alterar a permissão depois de montar o volume, alguém conseguiu isso?

uma solução alternativa:
Adicionando isso ao Dockerfile
RUN echo "if [ -e container_volume_path ]; then sudo chown user_name container_volume_path; fi" >> /home/user_name/.bashrc
A propriedade do container_volume_path é alterada após a montagem do volume.

Ser capaz de mapear uid e gid parece um elemento misterioso ausente para o manuseio do volume do docker. O caminho menos surpreendente seria incluí-lo e as correções sugeridas são desajeitadas e mais difíceis de descobrir, embora não ofereçam benefícios de práticas recomendadas:

Ré:
1) Não compartilhe volumes

  • Bom, mas irrelevante para a discussão sobre mapeamento de uid/gid
    2) Sincronize seu uid/gids
  • É isso que a funcionalidade pretende fazer, mas sem forçar um chown em um Dockerfile
    3) Certifique-se de que as permissões sejam permissivas o suficiente para todos que estão compartilhando
  • Isso novamente depende do comportamento definido em um Dockerfile, quando poderia ser um mapeamento simples
    4) Use montagens de fusíveis no host para vincular diferentes uid/gids para cada contêiner
  • Bom conselho, isso também parece barbear de iaque.

@colbygk

quando poderia ser um simples mapeamento

Esse é o problema, não é possível fazer um "mapeamento simples" pois não é suportado na camada vfs.
Alguns sistemas de arquivos fornecem a capacidade de mapear a propriedade (por exemplo, bindfs ou nfs), mas atualmente não é possível implementar isso no caso genérico.

Eu preciso de volumes compartilhados, por exemplo, na seguinte situação:

Certificados compartilhados

  • container 1 é um proxy reverso que lida com vamos criptografar para todos os domínios hospedados
  • container 2 é um servidor ldap que também precisa fornecer o certificado de seu domínio

solução: o contêiner de imagem 2 herda da mesma imagem que o contêiner 1, a imagem base comum cria um grupo comum, então ambos os contêineres têm o mesmo acesso ao grupo

Dockerfile de base comum :

RUN groupadd -g 500 ssl-cert

letsencrypt-config.sh na imagem vamos criptografar :

chgrp -R ssl-cert /etc/letsencrypt

Dockerfile de mwaeckerlin/reverse-proxy :

RUN usermod -a -G ssl-cert www-data

Dockerfile de mwaeckerlin/openldap :

RUN usermod -a -G ssl-cert openldap

É isso.

Tudo isso ilustra como alterar userperms durante o ponto de entrada ou durante o processo de compilação para que todo o docker seja executado em um usuário diferente.

Mas talvez eu perca um grande ponto depois de pesquisar na web nos últimos 3 dias.
Nenhuma das recomendações acima ou vinculadas e (soluções alternativas) funcionará de forma alguma.

Todos os volumes montados em um contêiner são sempre de propriedade de root:root dentro do contêiner. Independentemente se eu alterar o proprietário antecipadamente no host com UID/GID correspondente ou não.

Eu não posso perder a sensação de que estou sendo estúpido tentando fazer algo muito básico - do meu ponto de vista.

  • Windows 10 Pro 1803 (17134.112)
  • Docker para Windows 18.03.1-ce-win65 (17513)
  • Windows WSL com Hyper-V e Ubuntu

Tentando iniciar um contêiner apache2 simples, onde a raiz do documento é montada no host, para que eu possa desenvolver no código-fonte php enquanto o testo imediatamente no contêiner docker.

root<strong i="16">@win10</strong>:# docker run --rm -v /c/Users/<MyUser>/Development/www-data:/var/www/html -it httpd:2.4 /bin/bash

Dentro do contêiner docker, o diretório _/var/www/html_ é sempre de propriedade de _ root:root_ , então meu aplicativo php nunca será capaz de fopen ou escrever com nenhum dado dentro dessa pasta.
Nada funcionou ainda... :(

Para quem busca uma solução razoavelmente elegante veja o que o @elquimista sugeriu aqui . Eu testei isso e está funcionando bem

Estamos usando https://github.com/boxboat/fixuid#specify -paths-and-behavior-across-devices com sorte. Além disso, ele configura um usuário dentro do contêiner para corresponder a um usuário no host.

Aqui está um exemplo de configuração da imagem:

$ cat /etc/fixuid/config.yml
user: lion
group: lion
paths:
  - /home/lion
  - /home/lion/.composer/cache
  - /tmp

e para executar:

$ docker run --rm -it --init \
    -u 1000:1000 \
    -v `pwd`:/app \
    -v "$HOME/.composer/cache:/home/lion/.composer/cache" \
    --entrypoint='fixuid' \
    php:7.2-cli \
        /bin/bash

Observe que isso também é um incômodo ao usar sistemas de armazenamento que não oferecem suporte a permissões e propriedade unix. Nesse caso a montagem do storage deve ser feita para que ele obtenha o uid correto para uso dentro do container pois qualquer tentativa de chown os arquivos simplesmente falha. Se houvesse uma maneira de dizer ao docker para apresentar os arquivos como pertencentes a um determinado uid, independentemente da propriedade fora do contêiner, isso simplificaria as coisas.

@tlhonmey

Se houvesse uma maneira de dizer ao docker para apresentar os arquivos como pertencentes a um determinado uid

Não há, não sem um sistema de arquivos personalizado (por exemplo, como o bindfs).

@tlhonmey Sim, consegui contornar o problema de "sistemas de armazenamento que não suportam permissões unix" com alguns links simbólicos.

Basicamente, montando a partir de unidades NTFS, eu colocaria as coisas em -v ./HostNtfsStuff:/data/ntfsMount e depois faria um link simbólico e mostraria que ln -s -T /data/ntfsMount /var/lib/myApp && chown -Rh myApp:myApp /var/lib/myApp/

Você também pode testar: su myApp -c 'echo foo > /var/lib/myApp/bar' && cat /data/ntfsMount/bar

Meu uso era para que os desenvolvedores do Windows pudessem executar contêineres MySQL e persistir em volumes montados, mas isso se aplica a muitos aplicativos.

Portanto, a solução é gerenciar manualmente vários pares uid:gid e esperar que eles não entrem em conflito no host ou em um script auxiliar ou:

Existe _one_ maneira de fazê-lo funcionar, mas você precisa se preparar com antecedência dentro do seu Dockrfile.

RUN mkdir -p /var/lib/redis ; chown -R redis:redis /var/lib/redis
VOLUME ["/var/lib/redis"]
ENTRYPOINT ["usr/bin/redis-server"]
USER redis

(Eu não testei este exemplo, estou trabalhando em um contêiner de cromo que é exibido em um contêiner _separate_ X11 que .... )

Eu estava usando a última técnica até hoje quando tentei ligar o volume do container e ele quebrou. Aparentemente você não pode fazer isso. O volume é criado como root e, em seguida, o aplicativo interno não pode gravar nele como o usuário. O preenchimento automático descrito na documentação do VOLUME também não parece funcionar com a montagem de ligação.

Eu vi isso lendo Dockerfile Best Practices e o script auxiliar é o que eles recomendam:

#!/usr/bin/env bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

Portanto, um chown recursivo para garantir que você tenha propriedade em cada início e, em seguida, execute seu aplicativo como o usuário. exec também força o PID 1 para que os sinais funcionem. E se eu quiser preencher o volume com algo como um script auxiliar para uso fora do contêiner nos dados resultantes, provavelmente também será necessário entrar no script auxiliar. Perguntando-se, no entanto, se há um impacto no desempenho no início do contêiner se seu aplicativo armazenar muitos arquivos em um volume, especialmente se o armazenamento não for local.

Parece que poderia haver uma solução melhor. Talvez algo como mapear o uid e o gid do contêiner para um nome de usuário e grupo especificados no host. O docker pode espiar o /etc do contêiner e descobrir isso talvez?

Você não pode mapear uids/gids no nível do sistema de arquivos, pelo menos não sem fusível.

Você não pode mapear uids/gids no nível do sistema de arquivos, pelo menos não sem fusível.

Tipo o que eu estava temendo. Alguma ideia de qual seria a penalidade de desempenho se o docker usasse um fusível assim?

@mdegans

Então, um chown recursivo para garantir que você tenha propriedade em todas as partidas,

Você não precisa fazer chown em cada partida. Em vez disso, verifique o proprietário do diretório de dados e só faça o chown recursivo se não estiver correto. Como isso:

 [ $(stat -c %U "$PG_DATA") == "postgres" ] || chown -R postgres "$PG_DATA"

Então, idealmente, isso acontecerá apenas na primeira partida.

E tenha muito cuidado ao executar um contêiner com esse script de ponto de entrada; se você montar (por exemplo) seu diretório inicial no contêiner, todos os seus arquivos serão chown para postgres

Em um bom design de imagem do docker, o usuário em tempo de execução não é root e, portanto, não pode chown arquivos…!

Em um bom design de imagem do docker, o usuário em tempo de execução não é root e, portanto, não pode chown arquivos…!

Correto, mas não deve haver nada que impeça uma mudança de e para root que geralmente é necessário ... assim como você normalmente não deve executar nada como root até precisar, mas quando você fizer isso, poderá fazer um ou mais dos seguintes procedimentos:

  • sudo
  • su
  • USER root

Conforme: https://f1.holisticinfosecforwebdevelopers.com/chap03.html#vps -countermeasures-docker-the-default-user-is-root

Na minha humilde opinião, cabe ao usuário da imagem do Docker garantir que ele defina a permissão no volume montado corretamente.

É muito semelhante ao que fazíamos tradicionalmente antes que os contêineres existissem, por exemplo, quando eu queria executar o nginx e precisava ter certeza de que o diretório HTML estático era de propriedade do usuário certo. Para saber que eu precisaria abrir meu arquivo nginx.conf, verifique o usuário dos workers e defina as permissões de acordo. Na verdade, tudo isso foi descrito na documentação do nginx.

Este é apenas um problema de permissão do Unix, nada de novo com o Docker aqui. Portanto, talvez a solução para esse problema seja uma documentação melhor para cada imagem do Docker do que deve ser a propriedade dos volumes montados. Não me lembro do daemon de inicialização do nginx certificando-se de que o diretório tinha a propriedade correta, ele simplesmente falharia se não fosse configurado corretamente.

No entanto, é verdade que, como agora temos usuários potencialmente definidos dentro do contêiner e não fora, isso faz com que as coisas pareçam diferentes (e não são). Mas o UID interno e externo são equivalentes, portanto, o foobar do usuário com UID 2000 pode existir dentro de um contêiner e não fora, mas o UID 2000 ainda pode ser definido em arquivos e diretórios do lado de fora. Temos que mudar nosso pensamento em termos de UID/GID em vez dos nomes amigáveis ​​com os quais costumávamos lidar.
Também torna as coisas potencialmente mais difíceis se você precisar compartilhar um volume entre 2 contêineres escritos por 2 autores diferentes. É possível que definir permissões usando o sistema Unix tradicional (de usuário, grupo e outros) não seja suficiente para resolver o problema (sem UID ou GID comum). Admito que, como uso o Docker, estou fazendo muito mais usos do POSIX ACL. Portanto, posso atribuir 3 permissões de usuários diferentes ao mesmo arquivo. por exemplo, um escritor de contêiner com permissão rw, um leitor de contêiner com permissão r e um usuário de host com permissão r.

Mais uma opção: o GID comum pode ser aplicado usando o sinalizador setgid para diretórios compartilhados. A máscara de arquivo pode ser imposta usando ACL.

Antes de fazer qualquer coisa no contêiner do Docker, execute:

```
umask 0000
````

https://en.wikipedia.org/wiki/Umask

Passando tarde para este tópico para reafirmar o quão útil esse recurso seria.

Para ser honesto, estou implantando contêineres há cerca de um ano e vejo isso se tornando um problema real em todo o lugar. Fornecer uma solução neste nível, aqui, parece ser a única escolha sensata.

Como está hoje, um número considerável de imagens do Docker optou por continuar executando seus pontos de entrada como root para que possam inicializar permissões de diretório e arquivo apenas para descartar privilégios antes de executar o processo do aplicativo.

Um problema real aparece quando você percebe que nem todos podem recorrer a essa prática. Para algumas plataformas populares, como Kubernetes ou OpenShift, alguns desses ambientes podem ser configurados para não permitir contêineres privilegiados... por... segurança. Do topo da minha cabeça, não consigo ver como uma grande instituição financeira consideraria adotar uma plataforma de contêiner processando informações confidenciais sem esse tipo de restrição.

As preocupações de segurança levantadas pela prática _entrypoint-as-root_ levaram um grande número de gráficos de comando do Kubernetes a fornecer initContainers que podem chown e chmod volumes antes que o contêiner do aplicativo seja iniciado . Isso pode parecer uma boa maneira de contornar isso, mas confie em mim quando digo isso: não é .

Os gráficos do Helm, em particular, estão cheios de uids e gids codificados porque eles precisam ser extraídos secretamente do tempo de execução do aplicativo. Essas informações estão ocultas dentro do contêiner e não estão disponíveis imediatamente durante a implantação.

Embora haja várias maneiras de contornar o problema, ele continua a atormentar as configurações de implantação como um _hack para fazer as coisas funcionarem_. O número de implantações afetadas por isso está aumentando rapidamente e as técnicas às quais as pessoas estão recorrendo são contrárias a todos os outros benefícios que os contêineres trazem para a mesa.

Espero que haja uma maneira de implementar isso como parte da especificação OCI para que outras soluções que dependem do Docker possam usá-lo para fornecer uma implantação totalmente automatizada de maneira elegante.

Então, a pergunta se torna: onde mais na internet eles desenvolvem a especificação OCI comum, onde essa discussão deve ser feita? Assumindo que essa não é a melhor maneira de colocar esse recurso no docker (eventualmente, por meio de um requisito de conformidade para uma futura adoção de padrões de comum acordo).

Uma vez que o problema definitivamente não desaparece sozinho, e a solução requer alguns tipos de mudanças fundamentais.

initContainers que podem chown e chmod volumes antes que o contêiner do aplicativo seja iniciado. Isso pode parecer uma boa maneira de contornar isso, mas acredite em mim quando digo isso: não é.

FWIW; esse recurso só seria necessário para situações em que os arquivos são compartilhados entre vários namespaces (arquivos (pré-) existentes no "host" ou um local de arquivo comum compartilhado entre vários contêineres executados como usuários diferentes). Em situações em que os arquivos são pré-criados no host, isso pode ser atenuado certificando-se de que esses arquivos tenham a propriedade e as permissões corretas antes de compartilhá-los com o contêiner. Efetivamente, isso não é diferente de (por exemplo) executar o nginx no host e garantir que os arquivos no webroot tenham as permissões corretas.

Ao compartilhar entre contêineres que estão sendo executados como um usuário diferente, execute os dois contêineres com o mesmo uid (ou gid e defina as permissões de grupo corretas, semelhante a como isso funcionaria ao executar dois processos não conteinerizados que precisam ter acesso aos mesmos recursos).

alguns desses ambientes podem ser configurados para não permitir contêineres privilegiados... por... segurança. Do topo da minha cabeça, não consigo ver como uma grande instituição financeira consideraria adotar uma plataforma de contêiner processando informações confidenciais sem esse tipo de restrição.

Apenas para evitar confusão; um container rodando como root não é o mesmo que um container "privilegiado" ( --privileged ou opções, como --cap-add set). Contêineres privilegiados ( --privileged ) são altamente inseguros, enquanto um contêiner executado como root está totalmente contido e não poderá ser interrompido ; passá-lo de arquivos/diretórios montados em ligação está abrindo buracos nisso, então _vai_ dar acesso aos arquivos/diretórios que você passa como uma montagem de ligação.

Os gráficos do Helm, em particular, estão cheios de uids e gids codificados porque eles precisam ser extraídos secretamente do tempo de execução do aplicativo. Essas informações estão ocultas dentro do contêiner e não estão disponíveis imediatamente durante a implantação.

Imaginando: se esses uids/gids não são conhecidos; como seria o UX? (como eu teria que fornecer um mapeamento uid/gid para usar para mapear um host uid/gid para um (desconhecido) container-uid/gid ?

Então, a pergunta se torna: onde mais na internet eles desenvolvem a especificação OCI comum, onde essa discussão deve ser feita?

Eu não acho (de relance) que uma mudança na especificação OCI seja necessária; isso pode ser resolvido fora da especificação OCI; o principal problema é que os mecanismos para mapear uids/gids estão faltando no kernel (ou existem (como shiftfs ), mas não comumente disponíveis)

Este é um pentagrama clássico da passagem de responsabilidades / outra pessoa pode ou deve resolver este problema. Ou é o:

  • Do utilizador
  • A implementação específica da plataforma Docker / conteinerização
  • Especificação OCI
  • Núcleo
  • Sistema de arquivo

O problema já foi efetivamente declarado: que fazer o usuário fazer isso é desajeitado e menos seguro. No entanto, o efeito indireto de ter usuários fazendo hacks por imagem também é importante:

Que é que você não pode tão facilmente interoperar e compartilhar / misturar imagens para trabalhar em conjunto de diferentes usuários. Assim também:

  • Quebra o compartilhamento da comunidade (bastante). Como diferentes usuários definem a partir do mesmo namespace global, seus uids e gids para suas imagens desenvolvidas individualmente
  • Força os usuários a desenvolver seu próprio padrão ad-hoc e esperar que outros sigam uma convenção que eles mesmos escolheram
  • Força os usuários a usar root para tudo. O que é certamente menos seguro. Porque você está eliminando uma camada extra de proteção de escalonamento privilegiada que você teria de outra forma. E torna as vulnerabilidades de fuga de contêiner muito mais fáceis de explorar, já que o usuário já está root dentro do contêiner para começar. Sem falar em poder rodar outros serviços dentro do mesmo container, que também é outra forma de ir de lado, antes de subir.

Então é um comércio. Os acima são os trade-offs atuais. Considerando que você teria um conjunto diferente de compensações para passar a responsabilidade para outro lugar, para uma ou mais das outras entidades listadas acima.

BTW em relação a examinar mais de perto uma solução baseada em sistema de arquivos, descobrimos este comentário 'potencialmente pode ser útil' de links de aranha:

https://github.com/docker/compose/issues/3270#issuecomment -365644540

Que tem várias referências diferentes a esse mesmo recurso geral (para outros projetos / locais), incluindo um sistema de arquivos distribuído (conhecido como 'Lustre') e outros problemas relacionados ao ZFS. Bem, eu mesmo estou usando o ZFS aqui.

Em seguida, também encontrei outra cópia do mesmo bug no ubuntu / launchpad. Fazendo referência ao mesmo problema ZOL #4177,

https://bugs.launchpad.net/ubuntu/+source/zfs-linux/+bug/1567558

O que diz que o bug em questão foi corrigido no zfs versão 0.6.5.7+ SO. Isso significa que potencialmente podemos usar zfs e ACLs, como algum tipo de armazenamento de apoio para remapear uids e gids de alguma forma? Bem, isso não é algo que eu tenha ouvido antes.

Ah, talvez essa solução funcione apenas para contêineres LXC. Porque ele também estava dizendo em seus comentários lá (o líder do projeto LXC), "nós usamos ajudantes setuid (newuidmap e newgidmap)" que podem então "configurar um mapa uid e gid". Então, presumivelmente, também há algum mecanismo necessário no próprio LXC, caso contrário, a parte zfs acls não pode ser utilizada? Ou talvez eu esteja enganado. Não estou completamente certo de que sigo isso até o fim.

Outro link interessante, desta vez sobre shiftfs , e uma discussão sobre a possibilidade de absorver seus recursos em overlayfs. Que, claro, é um sistema de arquivos subjacente que o docker já usa.

No entanto, o que acontece se o recurso de remapeamento for implementado em overlayfs , mas eu quiser usar o driver de armazenamento zfs em vez do meu sistema de arquivos subjacente? Devo ficar de fora da capacidade de remapear uids/gids, se estiver sendo implementado por sistema de arquivos? Ou podemos ter ambos implementados separadamente? Desculpe, não estou um pouco claro se o daemon do Docker precisa estar ciente de tais remapeamentos e fornecer uma API e sinalizadores comuns (para passar para a camada de drivers fs). Ou se, em vez disso, estivéssemos realizando esse remapeamento manualmente no lado do host (no sistema de arquivos, fora do docker). Esse aspecto também permanece um pouco obscuro para mim.

[EDIT] opa, esqueci de incluir o link! Aqui está

https://lists.linuxfoundation.org/pipermail/containers/2018-June/039172.html

Este problema é sobre volumes / montagens de ligação, portanto, separado do sistema de arquivos do contêiner

Usaríamos excessivamente com um deslocamento uid/gid para o bindmount se a sobreposição incorporasse recursos shiftfs, mas teríamos que recorrer a outra coisa (ou nada) em sistemas não suportados.

Podman é um substituto drop-in do Docker sem raiz https://www.youtube.com/watch?v=N0hSn5EwW8w https://podman.io/ . Com o podman, o root não é usado, então a permissão do usuário é tratada corretamente. Nossa equipe mudou para o Podman devido a esse problema e funcionou muito bem.

Isso não faz sentido.
Os mesmos problemas se aplicam.
Observe que o docker também possui um modo sem raiz.

Você pode testar o Podman com os comandos a seguir. O Podman não tem um daemon separado ao contrário do Docker, e tudo é executado sob o usuário que executa os comandos podman . Portanto, os arquivos criados dentro do podman são de propriedade do usuário que executou o comando podman run ... .

kkimdev<strong i="8">@ubuntu</strong>:~$ mkdir podman_test
kkimdev<strong i="9">@ubuntu</strong>:~$ ls -agh podman_test
total 8.0K
drwxrwxr-x 2 kkimdev 4.0K Jun 27 04:23 .
drwxr-xr-x 8 kkimdev 4.0K Jun 27 04:23 ..

kkimdev<strong i="10">@ubuntu</strong>:~$ podman run --rm -it -v ~/podman_test:/podman_test alpine
/ # cd /podman_test/
/podman_test # touch test_file
/podman_test # ls -agh
total 8K
drwxrwxr-x    2 root        4.0K Jun 27 02:24 .
drwxr-xr-x   20 root        4.0K Jun 27 02:24 ..
-rw-r--r--    1 root           0 Jun 27 02:24 test_file

/podman_test #

kkimdev<strong i="11">@ubuntu</strong>:~$ ls -agh podman_test/
total 8.0K
drwxrwxr-x 2 kkimdev 4.0K Jun 27 04:24 .
drwxr-xr-x 8 kkimdev 4.0K Jun 27 04:23 ..
-rw-r--r-- 1 kkimdev    0 Jun 27 04:24 test_file

Este não é o local apropriado para anunciar podman -- se houver detalhes técnicos específicos sobre como ele funciona que possam ajudar a resolver esse problema, eles seriam relevantes para serem discutidos, especialmente como possíveis soluções para o problema que você estou comentando no momento. Até agora, não foi isso que aconteceu, então, por favor, leve essa discussão para outro lugar.

O fato de podman ter uma arquitetura muito diferente do Docker, o que torna esse problema menos grave/doloroso, não permite magicamente que o Docker mude completamente a maneira como ele funciona apenas para resolver esse problema. Posso garantir que há muitas razões pelas quais o Docker está estruturado do jeito que está, e é francamente de má fé ignorar toda essa história.

@tianon Sim, absolutamente, existem prós e contras para ambas as abordagens. Mencionei o podman apenas porque executar um contêiner com podman com o usuário de destino resolve especificamente esse problema técnico, que é "montar volume como usuário diferente de root".

Por favor, dê uma olhada na permissão de "test_file" criada no meu comentário acima. Ele primeiro monta o diretório "~/podman_test" e grava o arquivo "test_file" dentro do contêiner podman. Então, uma vez que o usuário sai do contêiner, você pode ver que o arquivo é de propriedade de "kkimdev", não de root.

O problema é que sua sugestão para corrigir um problema com o Docker é que isso equivale a "não use o Docker", o que não é muito construtivo no rastreador de problemas do Docker.

Sim, podman foi projetado de maneira diferente, o que torna esse problema discutível para essa ferramenta - isso é bom e bom, mas totalmente fora do tópico aqui. Rootless tem diferentes compensações, algumas das quais são boas para algumas pessoas, outras não. Está melhorando com o tempo (e principalmente melhorias no kernel), mas não é uma solução genérica para todos aqui.

Isso requer modificações no kernel ou um shim para uma solução genérica, conforme discutido em detalhes acima (e como @ cpuguy83 e outros estão trabalhando para tentar ajudar a resolver esse problema de maneira genérica).

O Docker tinha esse problema específico aberto desde 2013 e quase seis anos depois não há nenhuma melhoria fácil à vista. O Podman foi projetado para obter compatibilidade com o Docker, mas também resolver as falhas de design do Docker (incluindo a execução como um usuário sem privilégios que não exigirá um daemon do Docker de superusuário).

Se os usuários puderem dar conselhos a outros sobre um problema do GitHub, tudo bem. Isso é uma comunidade. Sinta-se à vontade para recomendar o que puder ser útil.

Posso garantir que há muitas razões pelas quais o Docker está estruturado da maneira que está

Assim grep . Mas se alguém precisar pesquisar mais rápido, eu ainda recomendaria ripgrep . Mesmo no rastreador de problemas grep . Não importa de quem é o rastreador de problemas, desde que resolva o problema dos usuários e os deixe felizes.

Se o Podman não funcionar para você: tudo bem! Mas se ajuda os outros porque eles só precisam substituir docker por podman em sua infraestrutura: deixe-os fazer isso.

O principal argumento do Podman é que ele não executa um daemon e esse é meu principal argumento contra ele. Como faço para recuperar meu contêiner após uma reinicialização? Eu não vou fazer isso à mão e todo o resto é apenas um design ruim. Além disso, não quero que meu contêiner docker seja de propriedade de um usuário, mas de propriedade do sistema e isso significa root.
O Podman faz sentido se você for a única pessoa a usá-lo.

E para resolver seu problema: Construa um container com COPY --chown ...:... !

Além disso, o Docker não tem esses problemas e você pode controlar remotamente os servidores docker, o que também é importante para mim.

Existem ferramentas para gerar pods a partir de contêineres em execução, o que eu não recomendo porque você deve construí-los desde o início de maneira limpa.

Acho que devemos voltar ao tópico agora: IMHO, o primeiro conselho foi bom, mas todo o resto apenas explode esse problema e não resolve nada.


@SuperSandro2000 , você pode clicar aqui para obter a resposta às suas declarações.

Como faço para recuperar meu contêiner após uma reinicialização? Eu não vou fazer isso à mão e todo o resto é apenas um design ruim.

Bem, Podman tem integração nativa com systemd (como _quase_ todas as outras coisas em quase todas as distribuições GNU Linux modernas). Portanto, você não precisa manter 'dois' sistemas de inicialização (como primeiro ter o systemd para iniciar o daemon do Docker, que depois precisa fazer outra rodada de inicialização de contêineres em uma configuração diferente). Assim, com o Podman você pode controlar tudo com o systemd (ou seja: o sistema que você provavelmente já instalou e está rodando).

Além disso, não quero que meu contêiner docker seja de propriedade de um usuário, mas de propriedade do sistema e isso significa root.

Está tudo bem se você não quiser. Você ainda pode executar o Podman como superusuário, mas não precisa mais. Em geral, é considerado uma má ideia e aumenta a superfície de ataque porque se alguém for capaz de explorar seu daemon do Docker, ele terá controle sobre _tudo_ sobre o sistema.

O Podman faz sentido se você for a única pessoa a usá-lo.

Esta afirmação não faz nenhum sentido. O Podman permite que você se espalhe em um único sistema, um recurso que faz sentido especialmente se você tiver muitas pessoas trabalhando no mesmo sistema.

E para resolver seu problema: Construa um container com COPY --chown ...:... !

IMHO o problema aqui é _mounting_ um volume para um contêiner em _runtime_. O que tem pouco a ver com a construção de uma imagem.

Além disso, o Docker não tem esses problemas e você pode controlar remotamente os servidores docker, o que também é importante para mim.

Engraçado que você mencionou exatamente o blog que tem esse post nele. No entanto, não tenho muita experiência com detalhes de rede de ambas as implementações, mas pelo que entendi, o podman começa com o mínimo de regras de rede possíveis e usuários sem privilégios não podem configurar pares veth

Para ser claro, você deve conseguir o mesmo efeito com o docker sem raiz que obtém com o podman.
Isso ocorre porque o dockerd está sendo executado como seu usuário e o root no contêiner está mapeado para seu UID.

Isso tem desvantagens e, claro, não funciona ao compartilhar um daemon com vários usuários.
https://get.docker.com/rootless

Em 27 de junho de 2019, às 7h52, Alexander Adam [email protected] escreveu:

Acho que devemos voltar ao tópico agora: IMHO, o primeiro conselho foi bom, mas todo o resto apenas explode esse problema e não resolve nada.

@SuperSandro2000 https://github.com/SuperSandro2000 , você pode clicar aqui para a resposta em suas declarações.
https://podman.io/blogs/2018/09/13/systemd.html https://osric.com/chris/accidental-developer/2018/12/docker-versus-podman-and-iptables/ https:// /osric.com/chris/accidental-developer/2018/12/using-docker-to-get-root-access/

Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, vê-lo no GitHub https://github.com/moby/moby/issues/2259?email_source=notifications&email_token=AAGDCZXX2UQCG7LUVH57V6LP4TH2DA5CNFSM4AI3DP62YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYXL2XI#issuecomment-506379613 , ou silenciar o fio https://github.com/notifications/ unsubscribe-auth/AAGDCZX437HJP4M6XG3SEY3P4TH2DANCNFSM4AI3DP6Q .

@alexanderadam

IMHO, o problema aqui é montar um volume para um contêiner em tempo de execução. O que tem pouco a ver com a construção de uma imagem.

Minha solução foi não montar o diretório, mas assá-lo no contêiner, se possível.

Quero dizer, podman soa bem, mas não vou trocar porque por enquanto não vejo nenhuma vantagem para mim. Obrigado pela explicação de qualquer maneira.

podman sofre do mesmo problema se o Apache dentro do container for executado sob o usuário www . https://github.com/containers/libpod/issues/3990

A solução pode ser mapear o usuário www do contêiner para o UID no host se não houver nenhum usuário root dentro do contêiner. Não sei se isso é possível.

Se você deseja executar com --read-only (para fazer o mesmo que a política readOnlyRootFilesystem do Kubernetes), é possível fazer o seguinte. Ele se baseia na solução alternativa que @jpetazzo estava sugerindo:

  • Minha imagem docker cria e usa um usuário com uid=1001 e gid=1001
  • Separadamente, crie um volume docker
  • Chown o uid:gid para 1001
  • Monte essa imagem ao executar o aplicativo.

Dockerfile:

FROM ubuntu

RUN groupadd -g 1001 appgroup && \
    useradd -u 1001 -g appgroup appuser

USER appuser

Então:

$ docker build . -t test
$ docker volume create somedir
$ docker run -v somedir:/some_dir alpine chown -R 1001:1001 /some_dir

Agora, ao executar a imagem do docker e montar o volume, /some_dir pertence ao usuário que eu quero.

$ docker run -it --read-only -v somedir:/some_dir test ls -lrt

...
dr-xr-xr-x  13 root    root        0 Nov  4 15:22 sys
drwxr-xr-x   2 appuser appgroup 4096 Nov  5 09:45 some_dir
drwxr-xr-x   1 root    root     4096 Nov  5 09:45 etc
...

$ docker run -it --read-only -v somedir:/some_dir test touch /some_dir/hello
$ docker run -it --read-only -v somedir:/some_dir test ls -lrt /some_dir

-rw-r--r-- 1 appuser appgroup 0 Nov  5 09:52 hello

Vou apontar novamente, porque é facilmente perdido no encadeamento, que um link simbólico chown provavelmente funcionará para a maioria dos cenários. A desvantagem é que você precisa de alguma forma de configurá-lo, o que geralmente significa substituir o ponto de entrada por um script que executa o comando original.

https://github.com/moby/moby/issues/2259#issuecomment -466094263

+1

Acho que esse é até agora o problema mais irritante que tenho com o docker e ver quanto tempo ele já está aberto sugere que esse não é o caso de muitos outros?

Não é um problema se você conhece a solução alternativa. Meus casos:

  • Host é Linux

    • uid no contêiner == uid desejado no host - nenhuma solução alternativa é necessária
    • uid in container != uid desejado no host - apenas execute alguns comandos setfacl e dê acesso a rw tanto para o usuário do host quanto para o usuário do contêiner
  • O host é o MacOS - tudo funciona imediatamente para o aplicativo oficial do Docker.

apenas execute alguns comandos setfacl e dê acesso a rw tanto para o usuário do host quanto para o usuário do contêiner

Isso é problema. Não quero executar alguns comandos setfacl para cada imagem do docker e detectar o sistema operacional.

Na verdade, isso também é um grande problema de segurança.

Cenário de exemplo:

  • host1 tem o docker instalado
  • host1 tem um serviço múltiplo em execução em contêineres docker - todos os quais são caminhos locais de montagem em /docker/my-service-01|02|03|etc
  • cada contêiner foi construído por um fornecedor diferente e cada um segue sua própria política uid e guid , exigindo assim que você chown -R uid.gid /docker/my-service-01... acordo.

Resultado:

  • Em algum momento, usuários normais ou de serviço criados em host terão acesso total a /docker/my-service-01|02|03|etc que não é pretendido nem desejado.
  • Se você quiser montar um volume como "somente leitura" em dois contêineres de fornecedores diferentes - ele falhará, pois o uid.gid não corresponderá aos necessários e você não poderá chown porque cada container tem sua própria política de uid.gid e são diferentes :)

Sim, nós discutimos esse problema detalhadamente anteriormente e o fato chave que estava sendo comunicado (naquela época) era que o kernel do Linux não tinha um mecanismo de suporte subjacente para fornecer uids e gids remapeáveis. Portanto, seria necessário adicionar ao kernel para que este projeto (moby / docker) implementasse essa funcionalidade altamente desejável. Caso contrário, já teríamos obtido esse recurso há algum tempo. Quando foi visto pela primeira vez.

Portanto, a maneira mais produtiva de continuar essa discussão (hoje) seria: Veja se alguma dessas situações mudou desde então. Procure um comentário técnico dos desenvolvedores da linha principal do kernel linux em vger.org. Procure conjuntos de patches anteriores / solicitações de mesclagem no kernel para esse recurso ausente subjacente. etc.

Na esperança de uma melhor compreensão do que vem acontecendo nesse nível inferior. Qual foi o obstáculo? Foi um problema de desempenho? Foi uma objeção em termos do modelo de segurança/enfraquecimento? Ainda está na mesa ou em um roteiro futuro, mas só faz sentido depois que outros recursos B e C puderem ser implementados? Todo esse desenvolvimento do kernel continua em outro lugar. Em outros canais.

@DXist O fato de isso funcionar magicamente no OSX e não no Linux é surpreendente e um problema em si.

De acordo com o último comentário do @dreamcat4 , alguém fez uma nova tentativa de ver qual é o status disso? Temos suporte no Kernel para uids e gids remapeáveis ​​agora? Qual é o status geral aqui?

Eu usei os namespaces de usuário do Linux para resolver perfeitamente esse problema. Funciona exatamente da mesma forma (AFAICT) que as outras plataformas (o contêiner vê o volume montado no bind como root, o host o vê como o usuário que está executando o docker).

O guia está aqui: https://www.jujens.eu/posts/en/2017/Jul/02/docker-userns-remap/

@patrobinson +1

Esta página foi útil?
0 / 5 - 0 avaliações