Jenkins in Docker: Running Docker in a Jenkins container
Tags: jenkins, devops, docker, cloudnative
Published: 2022-04-05 14:54:45

This article was originally posted on [Hackmamba](https://hackmamba.io/blog/2022/04/running-docker-in-a-jenkins-container/)

Jenkins is a popular continuous integration and delivery (CI/CD) tool. Jenkins is open source and has a great developer community that maintains its existing software and builds plugins to increase its functionality. 

Though with excellent community support, while using Jenkins, you may suffer from issues like configuration files clashes which you can resolve by running Jenkins in a container technology like Docker. However, running Jenkins in Docker brings a new challenge if you plan to dockerize applications with Jenkins. 

This article will guide you on setting up Jenkins in Docker and enabling the Jenkins container to allow running of Docker (specifically: build, run, and push images).  At the end, you will test the setup by automating the building and pushing of the Docker image - a NodeJS app on GitHub, to Docker Hub.


## GitHub Repository

To view the source code and `Dockerfile` of the NodeJS application on GitHub, click [here](https://github.com/Kikiodazie/Backend-RESTful-API).

## Prerequisites

To follow along with this article, you must have:

- Working knowledge of Docker and the terminal.
- A Docker Hub account — create a free one [here](https://hub.docker.com/).

Knowing Jenkins isn’t a strict requirement, but it’ll be nice to have.


## Setting up Jenkins in Docker to run Docker

To set up Jenkins in Docker to be able to run Docker (specifically: build, run, and push an image), there are at least two options:


- Docker-in-Docker, and
- Create a custom Jenkins Docker image and bind-mount the container to the host system daemon

Though you will be using the latter option in this article, first, you will learn about Docker-in-Docker. 

**Docker-in-Docker** 
The primary purpose of Docker-in-Docker is to help the Docker core team work faster on Docker development.  And at that time (2013-2015), the only way to run Docker-in-Docker, was to use the `*-privileged*` **flag in the run command.

Though it works, using the `-privileged` flag introduces other issues, such as data corruption when multiple containers share `/var/lib/docker`. Only the Docker daemon should have access to `/var/lib/docker` by design.

Today, things are very different. Docker-in-Docker has a more secure and safe approach with [rootless containers](https://rootlesscontaine.rs/) and freemium tools like [sysbox](https://github.com/nestybox/sysbox). Tools like *sysbox* let you run Docker-in-Docker without the *-privileged* flag and optimizes specific scenarios, like running multiple nodes of a Kubernetes cluster as ordinary containers.


## Creating a custom Jenkins image

To start, in any directory, create a `Dockerfile` and add:

```dockerfile
FROM jenkins/jenkins:lts
USER root
RUN apt-get update -qq \
    && apt-get install -qqy apt-transport-https ca-certificates curl gnupg2 software-properties-common
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
RUN add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"
RUN apt-get update  -qq \
   && apt-get -y install docker-ce
RUN usermod -aG docker jenkins
```
The `Dockerfile` contains all the commands to create the custom Jenkins image.

- The `FROM` command tells Docker the base image (`jenkins/jenkins:lts`) from which to build the custom image.
- The first `RUN` command updates all essential packages using `apt-get update`. Then installs the new ones needed for the custom Jenkins image using `apt-get install`.
- The following `RUN` command downloads the Docker Linux Debian distribution CLI. Then the next one adds it to the repository. 
- And the last `RUN` command adds Jenkins user to the Docker group.

To build the custom Jenkins image, run:

```bash
$ docker image build -t custom-jenkins-docker .
```
You can run the image now to configure Jenkins, but if you do that, you will not be able to:

- Store Jenkins configurations and data when the container is stopped, restarted or deleted,
- Dockerize an application (goal of the article) with the Jenkins container because of the absence of Docker daemon (required to build and push images) in the custom Jenkins image YOU.

**Store Jenkins data**
To store Jenkins, you need to create an explicit volume for Jenkins on your host machine. To do that, add this argument `-v jenkins_home:/var/jenkins_home` when running the custom Jenkins image.

**Enabling use of Docker daemon in the Jenkins container**
To do this, connect the Docker CLI in the Jenkins container to the Docker daemon on the host machine by bind mounting the daemon’s socket into the container with the `-v` flag. When running the image add this argument: `/var/run/docker.sock:/var/run/docker.sock`. 

Now, putting all the arguments together, you can run the custom Jenkins image with the following command:

```bash
$ docker run -it -p 8080:8080 -p 50000:50000 -v /var/run/docker.sock:/var/run/docker.sock -v jenkins_home:/var/jenkins_home custom-jenkins-docker
```
 
After you've run the command above, visit localhost `localhost:8080` to configure your Jenkins environment.


## Configuring your Jenkins environment

When you go to `localhost:8080`, you should see a web page similar to the image below:


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645484899181_jenkins-getting-started.png)


You can quickly get the `admin` password from the log returned. 

See what it looks like below:


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645553155314_Screenshot+from+2022-02-22+19-05-37.png)


In the following prompt, select **Install suggested plugins.** Jenkins will automatically install all plugins the Jenkins community finds most useful.

![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645661908679_plugins-installation.png)


After the installation, create a first admin user and finish the configuration.


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645717974971_Screenshot+from+2022-02-24+16-52-36.png)


So far, you’ve created a custom Jenkins image and set it up to be able to run Docker. Next, you will test the entire setup by automating Jenkins to build (Docker image) of the GitHub repo and publish it on Docker Hub. 


## Dockerizing a NodeJS application with Jenkins in Docker 

Before you can Dockerize a NodeJS application in your Jenkins environment, you will need to install the following plugins:


- **NodeJS Plugin**: To execute NodeJS scripts as a build step
- **CloudBees Docker Build and Publish plugin**: To enable the building of `Dockerfile` based projects and publish the built images to Docker Hub.

To install the above plugins, on the Jenkins dashboard, go to **Manage Jenkins**, under **System Configurations**, select **Manage Plugins.** After that, click on the **Available** tab on the plugins manager and search for the respective plugins and install them.


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645718891759_Screenshot+from+2022-02-24+17-07-55.png)


**NodeJs Plugin**
In **Manage Jenkins,** still under **System Configurations**, select **Global Tool Configuration**, then add a NodeJS installation similar to the image below:


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645570133589_Screenshot+from+2022-02-22+23-43-28.png)


******Creating a build job to dockerize the application**
To start, on the Jenkins dashboard, click on **New Item**, select **Freestyle project** and name it. Then click **OK**:


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645602069526_Screenshot+from+2022-02-23+08-40-27.png)


On the following webpage, click on the **Source Code Management** tab, select **Git**, and add the URL of the GitHub repository: https://github.com/Kikiodazie/Backend-RESTful-API.git.


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645604367689_Screenshot+from+2022-02-23+09-15-47.png)


Leave the **Credentials** field blank as the repository is public.

Then click on the **Build** tab to add the build step for building and publishing the NodeJS application image using the **CloudBees Docker Build and Publish plugin.**


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645606022505_Screenshot+from+2022-02-23+09-46-45.png)


After selecting the **Docker Build and Publish** build step, fill in the Repository name with `your_Dockerhub_id/desired_name_of_the_repo` example `kikiodazie/node-docker`. 

Leave the remaining fields blank because even if you add your Docker Hub **Registry credentials**, Jenkins in Docker will not validate it. 


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645610156349_Screenshot+from+2022-02-23+10-54-13.png)


To solve the empty **Registry credentials**, you will need to give Jenkins access by login into your Docker Hub account inside the Jenkins container through the command line. 

To get the `bash` of the container run:

```bash
$ docker exec -it <container_name/container_id> /bin/bash
```
Then inside the container, run:

```bash
$ docker login
```
To complete this process, input your Docker Hub credentials:


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645609751364_Screenshot+from+2022-02-23+00-14-27.png)


Go back to Jenkins, click on **Build Now**, and the NodeJS application image will be built and published to your Docker Hub account. 

You can view the console output in the **Build History**:


![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645611042388_Screenshot+from+2022-02-23+11-10-24.png)


The output should look similar to the one in the image below:

![](https://paper-attachments.dropbox.com/s_33CE5684927EB1F665F2EEF2A8A615DFA881F46F04918B588BABDF4D08ACF025_1645611213322_Screenshot+from+2022-02-23+11-13-15.png)


The above image shows that Jenkins in Docker successfully builds the image and publishes it to Docker Hub.


## Conclusion

This article guided you on setting up Jenkins in Docker to run Docker and test it by building and publishing the Docker image of a remote GitHub repository to Docker Hub. 


## Resources

To learn more about Jenkins in Docker, check out the following resources:

- [Installing Jenkins in Docker](https://www.jenkins.io/doc/book/installing/docker/) - on the Jenkins Documentation
- [Using Docker-in-Docker for your CI or testing environment? Think twice](https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/)
- [Easy Jenkins with a System Container](https://blog.nestybox.com/2019/09/29/jenkins.html)