2015-05-06 15 views
12

Ich habe einen Workflow wie folgt für die Veröffentlichung von Webapps auf meinem Dev-Server. Der Server verfügt über einen einzelnen Docker-Host und ich verwende docker-compose zum Verwalten von Containern.Jenkins in Docker mit Zugriff auf Host-Docker

  1. Push-Änderungen in meiner App zu einem privaten Gitlab (im Docker ausgeführt). Die App enthält eine Dockerfile und Docker-compose.yml
  2. Gitlab löst eine jenkins Build (jenkins wird auch in Docker läuft), die einige normale Build Sachen tut (zB Lauftest)
  3. Jenkins muss dann eine neue Docker bauen Image und stellen Sie es mithilfe von Docker-Compose bereit.

Das Problem ich habe in Schritt 3. Die Art und Weise habe ich es einrichten, hat der jenkins Container Zugriff auf den Host Docker, so dass in der Build-Skript jede docker Befehl ausgeführt wird, im Wesentlichen die gleichen wie es läuft auf der Gastgeber. Dies geschieht folgende DockerFile für jenkins mit:

FROM jenkins 
USER root 

# Give jenkins access to docker 
RUN groupadd -g 997 docker 
RUN gpasswd -a jenkins docker 

# Install docker-compose 
RUN curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 
RUN chmod +x /usr/local/bin/docker-compose 

USER jenkins 

und Abbilden der folgenden Volumina in die Behälter jenkins:

-v /var/run/docker.sock:/var/run/docker.sock 
-v /usr/bin/docker:/usr/bin/docker 

Eine typische Build-Skript in jenkins sieht ungefähr so ​​aus:

docker-compose build 
docker-compose up 

Dies funktioniert in Ordnung, aber es gibt zwei Probleme:

  • Es fühlt sich wirklich wie ein Hack an. Aber die einzigen anderen Optionen, die ich gefunden habe, ist, das Docker-Plugin für jenkins zu verwenden, in einer Registry zu veröffentlichen und dann eine Möglichkeit zu haben, den Host wissen zu lassen, dass er neu starten muss. Dies sind wesentlich mehr bewegliche Teile, und das Docker-Jenkins-Plugin erforderte, dass der Docker-Host sich auf einem offenen Port befindet, den ich nicht wirklich darstellen möchte.

  • Die jenkins DockerFile enthält groupadd -g 997 docker, die benötigt wird, um dem Benutzer jenkins Zugriff auf docker zu gewähren. Die GID (997) ist jedoch die GID auf dem Hostcomputer und daher nicht tragbar.

Ich bin nicht wirklich sicher, welche Lösung ich suche. Ich kann keine praktische Möglichkeit sehen, diesen Ansatz zu umgehen, aber es wäre schön, wenn es möglich wäre, docker-Befehle innerhalb des jenkins-Containers auszuführen, ohne die GID in der DockerFile fest codieren zu müssen. Hat jemand irgendwelche Vorschläge dazu?

+0

Ich stieß auf ein ähnliches Problem beim Erstellen eines Docker-Image zum Ausführen von Android Studio. Ich brauche die gleiche GID für die Gruppen kvm und Video, damit Android Studio Geräteemulatoren ausführen kann. Ich entwickelte einen Hack: 1. Erstellen Sie im Host ein kurzes Skript, das Umgebungsvariablen auf die erforderlichen GID-Werte setzt. 2. Geben Sie in der Dockerdatei das obige Skript ein, und verwenden Sie die Umgebungsvariablen, um addgroup durchzuführen und die GID für vorhandene Gruppen zu validieren. Das Problem besteht darin, dass das erstellte Docker-Image nicht auf andere Hosts portierbar ist, die möglicherweise unterschiedliche GIDs für die oben genannten Gruppen haben. –

Antwort

5

Ich stieß auf die gleichen Probleme. Ich gab Jenkins schließlich passwortlose sudo-Privilegien wegen des GID-Problems. Ich habe mehr darüber hier geschrieben: http://container-solutions.com/2015/03/running-docker-in-jenkins-in-docker/

Dies wirkt sich nicht wirklich auf die Sicherheit, da docker Berechtigungen effektiv entspricht Sudo Rechte.

+1

Nützlicher Artikel, ich nehme an, dass alle docker Befehle in jenkins "sudo docker" sein müssten? – aquavitae

+0

Genau. (sinnlose Zeichen, damit ich kommentieren kann). –

2

Bitte nehmen Sie sich einen Blick auf diese Docker Datei nur habe ich geschrieben: https://github.com/bdruemen/jenkins-docker-uid-from-volume/blob/master/gid-from-volume/Dockerfile

Hier wird das von einem eingehängten Volumen extrahiert GID (Host-Verzeichnis), mit

stat -c '%g' <VOLUME-PATH> 

Dann wird die GID der Gruppe von der Containerbenutzer wird mit

groupmod -g <GID> 

geändert. Dies muss als root durchgeführt werden, aber dann sind root Privilegien dr geopt mit

gosu <USERNAME> <COMMAND> 

Alles ist in der ENTRYPOINT getan, so der eigentliche GID ist unbekannt, bis Sie

docker run -d -v <HOST-DIRECTORY>:<VOLUME-PATH> ... 

Hinweis ausgeführt, dass nach der GID ändert, könnte es in den Behälter andere Dateien nicht mehr zugänglich für den Prozess, so dass Sie möglicherweise eine

vor dem Befehl gosu benötigen.

Sie können auch die UID ändern, siehe meine Antwort hier Changing the user's uid in a pre-build docker container (jenkins) und vielleicht möchten Sie beide ändern, um die Sicherheit zu erhöhen.

5

Meine vorherige Antwort war generischer und gab an, wie Sie die GID innerhalb des Containers zur Laufzeit ändern können. Nun, durch Zufall, jemand aus meinen engen Kollegen bat um eine jenkins-Instanz, die Docker Entwicklung tun kann, so dass ich diese erstellt:

FROM bdruemen/jenkins-uid-from-volume 
RUN apt-get -yqq update && apt-get -yqq install docker.io && usermod -g docker jenkins 
VOLUME /var/run/docker.sock 
ENTRYPOINT groupmod -g $(stat -c "%g" /var/run/docker.sock) docker && usermod -u $(stat -c "%u" /var/jenkins_home) jenkins && gosu jenkins /bin/tini -- /usr/local/bin/jenkins.sh 

(Die Mutter Dockerfile ist das gleiche, die ich in meiner Antwort beschrieben habe: Changing the user's uid in a pre-build docker container (jenkins))

Um es zu verwenden, mounten Sie beide, jenkins_home und docker.sock.

docker run -d /home/jenkins:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock <IMAGE> 

Der jenkins Prozess in dem Behälter die gleiche UID als Host-Verzeichnis montiert hat. Vorausgesetzt, der Docker-Socket ist für die Docker-Gruppe auf dem Host verfügbar, wird im Container, der auch als Docker bezeichnet wird, eine Gruppe mit derselben GID erstellt.