Je joue avec Docker depuis un certain temps et je continue de trouver le même problème lorsque je traite des données persistantes.
Je crée Dockerfile
et expose un volume ou j'utilise --volumes-from
pour monter un dossier hôte dans mon conteneur .
Quelles autorisations dois-je appliquer au volume partagé sur l'hôte?
Je peux penser à deux options:
Jusqu'à présent, j'ai donné à tout le monde un accès en lecture / écriture, donc je peux écrire dans le dossier à partir du conteneur Docker.
Mappez les utilisateurs de l'hôte dans le conteneur, afin que je puisse attribuer des autorisations plus précises. Je ne suis pas sûr que cela soit possible et je n'ai pas trouvé grand-chose à ce sujet. Jusqu'à présent, tout ce que je peux faire est d'exécuter le conteneur en tant qu'utilisateur:,
docker run -i -t -user="myuser" postgres
mais cet utilisateur a un UID différent de celui de mon hôtemyuser
, donc les autorisations ne fonctionnent pas. De plus, je ne suis pas sûr que le mappage des utilisateurs pose des risques de sécurité.
Y a-t-il d'autres alternatives?
Comment gérez-vous ce problème?
Réponses:
MISE À JOUR 2016-03-02 : Depuis Docker 1.9.0, Docker a nommé des volumes qui remplacent les conteneurs de données uniquement . La réponse ci-dessous, ainsi que mon article de blog lié, a toujours de la valeur dans le sens de penser aux données à l'intérieur de Docker, mais envisagez d'utiliser des volumes nommés pour implémenter le modèle décrit ci-dessous plutôt que des conteneurs de données.
Je pense que la manière canonique de résoudre ce problème consiste à utiliser des conteneurs de données uniquement . Avec cette approche, tous les accès aux données de volume se font via des conteneurs qui utilisent
-volumes-from
le conteneur de données, donc l'hôte uid / gid n'a pas d'importance.Par exemple, un cas d'utilisation donné dans la documentation est la sauvegarde d'un volume de données. Pour ce faire, un autre conteneur est utilisé pour effectuer la sauvegarde via
tar
, et il l'utilise également-volumes-from
pour monter le volume. Je pense donc que le point clé de grok est: plutôt que de penser à comment accéder aux données sur l'hôte avec les autorisations appropriées, pensez à faire tout ce dont vous avez besoin - sauvegardes, navigation, etc. - via un autre conteneur . Les conteneurs eux-mêmes doivent utiliser des uid / gids cohérents, mais ils n'ont pas besoin d'être mappés à quoi que ce soit sur l'hôte, restant ainsi portables.C'est relativement nouveau pour moi aussi, mais si vous avez un cas d'utilisation particulier, n'hésitez pas à commenter et j'essaierai de développer la réponse.
MISE À JOUR : Pour le cas d'utilisation donné dans les commentaires, vous pourriez avoir une image
some/graphite
pour exécuter le graphite et une imagesome/graphitedata
comme conteneur de données. Donc, en ignorant les ports et autres, l'Dockerfile
imagesome/graphitedata
est quelque chose comme:Générez et créez le conteneur de données:
le
some/graphite
Dockerfile devrait également obtenir le même uid / gids, il pourrait donc ressembler à ceci:Et il serait exécuté comme suit:
Ok, maintenant cela nous donne notre conteneur de graphite et le conteneur de données uniquement associé avec le bon utilisateur / groupe (notez que vous pouvez également réutiliser le
some/graphite
conteneur pour le conteneur de données, en remplaçant l'entrée / cmd lors de son exécution, mais en les ayant comme images distinctes IMO est plus clair).Maintenant, disons que vous souhaitez modifier quelque chose dans le dossier de données. Donc, plutôt que de lier le montage du volume à l'hôte et de le modifier, créez un nouveau conteneur pour faire ce travail. Permet de l'appeler
some/graphitetools
. Permet également de créer l'utilisateur / groupe approprié, tout comme l'some/graphite
image.Vous pouvez rendre ce SEC en héritant de
some/graphite
ousome/graphitedata
dans le Dockerfile, ou au lieu de créer une nouvelle image, réutilisez simplement l'une des images existantes (en remplaçant le point d'entrée / cmd si nécessaire).Maintenant, vous exécutez simplement:
et alors
vi /data/graphite/whatever.txt
. Cela fonctionne parfaitement car tous les conteneurs ont le même utilisateur de graphite avec uid / gid correspondant.Comme vous ne montez jamais à
/data/graphite
partir de l'hôte, vous ne vous souciez pas de la façon dont l'hôte uid / gid est mappé à l'uid / gid défini à l'intérieur des conteneursgraphite
etgraphitetools
. Ces conteneurs peuvent désormais être déployés sur n'importe quel hôte et continueront de fonctionner parfaitement.La chose
graphitetools
intéressante à ce sujet est qu'il pourrait avoir toutes sortes d'utilitaires et de scripts utiles, que vous pouvez désormais également déployer de manière portable.MISE À JOUR 2 : Après avoir écrit cette réponse, j'ai décidé d'écrire un article de blog plus complet sur cette approche. J'espère que ça aide.
MISE À JOUR 3 : J'ai corrigé cette réponse et ajouté plus de détails. Il contenait auparavant des hypothèses incorrectes sur la propriété et les perms - la propriété est généralement attribuée au moment de la création du volume, c'est-à-dire dans le conteneur de données, car c'est à ce moment que le volume est créé. Voir ce blog . Ce n'est pas une exigence cependant - vous pouvez simplement utiliser le conteneur de données comme "référence / handle" et définir la propriété / les autorisations dans un autre conteneur via chown dans un point d'entrée, qui se termine par gosu pour exécuter la commande en tant qu'utilisateur correct. Si quelqu'un est intéressé par cette approche, veuillez commenter et je peux fournir des liens vers un exemple utilisant cette approche.
la source
/data/newcontainer
? Je suppose que vous exécutez endocker
tant que root (est-il possible de ne pas le faire?) De plus, y a-t-il une différence dans ces autorisations si les données sont montées directement dans le conteneur principal ou via un conteneur de données uniquement ?/var/lib/docker
quelque part mais toujours une énorme douleurUne solution très élégante est visible sur l' image redis officielle et en général sur toutes les images officielles.
Décrit dans le processus étape par étape:
Comme on le voit sur les commentaires Dockerfile:
gosu est une alternative à
su
/sudo
pour un retrait facile de l'utilisateur root. (Redis est toujours exécuté avec l'redis
utilisateur)/data
volume et le définir comme répertoire de travailEn configurant le volume / data avec le
VOLUME /data
commande, nous avons maintenant un volume séparé qui peut être soit un volume docker, soit monté sur un répertoire hôte.Le configurer en tant que workdir (
WORKDIR /data
) en fait le répertoire par défaut à partir duquel les commandes sont exécutées.Cela signifie que toutes les exécutions de conteneurs s'exécuteront via le script docker-entrypoint et, par défaut, la commande à exécuter est redis-server.
docker-entrypoint
est un script qui fait une fonction simple: Modifier la propriété du répertoire courant (/ données) et abaisseur deroot
à l'redis
utilisateur d'exécuterredis-server
. (Si la commande exécutée n'est pas redis-server, elle exécutera la commande directement.)Cela a l'effet suivant
Si le répertoire / data est monté en liaison avec l'hôte, le docker-entrypoint préparera les autorisations utilisateur avant d'exécuter redis-server sous
redis
user.Cela vous donne la facilité d'esprit qu'il n'y a aucune configuration pour exécuter le conteneur dans n'importe quelle configuration de volume.
Bien sûr, si vous devez partager le volume entre différentes images, vous devez vous assurer qu'elles utilisent le même ID utilisateur / ID groupe, sinon le dernier conteneur détournera les autorisations utilisateur de la précédente.
la source
chown
à l'intérieur duENTRYPOINT
script?Ce n'est sans doute pas le meilleur moyen pour la plupart des circonstances, mais cela n'a pas encore été mentionné, alors peut-être que cela aidera quelqu'un.
Lier le volume hôte de montage
Host folder FOOBAR is mounted in container /volume/FOOBAR
Modifiez le script de démarrage de votre conteneur pour trouver le GID du volume qui vous intéresse
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
Assurez-vous que votre utilisateur appartient à un groupe avec ce GID (vous devrez peut-être créer un nouveau groupe). Pour cet exemple, je ferai comme si mon logiciel fonctionnait en tant
nobody
qu'utilisateur à l'intérieur du conteneur, je veux donc m'assurer qu'ilnobody
appartient à un groupe avec un identifiant de groupe égal àTARGET_GID
J'aime cela parce que je peux facilement modifier les autorisations de groupe sur mes volumes hôtes et savoir que ces autorisations mises à jour s'appliquent à l'intérieur du conteneur Docker. Cela se produit sans aucune autorisation ni modification de propriété de mes dossiers / fichiers hôtes, ce qui me rend heureux.
Je n'aime pas cela, car cela suppose qu'il n'y a aucun danger à s'ajouter à des groupes arbitraires à l'intérieur du conteneur qui utilisent un GID que vous souhaitez. Il ne peut pas être utilisé avec une
USER
clause dans un Dockerfile (sauf si cet utilisateur a des privilèges root je suppose). De plus, ça crie du piratage ;-)Si vous voulez être hardcore, vous pouvez évidemment l'étendre de nombreuses façons - par exemple, rechercher tous les groupes sur n'importe quel sous-fichier, plusieurs volumes, etc.
la source
$TARGET_GID
serait d'utilisergrep ':$TARGET_GID:'
, sinon si le conteneur a, par exemple gid 10001 et que votre hôte est 1000, ce contrôle passera mais il ne devrait pas.Ok, cela est maintenant suivi dans le problème de docker # 7198
Pour l'instant, je traite cela en utilisant votre deuxième option:
Dockerfile
CLI
MISE À JOUR Je suis actuellement plus enclin à répondre à Hamy
la source
id -u <username>
,id -g <username>
,id -G <username>
pour obtenir la place de l'ID utilisateur et l' ID de groupe d'un utilisateur spécifiqueEssayez d'ajouter une commande à Dockerfile
les crédits vont à https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
la source
De la même manière que vous, je cherchais un moyen de mapper les utilisateurs / groupes de l'hôte aux conteneurs Docker et c'est le moyen le plus court que j'ai trouvé jusqu'à présent:
Ceci est un extrait de mon docker-compose.yml.
L'idée est de monter (en mode lecture seule) des listes d'utilisateurs / groupes de l'hôte vers le conteneur, donc après le démarrage du conteneur, il aura les mêmes correspondances uid-> nom d'utilisateur (ainsi que pour les groupes) avec l'hôte. Vous pouvez maintenant configurer les paramètres utilisateur / groupe pour votre service à l'intérieur du conteneur comme s'il fonctionnait sur votre système hôte.
Lorsque vous décidez de déplacer votre conteneur vers un autre hôte, il vous suffit de remplacer le nom d'utilisateur du fichier de configuration du service par ce que vous avez sur cet hôte.
la source
-u $( id -u $USER ):$( id -g $USER )
et vous n'avez plus à vous soucier du nom d'utilisateur. Cela fonctionne bien pour les environnements de développement locaux où vous souhaitez générer des fichiers (binaires par exemple) auxquels vous avez accès en lecture / écriture par défaut.Voici une approche qui utilise toujours un conteneur de données uniquement mais ne nécessite pas qu'il soit synchronisé avec le conteneur d'application (en termes d'avoir le même uid / gid).
Vraisemblablement, vous voulez exécuter une application dans le conteneur en tant que $ USER non root sans shell de connexion.
Dans le Dockerfile:
Ensuite, dans entrypoint.sh:
la source
Pour sécuriser et modifier la racine du conteneur Docker, un hôte Docker utilise les options
--uidmap
et les--private-uids
optionshttps://github.com/docker/docker/pull/4572#issuecomment-38400893
Vous pouvez également supprimer plusieurs fonctionnalités (
--cap-drop
) dans le conteneur Docker pour des raisons de sécuritéhttp://opensource.com/business/14/9/security-for-docker
Le support de MISE À JOUR devrait arriver
docker > 1.7.0
UPDATE version
1.10.0
(2016-02-04), ajoutez l'--userns-remap
indicateur https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2la source
--uidmap
ni les--private-uids
options. On dirait que le PR n'a pas réussi et n'a pas été fusionné."We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!"
github.com/docker/docker/pull/12648 Donc je pense que nous devrions attendre la prochaine version stable.Mon approche consiste à détecter l'UID / GID actuel, puis à créer un tel utilisateur / groupe à l'intérieur du conteneur et à exécuter le script sous lui. En conséquence, tous les fichiers qu'il créera correspondront à l'utilisateur sur l'hôte (qui est le script):
la source
Image de base
Utilisez cette image: https://hub.docker.com/r/reduardo7/docker-host-user
ou
Important: cela détruit la portabilité des conteneurs entre les hôtes .
1)
init.sh
2)
Dockerfile
3) run.sh
4) Construisez avec
docker
4) Courez!
la source
Dans mon cas spécifique, j'essayais de créer mon package de noeud avec l'image de docker de noeud afin de ne pas avoir à installer npm sur le serveur de déploiement. Cela a bien fonctionné jusqu'à ce que, en dehors du conteneur et sur la machine hôte, j'essaie de déplacer un fichier dans le répertoire node_modules que l'image docker du nœud avait créé, auquel je n'ai pas été autorisé car il appartenait à root. J'ai réalisé que je pouvais contourner ce problème en copiant le répertoire hors du conteneur sur la machine hôte. Via les documents Docker ...
Il s'agit du code bash que j'ai utilisé pour changer la propriété du répertoire créé par et dans le conteneur Docker.
Si nécessaire, vous pouvez supprimer le répertoire avec un deuxième conteneur Docker.
la source
Pour partager un dossier entre l'hôte Docker et le conteneur Docker, essayez la commande ci-dessous
L'indicateur -v monte le répertoire de travail actuel dans le conteneur. Lorsque le répertoire hôte d'un volume monté sur liaison n'existe pas, Docker crée automatiquement ce répertoire sur l'hôte pour vous,
Cependant, il y a 2 problèmes que nous avons ici:
Solution:
Conteneur: créez un utilisateur, dites 'testuser', par défaut, l'ID utilisateur commencera à partir de 1000,
Hôte: créez un groupe, dites 'testgroup' avec l'ID de groupe 1000, et chown le répertoire au nouveau groupe (testgroup
la source
Si vous utilisez Docker Compose, démarrez le conteneur en mode privilégié:
la source