I\'m using the declarative pipeline syntax to do some CI work inside a docker container.
I\'ve noticed that the Docker plugin for Jenkins runs a container using the
I verified that trying to assign user_id and group_id without a node didn't work, as you found, but this worked for me to assign these values and later access them:
def user_id
def group_id
node {
user_id = sh(returnStdout: true, script: 'id -u').trim()
group_id = sh(returnStdout: true, script: 'id -g').trim()
}
pipeline {
agent { label 'docker' }
stages {
stage('commit_stage') {
steps {
echo 'user_id'
echo user_id
echo 'group_id'
echo group_id
}
}
}
}
Hopefully these will also work in your additionalBuildArgs
statement.
In a comment, you pointed out what is most likely a critical flaw with the approach that figures out the user_id and group_id outside the declarative pipeline before using it to configure the dockerfile: the slave on which it discovers the user_id will not necessarily match up with the slave that it uses to kick off the docker-based build. i don't there is any way around this while also keeping the declarative Jenkinsfile constraint.
You can guarantee one slave for all stages by using a global agent declaration: Jenkins declarative pipeline: What workspace is associated with a stage when the agent is set only for the pipeline?
But multiple node references with the same label don't guarantee the same workspace: Jenkins declarative pipeline: What workspace is associated with a stage when the agent is set only for the pipeline?
You can also use the args parameter to solve the issue.
As described in Pipeline Syntax:
docker also optionally accepts an args parameter which may contain arguments to pass directly to a docker run invocation.
This is also possible when using dockerfile instead of docker in agent section.
I had the same problem like you and the following lines working fine for me:
agent {
dockerfile {
dir 'Docker/kubernetes-cli'
args '-u 0:0' //Forces Container tu run as User Root
reuseNode true
}
}
You can also add a block like this:
agent {
dockerfile {
args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
}
}
That will allow the container to have the correct user and group ID.
I believe we found a good way of dealing with this.
We have a Jenkins deployment which runs as a docker instance, I've mapped a volume for /var/jenkins_home and added the .ssh folder to /var/jenkins_home/.ssh
We also run all builds inside docker containers, using the dockerfile agent directive. Sometimes we need to access some of our private composer libraries via git over ssh.
We leverage docker image caching by installing project deps (composer) which means we only rebuild the build containers if our deps change. This means we need to inject an SSH key during docker build.
See these example files:
project/Jenkinsfile
def SSH_KEY
node {
SSH_KEY = sh(returnStdout: true, script: 'cat /var/jenkins_home/.ssh/id_rsa')
}
pipeline {
agent {
dockerfile {
filename 'Dockerfile'
additionalBuildArgs '--build-arg SSH_KEY="' + SSH_KEY + '"'
reuseNode true
}
}
stages {
stage('Fetch Deps') {
steps {
sh 'mv /home/user/app/vendor vendor'
}
}
stage('Run Unit Tests') {
steps {
sh './vendor/bin/phpunit'
}
}
}
}
project/Dockerfile
FROM mycompany/php7.2-common:1.0.2
# Provides the image for building mycompany/project on Jenkins.
WORKDIR /home/user/app
ARG SSH_KEY # should receive a raw SSH private key during build.
ADD composer.json .
RUN add-ssh-key "${SSH_KEY}" ~/.ssh/id_rsa && \
composer install && \
remove-ssh-keys
# Note: add-ssh-key and remove-ssh-keys are our shell scripts put in
# the base image to reduce boilerplate for common tasks.
if you have admin access to Jenkins you can add these two script approvals:
staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods execute java.lang.String
staticMethod org.codehaus.groovy.runtime.ProcessGroovyMethods getText java.lang.Process
in this URI: http://${jenkins_host:port}/jenkins/scriptApproval/
which will allow you to execute a shell command in the master in this way:
def user = 'id -u'.execute().text
node {
echo "Hello World ${user}"
}