DEV Community

Cover image for How to run docker from a Jenkins docker container that is already running without docker
Abdelhafid El Bekkaoui
Abdelhafid El Bekkaoui

Posted on

How to run docker from a Jenkins docker container that is already running without docker

Let's imagine the following scenario:

You needed to implement some CI/CD for your project and since you have some knowledge about docker and its advantages you thought "You know what, I'm going to run Jenkins as a docker container"! And you did and were able to create a pipeline with build steps and everything was going wonderfully.

Then you realised that maybe you want to build a docker image from within Jenkins, so you added a shell script to do so. But Oh-oh! Docker is not recognized and your build fails.

First Scenario : You have a Jenkins Docker container that can't run docker and you want to add docker to it.

Step 1 : Install Docker

In this scenario we will solve two issues. The first one is how to run docker inside the Jenkins container (Docker out of Docker). And the second one how to do so without losing your existing Jenkins configuration and pipelines.

Let's assume you are using RHEL or Centos, first you need to install docker, if you are using a different Linux distrubtion check the documentation from docker on what commands to run to install it, it is pretty easy to read and straightforward :

Image description

sudo -i
whoami # Should show "root"
Enter fullscreen mode Exit fullscreen mode
  • Run yum update
yum -y update
Enter fullscreen mode Exit fullscreen mode
  • Install docker
yum install -y yum-utils
Enter fullscreen mode Exit fullscreen mode

Note: Notice that this repo is a centos repo while we are using Rhel, the reason is because docker is not supported for some versions of RHEL but centos's docker works fine on all version of Rhel

yum-config-manager \ 
    --add-repo \ 
    https://download.docker.com/linux/centos/docker-ce.repo
Enter fullscreen mode Exit fullscreen mode
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Enter fullscreen mode Exit fullscreen mode
  • Check if docker is installed :
docker --version
Enter fullscreen mode Exit fullscreen mode

Step 2 : Run Jenkins container :

To pull the jenkins image and run it as a docker container use the following command

docker run --name jenkins -p 8080:8080 -p 50000:50000 -d --restart=on-failure -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk11
Enter fullscreen mode Exit fullscreen mode

Explanation :
--name jenkins : We are giving a name to this container so we can distinguish it easily. You can name it jenkins or whatever you want.
-p 8080:8080 -p 50000:50000 : We are mapping and exposing the ports here. Jenkins runs on port 8080 by default but we can map it to whatever port we want. So for example if you use -p 80:8080 you will be able to access Jenkins through port 80.
-d : To run the container in detached mode (Or in the background)
-v jenkins_home:/var/jenkins_home : Adding the jenkins_home volume.
jenkins/jenkins:lts-jdk11: The Jenkins image we want to run from dockerhub repository. Repository owner: jenkins. Repository name: Jenkins. Version or tag is : lts-jdk11.

docker logs jenkins
Enter fullscreen mode Exit fullscreen mode

Output:

Image description

Copy the password and head to : http://yourdomain.com:8080

Image description

Image description

Create credentials:

Image description

Create a simple Jenkins job

Now Jenkins is Setup correctly. Click on add new Item to add our first Jenkins job to test if docker works. It is supposed to fail. For the sake of simplicity we will start a FreeStyle project :

Image description

Image description

Image description

Put the following in the shell command which will allow us to verify if docker exists or not inside our Jenkins :

docker --version
docker ps -a
Enter fullscreen mode Exit fullscreen mode

Image description

Run the build/job

Image description

The build fails as expected

Image description

Let's see the logs of the build to verify that it was caused by missing docker :

Image description

Image description

Step 3 : Create a new Jenkins container from the existing container

This step is not necessary, but I will put it here in case you already customized your current Jenkins container and want to keep the customizations.

What we will actually do is create an image from the existing container and run a container from the image we created.

Basically we want to :

  • Get the image of the current Jenkins container we are running
  • Create a new image out of it (a copy)
  • Create a New Jenkins container from this new image.
docker commit jenkins my-jenkins-image
Enter fullscreen mode Exit fullscreen mode

Explanation of the command :

  • jenkins : this is the name of our jenkins container. You can see its name by running "docker ps" or "docker ps -a" if it's not running.
  • my-jenkins-image: The name of the output image. The image that we want to create from the existing container.

Result :

Image description

Congratulations. Now you have a "copy" of the old Jenkins image that you can use to create a new Jenkins container that keeps the customization.

Step 4 : How to keep the old configuration and files of the old Jenkins.

Before we create a new Jenkins container that will be able to run docker commands inside it we want it to have the configuration and the files of the old Jenkins container. If we don't do this we will have to reinstate Jenkins, enter the master password again, set credentials, define pipelines ... We don't want to do that even in a small project, but if it's an entreprise grade project well, we definitely don't want to do that.

In order to do that we will use volumes. What are docker volumes? Well the simplest explanation is that they allow you to connect and share the content of two directories. It's actually a bit more complex than that but this concept is sufficient for you to understand what they are and what are their usages.

As an example let's say you and your friend have 2 computers. Your compuer is named A, and their computer is named B. You both have a folder called MyFolder which is empty.

Now you want to connect the MyFolder on computer A to MyFolder on computer B. In a way that whatever files are in MyFolder in computer A will be in MyFolder in computer B.

Computer A
My Folder
- hello.txt

Computer B
My Folder
- hello.txt

Now if you create a new file in My Folder on Computer B called goodbye.txt, it will "magically" appear on computer A as well !

Computer A
My Folder
- hello.txt
- goodbye.txt
Computer B
My Folder
- hello.txt
- goodbye.txt

So the two folders are basically interlinked.
In our case what we want to do is mount the configuration files that are in the old (current) Jenkins container and mount them to the new Jenkins container we want to create.

Copy the Jenkins configuration files from the old Jenkins container to a local folder on your host machine:

docker cp jenkins:/var/jenkins_home /usr/jenkins-data
Enter fullscreen mode Exit fullscreen mode

Explanation:
jenkins:/var/jenkins_home : From container named "jenkins", copy the directory "/var/jenkins_home"

/usr/jenkins-data: Where we want to copy this directory into

Check if the data was copied :

ls /var/jenkins_home # Should not be empty
Enter fullscreen mode Exit fullscreen mode

Create the new Jenkins that can run docker

Congratulations. You created an image from the old jenkins container and you copied the Jenkins data, which you will use to create a new Jenkins container that is exactly the same as the old one with the added benefit of it being able to run docker.

Stop the current Jenkins container

docker stop jenkins
Enter fullscreen mode Exit fullscreen mode

Create new jenkins container that can run docker

docker run -u 0 --name jenkins-docker -p 8080:8080 -p 50000:50000 -d --restart=on-failure -v /var/run/docker.sock:/var/run/docker.sock -v /usr/jenkins-data:/var/jenkins_home -v $(which docker):/usr/bin/docker my-jenkins-image
Enter fullscreen mode Exit fullscreen mode

Check new container logs. It shouldn't show any password :

docker logs jenkins-docker
Enter fullscreen mode Exit fullscreen mode

Go to your http://yourdomain.com:8080

Image description

Notice that we are asked to log in and not to set up Jenkins even though we are running a new Jenkins container and not the old ones. This means that the configuration from the old Jenkins container is copied successfully.

We also have the old job that we created.

Image description

Now build the job

Image description

You see that the build is successful now
See the logs :

Image description

Important: Notice how when we run docker ps -a
we are getting a list of the containers of the docker that is installed on the Host machine! This is very important. Jenkins is now able to run not an installation of docker inside the jenkins container, but the installation of docker on the host itself.

Basically running "docker ps -a" from a Jenkins shell script is the exact same as running it from your server's SSH with a root account.

I hope this tutorial was helpful, it's my first time writing tutorials so there are some things to improve. Do not hesitate to leave any feedback.

Top comments (0)