How to use docker agent in Jenkinsfile pipeline? - docker

I have a Django project uploaded in GitHub and I need to link it with jenkins.
I installed Jenkins and Docker services on Ubuntu 20.04 machine.
I configured the Jenkins server with my repo and I installed all the suggestd plggins + docker pipeline plugin.
after that, I created a Jenkinsfile that uses docker agent to run the stages inside a python docker container but I'm getting "‘Jenkins’ doesn’t have label ‘docker’" in the console output. I tried to add the label docker in the project settings but still the same error appears!
This is my Jenkinsfile:
pipeline {
agent any
stages {
stage("install pip dependencies") {
agent {
docker {
label "docker"
image "python:3.7"
}
}
steps {
withEnv(["HOME=${env.WORKSPACE}"]) {
sh "pip install virtualenv"
sh "virtualenv venv"
sh "pip install -r requirements.txt "
}
}
}
}}
What am I missing?
Thank you!

That message means your only available node, which happens to be your Jenkins controller, does not have the label docker that you've required on your agent in this block:
agent {
docker {
label 'docker'
image 'python:3.7'
}
}
Adding the label docker to the controller, then restarting Jenkins (required for the label change to be recognized, though that surprised me. It might be a peculiarity of labeling the controller itself, since you should avoid scheduling jobs to run there if possible) resolves the issue.
Pre-label:
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (install pip dependencies)
[Pipeline] node
Still waiting to schedule task
‘Jenkins’ doesn’t have label ‘docker’
Aborted by admin
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: ABORTED
Post-label, pre-restart:
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (install pip dependencies)
[Pipeline] node
Still waiting to schedule task
‘Jenkins’ doesn’t have label ‘docker’
Aborted by admin
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: ABORTED
Post-restart, highlighting that my controller doesn't have docker installed
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (install pip dependencies)
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test#2
[Pipeline] {
[Pipeline] isUnix
[Pipeline] sh
+ docker inspect -f . python:3.7
/var/jenkins_home/workspace/test#2#tmp/durable-4a9f38a7/script.sh: 1: /var/jenkins_home/workspace/test#2#tmp/durable-4a9f38a7/script.sh: docker: not found
[Pipeline] isUnix
[Pipeline] sh
+ docker pull python:3.7
/var/jenkins_home/workspace/test#2#tmp/durable-58d19d02/script.sh: 1: /var/jenkins_home/workspace/test#2#tmp/durable-58d19d02/script.sh: docker: not found
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 127
Finished: FAILURE

Your pipeline will looks like the following one:
pipeline {
agent {
label 'docker'
}
stages {
stage('install pip dependencies') {
steps {
withEnv(["HOME=${env.WORKSPACE}"]) {
sh'''
pip install virtualenv
virtualenv venv
pip install -r requirements.txt
'''
}
}
}
}
}
But before you need to follow these steps to make jenkins run docker containers as slaves:
install docker on your host;
add jenkins to docker group: sudo usermod -aG docker jenkins
Modify ExecStart=/usr/bin/dockerd line in the file /lib/systemd/system/docker.service to the following ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -H fd:// -s overlay2 --containerd=/run/containerd/containerd.sock
run sudo systemctl daemon-reload and sudo systemctl restart docker
configure docker section in Jenkins: manage Jenkins -> manage nodes and clouds -> configure clouds -> add a new cloud -> docker type tcp://127.0.0.1:2375 (or 4243) or unix:///var/run/docker.sock in Docker URL field. Configure agent, set any label and use it in pipeline.
Probably you will need to turn off selinux.

Related

unable to run simple jenkins docker node build (home directories outside of /home are not currently supported)

I am using a very simple script mentioned below as per the official docs (https://www.jenkins.io/doc/book/pipeline/docker/):
pipeline {
agent {
docker { image 'node:14-alpine' }
}
stages {
stage('Test') {
steps {
sh 'node --version'
}
}
}
}
Simple as it is, it outputs follows:
22:58:45 [Pipeline] }
22:58:45 [Pipeline] // stage
22:58:45 [Pipeline] withEnv
22:58:45 [Pipeline] {
22:58:45 [Pipeline] isUnix
22:58:45 [Pipeline] sh
22:58:45 + docker inspect -f . node:14-alpine
22:58:46 Sorry, home directories outside of /home are not currently supported.
22:58:46 See https://forum.snapcraft.io/t/11209 for details.
22:58:46 [Pipeline] isUnix
22:58:46 [Pipeline] sh
22:58:46 + docker pull node:14-alpine
22:58:46 Sorry, home directories outside of /home are not currently supported.
22:58:46 See https://forum.snapcraft.io/t/11209 for details.
22:58:46 [Pipeline] }
22:58:46 [Pipeline] // withEnv
22:58:46 [Pipeline] }
22:58:46 [Pipeline] // node
22:58:46 [Pipeline] End of Pipeline
22:58:46 ERROR: script returned exit code 1
22:58:46 Finished: FAILURE
Not sure what I am doing wrong.
The hyperlink inside the message leads to a page that says:
Snapd does currently not support running snaps if the home directory of the user is outside of /home.
It says that for the docker command. I suspect you're trying to run the docker command as the jenkins user. The default home directory for the jenkins user is /var/lib/jenkins. The default home directory of the jenkins user is outside /home.
If that's the case, there are several alternatives available:
Create a user on that computer with a home directory in /home and run a Jenkins agent as that user
Install docker on that computer using apt instead of using snapd (following the Docker directions rather than the Ubuntu directions)
Create a user on another computer with a home directory in /home and install docker there with snapd, then configure an agent to use that computer
It's likely you are inheriting the HOME environment variable from Jenkins in some way. You can use env config to override that. If you want the HOME from the worker node executing the docker build you can mount env.HOME into /home/jenkins (or something like that) into the container.
Something like:
pipeline {
agent {
docker {
image 'node:14-alpine'
args '-v $HOME:/home/jenkins'
}
}
...
}

Jenkins pipeline build a dockerfile which contains a base image of my dockerhub repository

I am extremely new to Jenkins. I tried out few basic pipeline examples which worked.
My concrete use case is following:
I have a base image in my docker hub repository : my_dockerhub_rep/myImage:v1
Now I want to build another image based on this base image through a Jenkins pipeline.
So i wrote the following dockerfile :
FROM my_docker_hub_rep/myImage:v1
RUN /bin/bash -c 'echo entering in MC container'
To build this image from Jenkins, i wrote the following Jenkinsfile:
pipeline {
agent { dockerfile {
filename "/home/user/Desktop/Dockerfile"
registryUrl ""
registryCredentialsId 'dockerHub'
}}
stages {
stage('Build') {
steps {
echo 'hello !'
sh 'echo LM_LICENSE_FILE = $LM_LICENSE_FILE'
}
}
The jenkins server can successfully login to the docker repository at first but then as soon as it tries to fetch the base image it throws an error that pull access denied : repository doesnt exist or requires docker login.
What i dont understand is if it could login into the docker repo once then why not again ?
Here is the console output of jenkins :
Started by user unknown or anonymous
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/docker_test
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] withDockerRegistry
$ docker login -u mydockerID-p ******** https://index.docker.io/v1/
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /var/lib/jenkins/workspace/docker_test#tmp/a548cbfa-5d55-4a2c-87a7-4954052d7e5b/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Agent Setup)
[Pipeline] isUnix
[Pipeline] readFile
[Pipeline] sh
+ docker build -t b2f2e9020bdfdbcd1bc3d0a6f0f28b1c7abff41b -f /home/user/Desktop/Dockerfile .
Sending build context to Docker daemon 2.095kB
Step 1/8 : FROM my_docker_rep/myImage:v1
pull access denied for my_docker_rep/myImage, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withDockerRegistry
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 1
Finished: FAILURE
ps: i already added jenkins to the user group.
Your docker file should have a full image reference. <registry>/<repository>/<imagename>:<image_tag> if not, the docker demon will always try to pull image from the default docker registry. Change the FROM part of your DOCKERFILE to contain the full image path. It will work

Jenkins Pipeline push the Docker Image

I'm trying to push my docker image after building source code, when jenkins push images to docker Hub Registry i am getting below error.
Pipeline Script
stage('Build Docker Image') {
container('docker') {
echo 'docker'
sh "docker build -t ${image_name} ."
sh "docker tag ${image_name} ${image_name}:${image_tag}"
}
}
stage('Push Docker Image') {
container('docker') {
withCredentials([string(credentialsId: 'DOCKER_HUB_CREDENTIALS', variable: 'DOCKER_HUB_CREDENTIALS')]) {
sh "docker login -u user-name -p ${DOCKER_HUB_CREDENTIALS}"
}
sh "docker push ${image_name}:${image_tag}"
}
}
Jenkins Logs
[Pipeline] // container
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Push Docker Image)
[Pipeline] container
[Pipeline] {
[Pipeline] withCredentials
Masking supported pattern matches of $DOCKER_HUB_CREDENTIALS
[Pipeline] {
[Pipeline] sh
+ docker login -u user-name -p ****
Login Succeeded
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] sh
+ docker push devopsimage.azure/frontend:bug-fix-2cbb925d
The push refers to repository [devopsimage.azure/frontend]
Get https://devopsimage.azure/v2/: dial tcp: lookup devopsimage.azure.io: Temporary failure in name resolution
[Pipeline] }
[Pipeline] // container
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
ERROR: script returned exit code 1
Finished: FAILURE
Can you please any one help me on this ?
If you have dot(.) in your image name before the slash, docker treats it as the registry name. So docker push is trying to push to registry named devopsimage.azure. If you actually want to push to Docker Hub instead, remove the dot from the image name. If you want to push to registry named devopsimage.azure, then there is a DNS issue in resolving this registry from your build machine.

Docker Container Jenkins Pipeline Script: Permission denied while executing the script

I am running jenkins inside a docker container. I have created a simple pipleline to checkout,build and run docker image, but I am getting the following error.
Below is my pipleline script:
node {
def mvnHome = tool name: 'Maven Path', type: 'maven'
stage('Git CheckOut') {
git branch: '2019_DOCKER_SERVICES', credentialsId: 'git-creds', url: 'http://10.10.10.84:8111/scm/git/JEE_M_SERVICES'
}
stage('Maven Build') {
// Run the maven build
withEnv(["MVN_HOME=$mvnHome"]) {
if (isUnix()) {
sh '"$MVN_HOME/bin/mvn" -f Services/user-service/pom.xml clean install'
} else {
// bat(/"%MVN_HOME%\bin\mvn" -f Services\\user-service\\pom.xml clean install/)
}
}
}
stage('Docker Image Build') {
sh '"Services/user-service/" docker build -t user-service'
}
}
But I am getting the follow error in last stage, the first two stages ran successfully.
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Docker Image Build)
[Pipeline] sh
+ Services/user-service/ docker build -t user-service
/var/jenkins_home/jobs/docker-demo/workspace#tmp/durable-a5c035cf/script.sh: 1: /var/jenkins_home/jobs/docker-demo/workspace#tmp/durable-a5c035cf/script.sh: Services/user-service/: Permission denied
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
You have to set up new Jenkins slaves using Docker
It's weird to run Docker inside the Docker container
To access low-level operations you have to run your Docker container privileged

Bind Volumes to Docker container in a pipeline job

So, I have this pipeline job that builds completely inside a Docker container. The Docker image used is pulled from a local repository before build and has almost all the dependencies required to run my project.
The problem is I need an option to define volumes to bind mound from Host to container so that I can perform some analysis using a tool available on my Host system but not in the container.
Is there a way to do this from inside a Jenkinsfile (Pipeline script)?
I'm not fully clear if this is what you mean. But if it isn't. Let me know and I'll try to figure out.
What I understand of mounting from host to container is mounting the content of the Jenkins Workspace inside the container.
For example in this pipeline:
pipeline {
agent { node { label 'xxx' } }
options {
buildDiscarder(logRotator(numToKeepStr: '3', artifactNumToKeepStr: '1'))
}
stages {
stage('add file') {
steps {
sh 'touch myfile.txt'
sh 'ls'
}
}
stage('Deploy') {
agent {
docker {
image 'lvthillo/aws-cli'
args '-v $WORKSPACE:/project'
reuseNode true
}
}
steps {
sh 'ls'
sh 'aws --version'
}
}
}
post {
always {
cleanWs()
}
}
}
In the first stage I just add a file to the workspace. just in Jenkins. Nothing with Docker.
In the second stage I start a docker container which contains the aws CLI (this is not installed on our jenkins slaves). We will start the container and mount the workspace inside the /project folder of my container. Now I can execute AWS CLI command's and I have access to the text file. In a next stage (not in the pipeline) you can use the file again in a different container or jenkins slave itself.
Output:
[Pipeline] {
[Pipeline] stage
[Pipeline] { (add file)
[Pipeline] sh
[test] Running shell script
+ touch myfile.txt
[Pipeline] sh
[test] Running shell script
+ ls
myfile.txt
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] getContext
[Pipeline] sh
[test] Running shell script
+ docker inspect -f . lvthillo/aws-cli
.
[Pipeline] withDockerContainer
FJ Arch Slave 7 does not seem to be running inside a container
$ docker run -t -d -u 201:201 -v $WORKSPACE:/project -w ... lvthillo/aws-cli cat
$ docker top xx -eo pid,comm
[Pipeline] {
[Pipeline] sh
[test] Running shell script
+ ls
myfile.txt
[Pipeline] sh
[test] Running shell script
+ aws --version
aws-cli/1.14.57 Python/2.7.14 Linux/4.9.78-1-lts botocore/1.9.10
[Pipeline] }
$ docker stop --time=1 3652bf94e933cbc888def1eeaf89e1cf24554408f9e4421fabfd660012a53365
$ docker rm -f 3652bf94e933cbc888def1eeaf89e1cf24554408f9e4421fabfd660012a53365
[Pipeline] // withDockerContainer
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] cleanWs
[WS-CLEANUP] Deleting project workspace...[WS-CLEANUP] done
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
In your case you can mount your data in the container. Perform the stuff and in a later stage you can do your analysis on your code on your jenkins slave itself (without docker)
Suppose you are under Linux, run the following code
docker run -it --rm -v /local_dir:/image_root_dir/mount_dir image_name
Here is some detail:
-it: interactive terminal
--rm: remove container after exit the container
-v: volume or say mount your local directory to a volume.
Since the mount function will 'cover' the directory in your image, your should alway make a new directory under your images root directory.
Visit Use bind mounts to get more information.
ps:
run
sudo -s
and tpye the password before you run docker, that saves you a lot of time, since you don't have to type sudo in front of docker every time you run docker.
ps2:
suppose you have an image with a long name and the image ID is 5ed6274db6ce, you can simply run at least the first three digits, or more
docker run [options] 5ed
if you have more image have the same first three digits, you can use four or more.
For example, you have following two images
REPOSITORY IMAGE ID
My_Image_with_very_long_name 5ed6274db6ce
My_Image_with_very_long_name2 5edc819f315e
you can simply run
docker run [options] 5ed6
to run the image My_Image_with_very_long_name.

Resources