Pages

Wednesday, March 13, 2019

Jenkins - Running build Slaves in a Docker Container

We all know that every organisation contain many build machines when there are larger and heavier projects that build all the time. These build machine are nothing special but a physical machine with a communication created between this and Jenkins server. Whenever a build need to be done, the job from the jenkins server is triggered and jenkins server will run the job on a build machine identified by a label. These build machines that we create and connect to the Jenkins server are called slaves. Each of the slave will have a label to be identified by the jenkins server for running the job.

With the arrival of containers, there is no need for separate build physical machines. We can configure Jenkins to run our jobs in one of the container that gets created and job is run inside the container and destroyed once complete. In this article we will see how we can run a docker container as our slave and run job inside the slave.

In this article we will see how we can configure jenkins to trigger a docker container when ever we want to run a job. We will have jenkins running on a different machine and have docker slave containers created on different machine.

1. Configure Docker to enable the Remote API. The remote api allows us to execute the docker commands using the api. Add the below contents to the /etc/docker/daemon.json file
[root@ip-172-31-26-225 docker]# cat /etc/docker/daemon.json
{
   "log-level":"warn",
   "hosts": ["unix:///var/run/docker.sock","tcp://0.0.0.0:2375"]
}

Restart the docker daemon and docker server using
sudo systemctl daemon-reload
sudo systemctl restart docker.service

Confirm the Remote api by making a call as,
[root@ip-172-31-26-225 docker]# curl localhost:2375/version
{"Version":"1.13.1","ApiVersion":"1.26","MinAPIVersion":"1.12","GitCommit":"8633870/1.13.1","GoVersion":"go1.9.4","Os":"linux","Arch":"amd64","KernelVersion":"3.10.0-862.3.2.el7.x86_64","BuildTime":"2018-09-28T19:45:08.749348837+00:00","PkgVersion":"docker-1.13.1-75.git8633870.el7.centos.x86_64"}

Use the curl command and access “http://localhost:2375/version” and if we see the output its working fine.

For the article purpose, i have taken a Aws ec2 instance with the IP address “3.17.134.39”, installed docker and configured the docker api.

2. On the Jenkins side, install the docker plugin from the “Manage Jenkins -> Manage plugins”

3. Once we install the plugin, we will see an entry added to the “Manage Jenkins -> Configure System” called “cloud”

4. Configure the “docker Cloud Details” as below,


In the above configuration, the Docker Host URI is the important one. This is the same machine where i want to run my docker slave containers. In my case i have taken a Aws ec2 instance with the IP address “3.17.134.39”. The Docker Host URI is “tcp://3.17.134.39:2375”. This is the same host configuration that we did in the first step. Enable the “Enabled” check box. You can keep the other fields as they are.

One important thing is to make sure the remote api is working by clicking the “Test Connection” button. Once it returns the Version and Api Version values as shown in above image, it working fine.

5. Once the Docker cloud is configured, we need to configure the Docker template which is below the Docker cloud in the same page.

There are many configurations that we need to do in this template. The Label is the first thing that we need to configure. Give a name to the label field. This is the same name that we will use in a job to run the project. I have given the label as “slave” and when i configure the Jenkins job, i will set the label name in the job as “slave” so that that job will run in this docker container.

Name is any name that you can give. The Next and most important element is the Docker Image. There are certain conditions when running a slave container for jenkins. First we need to build a docker image by taking the “jenkins/ssh-slave” as base image.

Then we can install the necessary packages in it. This image will then need to be saved to the docker hub. Below is the Dockerfile for this article
FROM jenkins/ssh-slave

# Install selected extensions and other stuff
RUN apt-get update \
   && apt-get -y --no-install-recommends install \
   php7.0-cli \
   php-xdebug \
   composer \
   phpunit \
   && apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

I built the image and saved it with the name “docker.io/jagadesh1982/jenkins-slave-test:latest”. I then used the “docker push ” command to push to the docker hub.

Now once we define the image details in the “docker template” in jenkins, Jenkins will download the image to that machine and run the container using this image. One important thing is that we have a “Registry Authentication” button which will let us to configure our Docker hub credentials as Jenkins credentials. Jenkins will use these credentials to login to the docker hub and download the image to the machine. We need to configure these credentials with your docker hub details.

The Instance capacity is set to 5 and home location is set to “/home/jenkins”. The next important thing is the “connection method”. In this case i choose the “Connect on Ssh” which will give details below. In the Ssh Key, i have chosen the “Inject ssh key” type which will inject a dedicated ssh key into the container and sshd is configured accordingly. The user will be jenkins since we built the image from the Jenkins/ssh-slave, we have the jenkins user configured and also sshd configured. We can choose our own pull strategy.

Create a sample Freestyle Job -> set the label for the job by clicking the “restrict where the project can be run”. In this field enter the Label “slave” that we created for the docker cloud earlier.

Now if we run the job, we can see the image file is download and started in the ec2 instance as below,
[root@ip-172-31-26-225 docker]# docker images
REPOSITORY                                            TAG IMAGE ID CREATED SIZE
docker.io/jagadesh1982/jenkins-slave-test  latest 3fe46a04b63c 1 days ago   655 MB

[root@ip-172-31-26-225 docker]# docker ps
CONTAINER ID    IMAGE                 COMMAND CREATED STATUS            PORTS NAMES

51dbe4a21cbe        docker.io/jagadesh1982/jenkins-slave-test:latest   "setup-sshd /usr/s..." 4 seconds ago Up 3 seconds        0.0.0.0:32774->22/tcp angry_swartz

We can see the the image file is downloaded and and the container is started just 3 seconds before. More to come , Happy learning :-)

1 comment :

  1. Hi, I tried adding docker api in daemon.json file and restart the service. however it fails.

    - The start-up result is done.
    May 23 07:39:36 ip-10-0-1-226.ec2.internal systemd[1]: start request repeated too quickly for docker.service
    May 23 07:39:36 ip-10-0-1-226.ec2.internal systemd[1]: Failed to start Docker Application Container Engine.
    -- Subject: Unit docker.service has failed
    -- Defined-By: systemd
    -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
    --
    -- Unit docker.service has failed.
    --
    -- The result is failed.

    ReplyDelete