J'ai un serveur Jenkins qui s'exécute dans un conteneur Docker et j'ai accès à Docker sur le système hôte. Jusqu'à présent, il fonctionne bien. Maintenant, je souhaite configurer un pipeline pour tester un script dans un conteneur Docker.
Jenkinsfile:
pipeline {
agent { docker 'nginx:1.11' }
stages {
stage('build') {
steps {
sh 'nginx -t'
}
}
}
}
Message d'erreur:
> + docker pull nginx:1.11
>
> Warning: failed to get default registry endpoint from daemon (Got
> permission denied while trying to connect to the Docker daemon socket
> at unix:///var/run/docker.sock: Get
> http://%2Fvar%2Frun%2Fdocker.sock/v1.29/info: dial unix
> /var/run/docker.sock: connect: permission denied). Using system
> default: https://index.docker.io/v1/
>
> Got permission denied while trying to connect to the Docker daemon
> socket at unix:///var/run/docker.sock: Post
> http://%2Fvar%2Frun%2Fdocker.sock/v1.29/images/create?fromImage=nginx&tag=1.11:
> dial unix /var/run/docker.sock: connect: permission denied
>
> script returned exit code 1
Mon problème est que jenkins doit exécuter la commande docker avec Sudo, mais comment dire que l'agent exécute la commande avec sudo?
J'ai fait face au même problème. Après avoir analysé le journal de la console, j’ai constaté que la raison en est que le plug-in Docker Jenkins démarre un nouveau conteneur avec une option spécifique -u 107: 112 :
...
docker run -t -d -u 107:112 ...
...
Après avoir essayé de nombreuses options telles que: ajouter jenkins
au groupe Sudo (cela n’a pas fonctionné car jenkins
n’existe pas dans le conteneur), ajoutez USER root
dans Dockerfile
, ... mais aucun d’entre eux n’a fonctionné.
Enfin, j'ai trouvé une solution qui utilise args in docker agent pour écraser l’option -u . Ceci est mon Jenkinsfile :
pipeline {
agent {
docker {
image 'ubuntu'
args '-u root:Sudo -v $HOME/workspace/myproject:/myproject'
}
}
stages {
stage("setup_env") {
steps {
sh 'apt-get update -y'
sh 'apt-get install -y git build-essential gcc cmake make'
}
}
stage("install_dependencies") {
steps {
sh 'apt-get install -y libxml2-dev'
}
}
stage("compile_dpi") {
steps {
sh 'cd /myproject && make clean && make -j4'
}
}
stage("install_dpi") {
steps {
sh 'cd /myproject && make install'
}
}
stage("test") {
steps {
sh 'do some test here'
}
}
}
post {
success {
echo 'Do something when it is successful'
bitbucketStatusNotify(buildState: 'SUCCESSFUL')
}
failure {
echo 'Do something when it is failed'
bitbucketStatusNotify(buildState: 'FAILED')
}
}
}
Il y a peut-être un problème de sécurité ici mais ce n'est pas le problème dans mon cas.
Je résoudrais le problème différemment, en faisant correspondre l'identifiant du groupe Jenkins à l'intérieur du conteneur à celui du socket de menu fixe que vous avez monté dans un volume. Je le fais avec un point d’entrée qui fonctionne en tant que root, recherche le gid du socket, et si cela ne correspond pas à celui du gid dans le conteneur actuel, il effectue une groupmod
pour le corriger à l’intérieur du conteneur. Ensuite, je laisse les privilèges à l'utilisateur jenkins
pour lancer Jenkins. Ce point d’entrée est exécuté à chaque démarrage, mais de manière assez transparente pour l’application Jenkins lancée.
Toutes les étapes pour effectuer cela sont incluses dans ce repo github: https://github.com/Sudo-bmitch/jenkins-docker/
Je viens d'avoir exactement le même problème. Vous devez ajouter un utilisateur jenkins au groupe de docker:
DOCKER_SOCKET=/var/run/docker.sock
DOCKER_GROUP=docker
JENKINS_USER=jenkins
if [ -S ${DOCKER_SOCKET} ]; then
DOCKER_GID=$(stat -c '%g' ${DOCKER_SOCKET})
Sudo groupadd -for -g ${DOCKER_GID} ${DOCKER_GROUP}
Sudo usermod -aG ${DOCKER_GROUP} ${JENKINS_USER}
fi
# Start Jenkins service
Sudo service jenkins restart
Après avoir exécuté ce qui précède, les pipelines démarrent avec succès le menu fixe
Même problème ici où.
[...]
agent { docker 'whatever_I_try_doesnt_work'} # Sudo, jenkins user in dockerroot group etc
[...]
Ma solution consiste donc à l'ajouter à l'une des étapes de la phase de création du pipeline, comme suit:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'Sudo docker pull python:3.5.1'
}
}
}
}
J'aurais peut-être trouvé une bonne solution pour cela.
Je lance Jenkins en tant que conteneur et je l’utilise pour construire des conteneurs sur l’hôte de docker sur lequel il tourne. Pour ce faire, je passe /var/run/docker.sock
en tant que volume au conteneur.
Juste pour réitérer la clause de non-responsabilité, certaines personnes ont déjà déclaré: Donner accès au socket de docker revient essentiellement à donner un accès root à la machine - soyez prudent!
Je suppose que vous avez déjà installé Docker dans votre image Jenkins.
Ceci est basé sur le fait que le binaire du menu fixe ne se trouve pas dans le premier répertoire de $PATH
. Nous plaçons essentiellement un script Shell qui exécute Sudo docker
au lieu de la simple commande docker
(et transmet les paramètres).
Ajoutez un fichier comme celui-ci à votre référentiel Jenkins et appelez-le docker_Sudo_overwrite.sh
:
#! /bin/sh
# This basically is a workaround to add Sudo to the docker command, because aliases don't seem to work
# To be honest, this is a horrible workaround that depends on the order in $PATH
# This file needs to be place in /usr/local/bin with execute permissions
Sudo /usr/bin/docker $@
Puis prolongez votre Jenkins Dockerfile
comme ceci:
# Now we need to allow jenkins to run docker commands! (This is not elegant, but at least it's semi-portable...)
USER root
## allowing jenkins user to run docker without specifying a password
RUN echo "jenkins ALL=(ALL) NOPASSWD: /usr/bin/docker" >> /etc/sudoers
# Create our alias file that allows us to use docker as Sudo without writing Sudo
COPY docker_Sudo_overwrite.sh /usr/local/bin/docker
RUN chmod +x /usr/local/bin/docker
# switch back to the jenkins-user
USER jenkins
Cela permet à l'utilisateur du service jenkins d'exécuter le binaire du menu fixe en tant que root avec Sudo (sans fournir de mot de passe). Ensuite, nous copions notre script dans /usr/local/bin/docker
qui "superpose" le binaire actuel et l’exécute avec Sudo
. Si cela vous aide, vous pouvez regarder mon exemple sur Github .
Vous pouvez contourner ce problème en:
1- Dans votre Dockerfile
, ajoutez Jenkins au fichier sudoers:
RUN echo "jenkins ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
2- Ajoutez une étape supplémentaire dans votre Jenkinsfile
pour donner à Jenkins les autorisations nécessaires pour utiliser docker:
pipeline {
agent none
stages {
stage("Fix the permission issue") {
agent any
steps {
sh "Sudo chown root:jenkins /run/docker.sock"
}
}
stage('Step 1') {
agent {
docker {
image 'nezarfadle/tools'
reuseNode true
}
}
steps {
sh "ls /"
}
}
}
}
Ce qui a fonctionné pour moi était
node() {
String jenkinsUserId = sh(returnStdout: true, script: 'id -u jenkins').trim()
String dockerGroupId = sh(returnStdout: true, script: 'getent group docker | cut -d: -f3').trim()
String containerUserMapping = "-u $jenkinsUserId:$dockerGroupId "
docker.image('image')
.inside(containerUserMapping + ' -v /var/run/docker.sock:/var/run/docker.sock:ro') {
sh "..."
}
}
De cette façon, l'utilisateur du conteneur utilisait toujours l'ID utilisateur jenkins pour éviter les conflits d'autorisations avec les données partagées, mais il est également membre du groupe docker dans le conteneur requis pour accéder au socket docker (/var/run/docker.sock).
Je préfère cette solution car elle ne nécessite aucun script ni fichier de dock supplémentaire