Docker dans Docker ne peut pas monter le volume
J'exécute un cluster Jenkins où dans le maître et L'Esclave, les deux s'exécutent en tant que conteneurs Docker.
L'hôte est la dernière VM boot2docker fonctionnant sur MacOS.
Pour permettre à Jenkins d'effectuer un déploiement en utilisant Docker, j'ai monté le docker.sock et Docker client de l'hôte au conteneur Jenkins comme ceci: -
docker run -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):/usr/bin/docker -v $HOST_JENKINS_DATA_DIRECTORY/jenkins_data:/var/jenkins_home -v $HOST_SSH_KEYS_DIRECTORY/.ssh/:/var/jenkins_home/.ssh/ -p 8080:8080 jenkins
Je rencontre des problèmes lors du montage d'un volume sur des conteneurs Docker qui sont exécutés dans le conteneur Jenkins. Par exemple, si je besoin d'exécuter un autre conteneur à l'intérieur du conteneur Jenkins, je fais ce qui suit: -
sudo docker run -v $JENKINS_CONTAINER/deploy.json:/root/deploy.json $CONTAINER_REPO/$CONTAINER_IMAGE
Ce qui précède exécute le conteneur, mais le fichier " déployer.json " N'est pas monté en tant que Fichier, mais plutôt en tant que "répertoire". Même si je monte un répertoire en tant que Volume, Je ne peux pas afficher les fichiers dans le conteneur résultant.
Est-ce un problème, en raison des autorisations de fichier dues à Docker dans le cas Docker ?
Tous les pointeurs seraient utiles !
Merci!
5 réponses
Un conteneur Docker dans un conteneur Docker utilise le démon Docker de l'hôte parent et, par conséquent, tous les volumes montés dans le cas "docker-in-docker" sont toujours référencés à partir de l'hôte, et non du conteneur.
Par conséquent, le chemin réel monté à partir du conteneur Jenkins "n'existe pas" dans L'hôte. Pour cette raison, un nouveau répertoire est créé dans le "docker-en-docker" conteneur est vide. La même chose s'applique lorsqu'un répertoire est monté sur un nouveau conteneur Docker Conteneur.
Chose très basique et évidente que j'ai manquée, mais j'ai réalisé dès que j'ai tapé la question.
En ce qui concerne votre cas d'utilisation lié à Jenkins, vous pouvez simplement simuler le chemin en créant un lien symbolique sur L'hôte:
ln -s $HOST_JENKINS_DATA_DIRECTORY/jenkins_data /var/jenkins_home
Une autre façon de procéder consiste à utiliser des volumes nommés ou des conteneurs de volumes de données. De cette façon, le conteneur à l'intérieur n'a pas besoin de savoir quoi que ce soit sur l'hôte et le conteneur Jenkins et le conteneur de construction référencent le volume de données de la même manière.
J'ai essayé de faire quelque chose de similaire à ce que vous faites, sauf avec un agent plutôt qu'en utilisant le maître Jenkins. Le problème était le même en ce sens que je ne pouvais pas monter L'espace de travail Jenkins dans le conteneur interne. Quel travaillé pour moi utilisait l'approche conteneur de volume de données et les fichiers d'espace de travail étaient visibles à la fois le conteneur d'agent et le conteneur interne. Ce que j'ai aimé de l'approche, c'est que les deux conteneurs référencent le volume de données de la même manière. Le montage de répertoires avec un conteneur interne serait difficile car le conteneur interne doit maintenant savoir quelque chose sur l'hôte sur lequel son conteneur parent s'exécute.
J'ai un article de blog détaillé sur mon approche ici:
Ainsi Que le code ici:
Https://github.com/damnhandy/jenkins-pipeline-docker
Dans mon cas spécifique, tout ne fonctionne pas comme je le voudrais en termes de plugin Jenkins Pipeline. Mais il résout le problème du conteneur interne pouvant accéder au répertoire de L'espace de travail Jenkins.
Un moyen de contourner ce problème est de monter un répertoire (à l'intérieur de votre conteneur docker dans lequel vous avez monté votre socket docker) en utilisant exactement le même chemin pour sa destination. Ensuite, lorsque vous exécutez un conteneur à partir de ce conteneur, vous pouvez monter n'importe quoi dans le chemin de ce montage dans le nouveau conteneur en utilisant docker -v
.
Prenez cet exemple:
# Spin up your container from which you will use docker
docker run -v /some/dir:/some/dir -v /var/run/docker.sock:/var/run.docker.sock docker:latest
# Now spin up a container from within this container
docker run -v /some/dir:/usr/src/app $CONTAINER_IMAGE
Le dossier /some/dir
est maintenant monté sur votre hôte, le conteneur intermédiaire ainsi que votre conteneur de destination. Puisque le chemin du montage existe à la fois sur l'hôte en tant que conteneur "presque docker-in-docker", vous pouvez utiliser docker -v
comme prévu.
C'est un peu similaire à la suggestion de créer un lien symbolique sur l'hôte mais j'ai trouvé ceci (au moins dans mon cas), une solution plus propre. N'oubliez pas de nettoyer le répertoire de l'hôte par la suite! ;)
Cela fonctionne également via docker-compose
et/ou les volumes nommés de sorte que vous n'avez pas besoin de créer un conteneur de données uniquement, mais vous devez toujours avoir le répertoire vide sur l'hôte.
Configuration de L'hôte
Créez des répertoires côté hôte et définissez des autorisations pour permettre aux conteneurs Docker d'accéder
sudo mkdir -p /var/jenkins_home/{workspace,builds,jobs} && sudo chown -R 1000 /var/jenkins_home && sudo chmod -R a+rwx /var/jenkins_home
Docker-composer.yml
version: '3.1'
services:
jenkins:
build: .
image: jenkins
ports:
- 8080:8080
- 50000:50000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- workspace:/var/jenkins_home/workspace/
# Can also do builds/jobs/etc here and below
jenkins-lts:
build:
context: .
args:
versiontag: lts
image: jenkins:lts
ports:
- 8081:8080
- 50001:50000
volumes:
workspace:
driver: local
driver_opts:
type: none
o: bind
device: /var/jenkins_home/workspace/
Lorsque vous docker-compose up --build jenkins
(Vous pouvez l'incorporer dans un exemple prêt à fonctionner comme https://github.com/thbkrkr/jks où le.les scripts groovy pré-configurer Jenkins pour être utile au démarrage) et vous pourrez ensuite faire cloner vos travaux dans le répertoire $ JENKINS_HOME / workspace et ne pas avoir d'erreurs sur les fichiers manquants / etc car les chemins d'accès de l'hôte et du conteneur correspondront, puis exécuter d'autres conteneurs à partir du Docker-in-Docker devrait également fonctionner.
Dockerfile (pour Jenkins avec Docker dans Docker)
ARG versiontag=latest
FROM jenkins/jenkins:${versiontag}
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"
COPY jenkins_config/config.xml /usr/share/jenkins/ref/config.xml.override
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
USER root
RUN curl -L http://get.docker.io | bash && \
usermod -aG docker jenkins
# Since the above takes a while make any other root changes below this line
# eg `RUN apt update && apt install -y curl`
# drop back to the regular jenkins user - good practice
USER jenkins
EXPOSE 8080