This work is based on the Official Jenkins Docker Image [1].
Docker doesn't recommend running the Docker daemon inside a container (except for very few use cases like developing Docker itself), and the solutions to make this happen are generally hacky and/or unreliable.
Fear not though, there is an easy workaround: mount the host machine's Docker socket in the container. This will allow your container to use the host machine's Docker daemon to run containers and build images.
Your container still needs compatible Docker client binaries in it, but I have found this to be acceptable for all my use cases. [2]
In the Dockerfile, set the value of ARG docker_version=
to correspond to the same version of docker-ce
that is running on the host. The default value is 17.12.0~ce-0~debian
.
The version of docker-ce
on the host can be found by issuing a docker version
call.
-
Example:
$ docker version Client: Version: 17.12.0-ce API version: 1.35 Go version: go1.9.2 Git commit: c97c6d6 Built: Wed Dec 27 20:03:51 2017 OS/Arch: darwin/amd64 Server: Engine: Version: 17.12.0-ce API version: 1.35 (minimum version 1.12) Go version: go1.9.2 Git commit: c97c6d6 Built: Wed Dec 27 20:12:29 2017 OS/Arch: linux/amd64 Experimental: true
In this example the version was found to be
17.12.0-ce
, so the value ofdocker_version
in the Dockerfile should be set to17.12.0~ce-0~debian
prior to building the image. -
Debian based versions of
docker-ce
available as of 2018-04-17:# apt-cache madison docker-ce | tr -s ' ' | cut -d '|' -f 2 18.03.0~ce-0~debian 17.12.1~ce-0~debian 17.12.0~ce-0~debian 17.09.1~ce-0~debian 17.09.0~ce-0~debian 17.06.2~ce-0~debian 17.06.1~ce-0~debian 17.06.0~ce-0~debian 17.03.2~ce-0~debian-stretch 17.03.1~ce-0~debian-stretch 17.03.0~ce-0~debian-stretch
Versions are subject to change as time goes on and keeping this reference up to date is outside of the scope of this document.
Once the value of ARG docker_version=
has been set, the jenkins container can be built using docker-compose
[3].
docker-compose build
The resulting image should look something like:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jenkins.nginx.docker lts 3b61f3afc888 2 minutes ago 1.26GB
This build makes use of docker-compse which is released as a separate distribution from Docker.
An option has been added to allow the user to modify the UID and GID of the jenkins
user that runs within the container. This can be useful to allow the mounting of volumes to the container and maintain UID/GID combinations that are native to the host.
-
Example from
docker-compose.yml
:environment: - UID_JENKINS=1000 - GID_JENKINS=1000
The official Jenkins Docker image creates a user named jenkins
with UID/GID
= 1000/1000
. This is not always an ideal UID/GID pairing when wanting to use mounted volumes, so the notion of changing the UID/GID of the jenkins user has been introduced.
In order to facilitate this the root
user must issue some commands at start up, and thus a new docker-entrypoint.sh
script has been introduced. This new script then calls the original jenkins.sh
script as the jenkins
user on it's way out.
The new docker-entrypoint.sh
script is prefixed to use Tini [4] as was the case for the jenkins.sh
script from the original image.
The user may also define mount volumes for both the Nginx and Jenkins containers.
Default settings for nginx
:
volumes:
- ./nginx:/etc/nginx/conf.d
- ./logs/nginx:/var/log/nginx
Default settings for jenkins
:
volumes:
- ./jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
The nginx/default.conf
file is used to determine the behavior of the Nginx reverse proxy web server [5], and should be modified to fit the use case. Template files for both http and https have been included as examples.
Update FQDN_OR_IP
to be the fully qualified domain name or IP address of the host.
Use docker-compose to run the containers. Generally this is done using the -d
flag to daemonize the processes.
docker-compose up -d
A successful run will yield two new containers, nginx
and jenkins
.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3266e71ecb05 nginx:latest "nginx -g 'daemon of…" About an hour ago Up About an hour 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx
0970db06246b jenkins.nginx.docker:lts "/sbin/tini -- /dock…" About an hour ago Up About an hour 0.0.0.0:50000->50000/tcp, 8080/tcp, 0.0.0.0:50022->50022/tcp, 0.0.0.0:2022->22/tcp jenkins
Using the configuration provided in the repository you should now have a running instance of Jenkins at http://localhost/jenkins
First run:
To retrieve the initialAdminPassword
:
$ docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
455341501512421c82f46f7d7bed27d0
And paste the result into the Administrator password box. From here continue to customize Jenkins to your particular requirements.
$ docker exec -u jenkins jenkins sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3266e71ecb05 nginx:latest "nginx -g 'daemon of…" About an hour ago Up About an hour 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx
0970db06246b jenkins.nginx.docker:lts "/sbin/tini -- /dock…" About an hour ago Up About an hour 0.0.0.0:50000->50000/tcp, 8080/tcp, 0.0.0.0:50022->50022/tcp, 0.0.0.0:2022->22/tcp jenkins
Since the default.conf
file is mounted from the host it can be updated in real-time. Once changes have been made, the user should validate and reload the configuration.
-
Example validation:
$ docker exec nginx /etc/init.d/nginx configtest nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
-
Example reload:
$ docker exec nginx /etc/init.d/nginx reload Reloading nginx: nginx.
[1] Official Jenkins Docker Image: https://github.com/jenkinsci/docker
[2] Get into DevOps (blog): https://getintodevops.com/blog/the-simple-way-to-run-docker-in-docker-for-ci
[3] Docker Compose Github Releases: https://github.com/docker/compose/releases
[4] Advantage of Tini: krallin/tini#8
[5] Jenkins behind an NGinX reverse proxy: https://wiki.jenkins.io/display/JENKINS/Jenkins+behind+an+NGinX+reverse+proxy