web-dev-qa-db-fra.com

Autorisation refusée pour accéder au répertoire de l'hôte dans docker

En bref: j'essaie de monter un répertoire d'hôte dans Docker, mais je ne peux pas y accéder depuis le conteneur, même si les autorisations d'accès sont correctes.

Les détails:

Je fais

Sudo docker run -i -v /data1/Downloads:/Downloads ubuntu bash

puis

ls -al

Ça me donne:

total 8892
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 .
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 ..
-rwxr-xr-x.   1 root root       0 Jun 18 14:34 .dockerenv
-rwx------.   1 root root 9014486 Jun 17 22:09 .dockerinit
drwxrwxr-x.  18 1000 1000   12288 Jun 16 11:40 Downloads
drwxr-xr-x.   2 root root    4096 Jan 29 18:10 bin
drwxr-xr-x.   2 root root    4096 Apr 19  2012 boot
drwxr-xr-x.   4 root root     340 Jun 18 14:34 dev
drwxr-xr-x.  56 root root    4096 Jun 18 14:34 etc
drwxr-xr-x.   2 root root    4096 Apr 19  2012 home

et beaucoup plus de lignes comme ça (je pense que c'est la partie pertinente).

Si je fais

cd /Downloads
ls

le résultat est

ls: cannot open directory .: Permission denied

L'hôte est Fedora 20, avec Docker 1.0.0 et go1.2.2.

Des idées ce qui ne va pas?

239
user3753011

C'est un problème de selinux.

Vous pouvez émettre temporairement

su -c "setenforce 0"

sur l'hôte pour accéder ou ajouter une règle selinux en exécutant

chcon -Rt svirt_sandbox_file_t /path/to/volume
237
user3761313

Voir l'article de blog de Project Atomic sur Volumes et SELinux pour l'histoire complète.

Plus précisément:

Cela est devenu plus facile récemment depuis que Docker a finalement fusionné un correctif qui apparaîtra dans docker-1.7 (nous portons le correctif dans docker-1.6 sur RHEL, CentOS et Fedora).

Ce correctif ajoute le support pour "z" et "Z" comme options sur les montages de volume (-v).

Par exemple:

docker run -v /var/db:/var/db:z rhel7 /bin/sh

Fait automatiquement le chcon -Rt svirt_sandbox_file_t /var/db décrit dans la page de manuel.

Mieux encore, vous pouvez utiliser Z.

docker run -v /var/db:/var/db:Z rhel7 /bin/sh

Cela va étiqueter le contenu à l'intérieur du conteneur avec l'étiquette MCS exacte avec laquelle le conteneur sera exécuté. En gros, il exécute chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbs0:c1,c2 diffère pour chaque conteneur.

228
gregswift

AVERTISSEMENT: cette solution présente des risques de sécurité.

Essayez d’exécuter le conteneur en tant que privilégié:

Sudo docker run --privileged=true -i -v /data1/Downloads:/Downloads ubuntu bash

Une autre option (que je n'ai pas encore essayée) serait de créer un conteneur privilégié, puis de créer des conteneurs non privilégiés à l'intérieur de celui-ci.

66
John Phillips

De access.redhat.com:Sharing_Data_Across_Containers :

Les paramètres de volume de l'hôte ne sont pas portables, car ils dépendent de l'hôte et risquent de ne pas fonctionner sur aucune autre machine. Pour cette raison, il n'y a pas d'équivalent Dockerfile pour le montage de répertoires d'hôtes sur le conteneur. Sachez également que le système hôte n'a pas connaissance de la stratégie SELinux de conteneur. Par conséquent, si la stratégie SELinux est appliquée, le répertoire de l'hôte monté n'est pas accessible en écriture dans le conteneur, quel que soit le paramètre rw. Actuellement, vous pouvez contourner ce problème en attribuant le type de stratégie SELinux approprié au répertoire de l'hôte ":

chcon -Rt svirt_sandbox_file_t Host_dir

Où rép_hôte est un chemin d'accès au répertoire du système hôte monté sur le conteneur.

Cela semble être une solution de contournement mais j'ai essayé et cela fonctionne

29
Thomas8

En règle générale, les problèmes d'autorisations avec un montage de volume hôte sont dus au fait que l'uid/gid à l'intérieur du conteneur n'a pas accès au fichier conformément aux autorisations uid/gid du fichier sur l'hôte. Cependant, ce cas spécifique est différent.

Le point à la fin de la chaîne d'autorisation, drwxr-xr-x., indique que SELinux est configuré. Lorsque vous utilisez un montage hôte avec SELinux, vous devez passer une option supplémentaire à la fin de la définition du volume:

  • L'option z indique que le contenu du montage de la liaison est partagé entre plusieurs conteneurs.
  • L'option Z indique que le contenu du montage de la liaison est privé et non partagé.

Votre commande de montage en volume ressemblerait alors à ceci:

Sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash

En savoir plus sur les montages d’hôte avec SELinux à l’adresse suivante: https://docs.docker.com/storage/#configure-the-selinux-label


Pour les autres utilisateurs qui voient ce problème avec des conteneurs s'exécutant sous un utilisateur différent, vous devez vous assurer que l'ID utilisateur/gid de l'utilisateur à l'intérieur du conteneur dispose d'autorisations pour le fichier sur l'hôte. Sur les serveurs de production, cela se fait souvent en contrôlant l'uid/gid dans le processus de construction de l'image afin de faire correspondre un uid/gid sur l'hôte ayant accès aux fichiers (ou mieux, n'utilisez pas de montages d'hôte en production).

Un volume nommé est souvent préféré aux montages sur l'hôte, car il initialisera le répertoire de volumes à partir du répertoire d'images, y compris les droits de propriété et les autorisations de fichiers. Cela se produit lorsque le volume est vide et que le conteneur est créé avec le volume nommé.

Les utilisateurs MacOS ont maintenant OSXFS , qui gère automatiquement les uid/gid entre l’hôte Mac et les conteneurs. Les fichiers de l’intégré VM incorporé dans le conteneur, comme /var/lib/docker.sock, ne sont d'aucune utilité.

Pour les environnements de développement où l'hôte uid/gid peut changer par développeur, ma solution préférée consiste à démarrer le conteneur avec un point d'entrée fonctionnant en tant que root, à fixer l'uid/gid de l'utilisateur à l'intérieur du conteneur afin qu'il corresponde au volume hôte uid/gid. utilisez ensuite gosu pour passer de l'utilisateur root au conteneur afin d'exécuter l'application à l'intérieur du conteneur. Le script important pour cela est fix-perms dans mes scripts d'image de base, disponibles à l'adresse suivante: https://github.com/Sudo-bmitch/docker-base

Le bit important du script fix-perms est:

# 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

Cela récupère l'identifiant utilisateur de l'utilisateur à l'intérieur du conteneur et l'identifiant utilisateur du fichier. S'il ne correspond pas, il appelle usermod pour ajuster l'identifiant utilisateur. Enfin, il effectue une recherche récursive pour corriger les fichiers qui n'ont pas changé d'ID utilisateur. J'aime mieux cela que d'exécuter un conteneur avec un indicateur -u $(id -u):$(id -g), car le code de point d'entrée ci-dessus n'exige pas que chaque développeur exécute un script pour démarrer le conteneur. En outre, tous les fichiers hors du volume détenus par l'utilisateur ont leurs autorisations corrigées.


Vous pouvez également demander à docker d’initialiser un répertoire hôte à partir d’une image en utilisant un volume nommé qui effectue un montage lié. Ce répertoire doit exister à l'avance et vous devez fournir un chemin absolu vers le répertoire de l'hôte, contrairement aux volumes de l'hôte dans un fichier de composition qui peut être des chemins relatifs. Le répertoire doit également être vide pour que le menu fixe puisse l'initialiser. Trois options différentes pour définir un volume nommé sur un montage lié se présentent comme suit:

  # 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
  ...

Enfin, si vous essayez d'utiliser des espaces de noms d'utilisateurs, vous constaterez que les volumes hôtes ont des problèmes d'autorisation, car les uid/gid des conteneurs sont décalés. Dans ce scénario, il est probablement plus simple d'éviter les volumes d'hôte et d'utiliser uniquement des volumes nommés.

25
BMitch

J'ai vérifié que chcon -Rt svirt_sandbox_file_t /path/to/volume fonctionne et qu'il n'est pas nécessaire de l'exécuter en tant que conteneur privilégié.

C'est sur:

  • Docker version 0.11.1-dev, version 02d20af/0.11.1
  • centos7 en tant qu'hôte et conteneur avec selinux activé.
13
jeff mccormick

Essayez docker volume create.

mkdir -p /data1/Downloads
docker volume create --driver local --name hello --opt type=none --opt device=/data1/Downloads --opt o=uid=root,gid=root --opt o=bind
docker run -i -v hello:/Downloads ubuntu bash

Consultez le document https://docs.docker.com/engine/reference/commandline/volume_create/

7
cupen

J'ai eu un problème similaire, le mien a été causé par une discordance entre l'UID de l'hôte et celui de l'utilisateur du conteneur. Le correctif consistait à transmettre l'UID de l'utilisateur en tant qu'argument à la génération de menu fixe et à créer l'utilisateur du conteneur avec le même UID.

Dans le fichier Docker:

ARG UID=1000
ENV USER="ubuntu"
RUN useradd -u $UID -ms /bin/bash $USER

Dans l'étape de construction:

docker build <path/to/Dockerfile> -t <tag/name> --build-arg UID=$UID

Après cela, l’exécution du conteneur et des commandes conformément au PO m’a donné le résultat attendu.

4
RoboCop87

J'ai résolu ce problème en utilisant un conteneur de données, ce qui présente également l'avantage d'isoler les données de la couche d'application. Vous pourriez l'exécuter comme ceci:

docker run --volumes-from=<container-data-name> ubuntu

Ce tutoriel fournit une bonne explication sur l'utilisation des conteneurs de données.

0
tmsss

Dans ma situation, le problème était différent. Je ne sais pas pourquoi, mais même si le répertoire sur l'hôte avait chmod 777 exécuté, à l'intérieur du menu fixe, il était visible sous la forme 755.

L'exécution dans le conteneur Sudo chmod 777 my_volume_dir le corrige.

0
CodeSandwich