it-swarm.com.de

Docker in Docker kann kein Volume laden

Ich verwende einen Jenkins-Cluster, in dem sowohl Master als auch Slave als Docker-Container ausgeführt werden. 

Der Host ist der neueste boot2docker VM, der auf MacOS ausgeführt wird.

Damit Jenkins die Bereitstellung mit Docker durchführen kann, habe ich den docker.sock- und den Docker-Client vom Host an den Jenkins-Container wie folgt angehängt:

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

Beim Anhängen eines Volumes an Docker-Container, die im Jenkins-Container ausgeführt werden, treten Probleme auf. Wenn ich zum Beispiel einen anderen Container im Jenkins-Container ausführen muss, mache ich Folgendes: -

Sudo docker run -v $JENKINS_CONTAINER/deploy.json:/root/deploy.json $CONTAINER_REPO/$CONTAINER_IMAGE 

Oben wird der Container ausgeführt, aber die Datei "deploy.json" wird NICHT als Datei, sondern als "Verzeichnis" angehängt. Selbst wenn ich ein Verzeichnis als Volume einhänge, kann ich die Dateien im resultierenden Container nicht anzeigen. 

Ist dies ein Problem aufgrund von Dateiberechtigungen aufgrund von Docker im Fall Docker?

Alle Hinweise wären nützlich!

Vielen Dank!

32
ZephyrPLUSPLUS

Ein Docker-Container in einem Docker-Container verwendet den Docker-Daemon des übergeordneten Hosts. Daher werden alle Volumes, die im Fall "Docker-in-Docker" gemountet sind, weiterhin vom Host und nicht vom Container aus referenziert. 

Daher ist der tatsächliche Pfad aus dem Jenkins-Container im Host "nicht vorhanden". Aus diesem Grund wird ein neues Verzeichnis im Container "Docker-in-Docker" erstellt, der leer ist. Dasselbe gilt, wenn ein Verzeichnis in einem neuen Docker-Container in einem Container bereitgestellt wird. 

Eine sehr grundlegende und offensichtliche Sache, die ich vermisst habe, die jedoch schnell erkannt wurde, als ich die Frage eingab. 

51
ZephyrPLUSPLUS

Eine andere Möglichkeit besteht darin, benannte Volumes oder Daten-Volume-Container zu verwenden. Auf diese Weise muss der Container im Inneren nichts über den Host wissen, und sowohl der Jenkins-Container als auch der Build-Container verweisen auf das Datenvolumen auf dieselbe Weise. 

Ich habe versucht, etwas Ähnliches zu tun wie das, was Sie tun, außer mit einem Agenten, der den Jenkins-Master verwendet. Das Problem war das gleiche, dass ich den Jenkins-Arbeitsbereich nicht in den inneren Container einhängen konnte. Für mich funktionierte die Verwendung des Data-Volume-Container-Ansatzes, und die Arbeitsbereichsdateien waren sowohl für den Agent-Container als auch für den inneren Container sichtbar. Was mir an diesem Ansatz gefallen hat, ist, dass beide Container auf dieselbe Weise auf das Datenvolumen verweisen. Das Einhängen von Verzeichnissen mit einem inneren Container wäre schwierig, da der innere Container jetzt etwas über den Host wissen muss, auf dem der übergeordnete Container ausgeführt wird. 

Ich habe hier einen ausführlichen Blog-Post über meinen Ansatz:

http://damnhandy.com/2016/03/06/creating-containerized-build-environments-mit-the-jenkins-pipeline-plugin-und-docker-well-almost/

Sowie Code hier:

https://github.com/damnhandy/jenkins-pipeline-docker

In meinem speziellen Fall funktioniert nicht alles so, wie es mir für das Jenkins Pipeline-Plugin gefällt. Es befasst sich jedoch mit dem Problem, dass der innere Container auf das Arbeitsverzeichnis von Jenkins zugreifen kann. 

8

In Bezug auf Ihren Anwendungsfall in Bezug auf Jenkins können Sie den Pfad einfach fälschen, indem Sie auf dem Host einen Symlink erstellen:

ln -s $Host_JENKINS_DATA_DIRECTORY/jenkins_data /var/jenkins_home
8
mperrin

Dies funktioniert auch über docker-compose und/oder über benannte Datenträger. Sie müssen also keinen Datencontainer erstellen. Das leere Verzeichnis muss jedoch auf dem Host vorhanden sein.

Host-Setup

Erstellen Sie Host-seitige Verzeichnisse und legen Sie Berechtigungen fest, damit Docker-Container auf Sudo mkdir -p /var/jenkins_home/{workspace,builds,jobs} && Sudo chown -R 1000 /var/jenkins_home && Sudo chmod -R a+rwx /var/jenkins_home zugreifen können.

docker-compose.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/

Wenn Sie docker-compose up --build jenkins (Sie möchten dies in ein ausführbares Beispiel wie https://github.com/thbkrkr/jks integrieren, in dem die .groovy-Skripts Jenkins so konfigurieren, dass sie beim Start nützlich sind) und dann Ihre Jobs können in das Verzeichnis $ JENKINS_HOME/workspace geklont werden, und es sollten keine Fehler wegen fehlender Dateien/etc angezeigt werden, da die Host- und Containerpfade übereinstimmen und das Ausführen weiterer Container im Docker-in-Docker funktionieren sollte auch.

Dockerfile (für Jenkins mit Docker in 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
2
dragon788

Sie können dieses Problem umgehen, indem Sie ein Verzeichnis (in Ihrem Docker-Container, in dem Sie Ihren Docker-Socket angehängt haben) mit demselben Pfad für sein Ziel bereitstellen. Wenn Sie dann einen Container in diesem Container ausführen, können Sie alles innerhalb des Mount-Pfads mit docker -v in den neuen Container einhängen.

Nehmen Sie dieses Beispiel:

# 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

Der Ordner /some/dir ist jetzt auf Ihrem Host, dem Zwischencontainer sowie Ihrem Zielcontainer gemountet. Da der Pfad des Mount auf dem Host als Container "fast Docker-in-Docker" vorhanden ist, können Sie docker -v wie erwartet verwenden.

Es ähnelt dem Vorschlag, einen Symlink auf dem Host zu erstellen, aber ich fand dies (zumindest in meinem Fall) eine sauberere Lösung. Vergessen Sie nicht, das Verzeichnis auf dem Host anschließend zu bereinigen! ;)

0
Toon Lamberigts

Wenn Sie wie ich sind und sich nicht mit Jenkins Setup herumschlagen wollen oder zu faul, um all diese Mühen durchzugehen, finden Sie hier eine einfache Problemumgehung, um dieses Problem für mich zum Laufen zu bringen. 

Schritt 1 - Fügen Sie dem Umgebungsabschnitt der Pipeline folgende Variablen hinzu

environment {
    ABSOLUTE_WORKSPACE = "/home/ubuntu/volumes/jenkins-data/workspace" 
    JOB_WORKSPACE = "\${PWD##*/}"
}

Schritt 2 - Führen Sie Ihren Container mit dem folgenden Befehl der Jenkins-Pipeline wie folgt aus.

    steps {
        sh "docker run -v ${ABSOLUTE_WORKSPACE}/${JOB_WORKSPACE}/my/dir/to/mount:/targetPath imageName:tag"
    }

Beachten Sie die doppelten Anführungszeichen in der obigen Anweisung. Jenkins konvertiert die env-Variablen nicht, wenn die Anführungszeichen nicht richtig formatiert sind oder stattdessen einfache Anführungszeichen hinzugefügt werden.


Was bedeutet jede Variable?

  • ABSOLUTE_WORKSPACE ist der Pfad unseres Jenkins-Volumes, den wir beim Starten von Jenkins Docker Container installiert hatten. In meinem Fall war der Docker-Run-Befehl wie folgt. 

    Sudo docker run \ -p 80:8080 \ -v /home/ubuntu/volumes/jenkins-data:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ -d -t jenkinsci/blueocean

Also der variable ABSOLUTE_WORKSPACE =/home/ubuntu/volume/jenkins-data +/Arbeitsbereich

  • Der Befehl JOB_WORKSPACE gibt uns das aktuelle Arbeitsbereichsverzeichnis, in dem sich Ihr Code befindet. Dies ist auch das Hauptverzeichnis Ihrer Codebasis. Gerade folgte diese Antwort als Referenz.

Wie funktioniert das ?

Es ist sehr unkompliziert, wie in @ZephyrPLUSPLUS (Credits) mit Erwiderung erwähnt, dass der Quellpfad für unseren Docker-Container, der in der Jenkins-Pipeline ausgeführt wird, nicht der Pfad im aktuellen Container ist, sondern der Pfad des Hosts. Alles, was wir hier tun, ist den Pfad zu bauen, auf dem unsere Jenkins-Pipeline läuft. Und montiere es an unserem Container. Voila !!

Hier ist eine kleine Illustration, um zu klären ...  enter image description here

0
damitj07

Ich habe das gleiche Problem in Gitlab CI. Ich habe dieses Problem gelöst, indem ich docker cp Verwendet habe, um so etwas wie mount zu machen

script:
  - docker run --name ${CONTAINER_NAME} ${API_TEST_IMAGE_NAME}
after_script:
  - docker cp ${CONTAINER_NAME}:/code/newman ./
  - docker rm ${CONTAINER_NAME}
0
BohanZhang