I have multiple stages defined inside my Jenkinsfile (pipeline mode).
I would like to run one stage (the local build) inside one Docker container,
and some other stages (the cross-build) inside another Docker container.
However, I would also like the Docker containers to be specified by corresponding Dockerfiles instead of just by an image name, since I need some customisation in the respective containers.
The Jenkins documentation states that both these things are possible.
However, it also states that Dockerfile will always be used as the filename for the docker container specification.
How can I create two separate Dockerfiles and tell Jenkins to use one of them for one stage, and the other one for some other stage(s)?
From my understanding, the Jenkinsfile should look something like this:
pipeline {
agent None
stages {
stage('Local Build') {
agent { dockerfile true }
steps {
sh 'mvn --version'
}
}
stage('Cross-build') {
agent { dockerfile true } // <--- How do I specify *which*
// Dockerfile to use here?
steps {
sh 'node --version'
}
}
}
}
You can add the following details to the Dockerfile agent. So you can simply use filename and dir options.
agent {
// Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
additionalBuildArgs '--build-arg version=1.0.2'
args '-v /tmp:/tmp'
}
}
Suppose I have a dockerized pipeline with multiple steps. The docker container is defined in the beginning of Jenkinsfile:
pipeline {
agent {
docker {
image 'gradle:latest'
}
}
stages {
// multiple steps, all executed in 'gradle' container
}
post {
always {
sh 'git whatever-command' // will not work in 'gradle' container
}
}
}
I would like to execute some git commands in a post-build action. The problem is that gradle image does not have git executable.
script.sh: line 1: git: command not found
How can I execute it on Docker host still using gradle container for all other build steps? Of course I do not want to explicitly specify container for each step but that specific post-post action.
Ok, below is my working solution with grouping multiple stages (Build and Test) in a single dockerized stage (Dockerized gradle) and single workspace reused between docker host and docker container (see reuseNode docs):
pipeline {
agent {
// the code will be checked out on out of available docker hosts
label 'docker'
}
stages {
stage('Dockerized gradle') {
agent {
docker {
reuseNode true // < -- the most important part
image 'gradle:6.5.1-jdk11'
}
}
stages{
// Stages in this block will be executed inside of a gradle container
stage('Build') {
steps{
script {
sh "gradle build -x test"
}
}
}
stage('Test') {
steps{
script {
sh "gradle test"
}
}
}
}
}
stage('Cucumber Report') {
// this stage will be executed on docker host labeled 'docker'
steps {
cucumber 'build/cucumber.json'
}
}
}
post {
always {
sh 'git whatever-command' // this will also work outside of 'gradle' container and reuse original workspace
}
}
}
Is it possible to specify a Dockerfile as basis for a container job, instead of a reference to an already built container?
This is possible with Jenkins, and a much appreciated feature:
pipeline {
stages {
stage("My Stage") {
agent {
dockerfile {
filename 'Dockerfile'
}
}
steps {
//
}
}
}
}
I would suggest something like:
container:
dockerfile: Dockerfile
I have BookStore Spring Boot project that needs to be deployed through Jenkins. Docker installed in my local machine (macOS) and Jenkinsfile created as follows
pipeline
{
agent
{
docker
{
image 'maven:3-alpine'
//This exposes application through port 8081 to outside world
args '-u root -p 8081:8081 -v /var/run/docker.sock:/var/run/docker.sock '
}
}
stages
{
stage('Build')
{
steps
{
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test')
{
steps {
//sh 'mvn test'
sh 'echo "test"'
}
post {
always {
//junit 'target/surefire-reports/*.xml'
sh 'echo "test"'
}
}
}
stage('Deliver for development')
{
when {
branch 'development'
}
steps {
sh './jenkins/scripts/deliver-for-development.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
}
}
stage('Deploy for production')
{
when {
branch 'production'
}
steps {
sh './jenkins/scripts/deploy-for-production.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
}
}
stage('Deliver') {
when {
branch 'production'
}
steps {
sh 'bash ./jenkins/deliver.sh'
}
}
}
}
I created multi-branch pipeline in Jenkins and when I try to run it, I got following error
/Users/Shared/Jenkins/Home/workspace/BookStore_master-VPWQ32ZZPV7CVOXNI4XOB3VSGH56MTF3W34KXKZFJKOBMSGLRZQQ#tmp/durable-70dd5a81/script.sh: line 2: docker: command not found
script returned exit code 127
This looks strange to me as docker available in local machine, and also configured Global Tool Configuration section with appropriate details as shown below. I looked into several posts and none of the solutions worked so far.
I faced the same issue on the Mac and the following answer helped me.
docker: command not found ( mac mini ) only happens in jenkins shell step but work from command prompt.
The solution is to add the following line into the /usr/local/Cellar/jenkins-lts/2.176.3/homebrew.mxcl.jenkins-lts.plist file so that Jenkins able to find the docker command from the host machine.
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin/:/Users/Kh0a/Library/Group\ Containers/group.com.docker/Applications/Docker.app/Contents/Resources/bin</string>
</dict>
I had the same issue and was able to resolve it thanks to this thread https://stackoverflow.com/a/50029962/6943587.
You need to specify the docker label, aka which agent(s) have docker. There are two ways to do this, that I know of.
(Option 1 - preferred) Set docker label in Jenkinsfile
Set the agent as docker image with docker agent label.
// Jenkinsfile
pipeline {
// Assign to docker agent(s) label, could also be 'any'
agent {
label 'docker'
}
stages {
stage('Docker node test') {
agent {
docker {
// Set both label and image
label 'docker'
image 'node:7-alpine'
args '--name docker-node' // list any args
}
}
steps {
// Steps run in node:7-alpine docker container on docker agent
sh 'node --version'
}
}
stage('Docker maven test') {
agent {
docker {
// Set both label and image
label 'docker'
image 'maven:3-alpine'
}
}
steps {
// Steps run in maven:3-alpine docker container on docker agent
sh 'mvn --version'
}
}
}
}
(Option 2) Set docker label in configuration
Set the "docker label" in the Jenkins configuration under "Pipeline Model Definition", per the Jenkins docs here. This will only run the pipeline builds on agents with this label. Then you can create your pipeline like so...
// Jenkinsfile
pipeline {
// "Top-level" agent is assigned to docker agents via Jenkins pipeline configuration
agent none
stages {
stage('Docker node test') {
agent {
docker {
image 'node:7-alpine'
args '--name docker-node' // list any args
}
}
steps {
// Steps run in node:7-alpine docker container on docker agent
sh 'node --version'
}
}
stage('Docker maven test') {
agent {
docker {
image 'maven:3-alpine'
}
}
steps {
// Steps run in maven:3-alpine docker container on docker agent
sh 'mvn --version'
}
}
}
}
Hope this helps
Option 1 is preferred over option 2 because the Jenkinsfile configures
what machine(s) to run the docker agents on without relying on the
Jenkins pipeline configuration which could be deleted or edited in the
future.
Since you have chosen install automatically option in Global Tool Configuration section, Jenkins will not look for the docker in your system.
You can resolve this issue by unchecking the install automatically option for docker in Global Tool Configuration section
download docker installer,
install it and
give the path of installer to Jenkins.
Example screenshot is below.
Setup docker installer path in jenkins under Global Tool Configuration
I was able to solve this by retrieving Docker and Maven values from Global Tool Configuration section and adding them to environment PATH as shown below
Updated Jenkinsfile:
node {
stage('Initialize')
{
def dockerHome = tool 'MyDocker'
def mavenHome = tool 'MyMaven'
env.PATH = "${dockerHome}/bin:${mavenHome}/bin:${env.PATH}"
}
stage('Checkout')
{
checkout scm
}
stage('Build')
{
sh 'uname -a'
sh 'mvn -B -DskipTests clean package'
}
stage('Test')
{
//sh 'mvn test'
sh 'ifconfig'
}
stage('Deliver')
{
sh 'bash ./jenkins/deliver.sh'
}
}
There seems to be an issue with automated docker installer. I encountered the same issue on docker on centos 7.
I downloaded the docker cli executables from https://download.docker.com/linux/static/stable/x86_64/ and extracted them into jenkins docker volume on host (/var/lib/docker/volumes/jenkins_home/_data/docker). Then copied from /var/jenkins_home/docker to /usr/bin using shell on docker container.
After coping the executables, the build worked as expected.
In my case I had docker command issues because I was using jenkins-lts which is also a docker. After trying to debug for quite a while, I realized referencing docker command with in a docker might be an issue. I stopped the jenkins-lts service, downloaded jenkins.war file and ran the same pipeline script with docker command. It started working. My pipeline script has agent any, it still works in jenkins.war version of jenkins
If you are on windows
Follow from here:-
https://www.katacoda.com/courses/jenkins/build-docker-images
Just apply the line separator Unix and Mac Os : "\n" in your ".sh" files with your code editor. It worked for me.
add -v $(which docker):/usr/bin/docker while running container
We have a jenkins master and some slaves. All on their own servers.
Now we have installed Docker on the slaves. We try to create a very basic pipeline now which will perform one step in the container.
I saw configurations where the agent is a docker container.
But we want something like this:
pipeline {
agent any
triggers {
pollSCM pipelineParams.polling
}
options {
buildDiscarder(logRotator(numToKeepStr: '3'))
}
stages {
stage('Clone') {
steps {
//clone repo scm..
}
}
stage ('npm') {
steps {
script {
sh 'npm ...'
}
}
stage ('docker') {
steps {
//start docker container and mount project in it
}
}
...
How do we have to configure the docker step? Do we have to define a new agent insdie the stage step while we have agent any already above?