Saturday, July 14, 2018

How to use Jenkins docker image to run Jenkins master

How to use Jenkins docker image as a master and as a build node.
In the recent past, the Containerization is becoming very popular. Docker is a very prominent player in the filed of containerization.
Today I am going to show step by step procedure on how to use docker image for both Jenkins master and node. Also, I am going to address a few known issues which and how to find a workaround for them. In the tutorial, I will use the Jenkins version jenkins/jenkins:2.107.3.
Pull the image from docker hub
$ docker pull jenkins/Jenkins:2.107.3
Note that the docker-ized Jenkins will use /var/jenkins_home as Jenkins home. If you want to change this you have to edit the docker file provided by the docker hub, which was used to build the image jenkins/jenkins:2.107.3. I will not cover that in the tutorial.
The additional steps we are doing on top of the base image Jenkins/jenkins:2.107.3
1.     Customize the Jenkins docker image with additional packages and new users
2.     Use different user other than the default jenkins user.
3.     Use different home directory for a different user but use the same jenkins_home folder
4.     Use a host-volume to map to Jenkins_home inside the container
5.     Use the host machine ssh keys on the container as also
Let us see one by one and what are the issues we have.
In most of the cases you will not want to use the default user called jenkins, you need to use the user which is specific to your organization or company. I will call the new user as user_jenkins, this user is already present in my host machine and it needs to be created in the new image.
Below docker file will add the new user, declares 2 arguments for ssh private and public key, copy the plugins.txt file and install them, finally copies the necessary ssh keys from host to the container.  

from jenkins/jenkins:2.107.3
ARG priv
ARG pub
USER root

COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt

# Add user user_jenkins using static UID/GID from AD, home /var/lib/jenkins, adequate shell
RUN groupadd -g 215 group_jenkins && \
    useradd -u 1396 -g group_jenkins -d /var/jenkins_home_tmp -s /bin/bash -m user_jenkins

USER user_jenkins

# insert ssh keys
RUN mkdir -p ~/.ssh && \
    echo "$priv" > ~/.ssh/id_rsa && \
    echo "$pub" > ~/.ssh/id_rsa.pub && \
    chmod 644 ~/.ssh/id_rsa.pub && chmod 600 ~/.ssh/id_rsa && chmod 700 ~/.ssh 

Now try to build the docker image using docker build command. We need to keep the plugins.txt in the build context and ssh keys to be passed as a build parameter. 

The format of the plugins.txt file should as below 

mask-passwords:2.8
workflow-step-api:2.2
external-monitor-job:1.4
accelerated-build-now-plugin:1.0.1
pam-auth:1.1
ssh-credentials:1.10
plot:1.11
configurationslicing:1.47
active-directory:2.2
git-parameter:0.6.1
disk-usage:0.28
structs:1.2
envinject:1.92.1
release:2.5.4
custom-tools-plugin:0.4.4
coverity:1.7.1
elastic-axis:1.2
run-condition:1.0
slave-status:1.6
groovy-label-assignment:1.2.0
matrix-project:1.4.1
scm-api:1.2
warnings:4.56
docker-plugin:0.16.2
ssh-agent:1.13
maven-plugin:2.7.1
periodic-reincarnation:1.10
icon-shim:2.0.3
docker-slaves:1.0.6
mapdb-api:1.0.9.0
throttle-concurrents:1.9.0
analysis-core:1.79
jquery:1.11.2-0
slave-setup:1.10
subversion:1.54
postbuild-task:1.8
artifactdeployer:0.33
timestamper:1.8.8
gerrit-trigger:2.21.1
bouncycastle-api:1.648.3
translation:1.10
monitoring:1.59.0
credentials:2.1.13
javadoc:1.1
build-name-setter:1.6.5
antisamy-markup-formatter:1.1
PrioritySorter:3.4
extended-choice-parameter:0.74
workflow-scm-step:2.2
cvs:2.11
authentication-tokens:1.3
ldap:1.11
unreliable-slave-plugin:1.2
description-setter:1.10
parameterized-trigger:2.31
project-stats-plugin:0.4
token-macro:1.12.1
ant:1.2
script-security:1.29
leastload:1.0.3
junit:1.2-beta-4
ssh-slaves:1.9
repo:1.10.2
email-ext:2.44
purge-build-queue-plugin:1.0
git:2.5.2
matrix-auth:1.1
keepSlaveOffline:1.0
preSCMbuildstep:0.3
mailer:1.11
docker-commons:1.6
conditional-buildstep:1.3.5
jobConfigHistory:2.16
dashboard-view:2.9.10
durable-task:1.13
git-client:1.19.7

build-failure-analyzer:1.16.0

Passing ssh keys to the image during the build time is necessary for various reasons. One such reason is to clone from git or Github, which requires ssh keys to connect to the servers. Copying ssh keys is also tricky because we are copying both private and public keys. Earlier I used to keep the ssh keys in a plain text inside the docker file. But that is very dangerous. Now I am trying to pass them as a build parameter. The only concern with the approach is that the keys are available in the docker layer. There is an experimental option available in the docker engine to squash the layers so the layers are which are exposing the security information can be merged into other layers. This can be achieved using –squash option in the docker build command.
The docker build command
$ docker build --build-arg priv="$(cat ~/.ssh/id_rsa)" --build-arg pub="$(cat ~/.ssh/id_rsa.pub)" -t jenkins_2 --no-cache  -f docker .
The key thing to be noted here is the --build-arg parameters. I am reading the existing ssh keys from the host machine and passing them as a parameter. Note that here 2 separate –-build-arg parameters one each for private key and public key. The parameters are handled by ARG instruction in the docker file
Once the image is built successfully we can start the container.
Run command
$ docker run -d  -p 8082:8080  -p 5002:5000  jenkins_2
I am using the different ports. You will get the error message as shown below or similar.  

17:46:34 root dev ~ → docker logs 4s6yuknv568
touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
Note that the ‘/var/jenkins_home/’ is the default home directory from where the Jenkins runs. If you are using a user other than default user jenkins, you will get permission denied error.
To overcome this error there should be a proper folder created before running the container. The new folder created will be mapped as host volume as in the below command.  
$ su user_jenkins
$ mkdir -p /opt/my_jenkins_home
$ docker run -d  -p 8082:8080  -p 5002:5000 -v /opt/my_jenkins_home:/var/jenkins_home  jenkins_2

No comments:

Post a Comment

Cleaning up private docker registry

The solution to cleaning the unused docker registry layers is not straightforward, there is nothing readily available from docker. As more ...