
Run Jenkins in a Docker container — part 2 — socat
Guide for developers to get up and running with Jenkins running in Docker (on Windows).
This small series of guides will walk through three solutions for installing Jenkins in a Docker container on Windows, along with the configuration necessary to spin up dynamic build slaves also using Docker containers.
Running locally on a personal device is perfect for individual users, freelancers, or developers looking to do local Jenkinsfile or Shared Library development and testing before pushing to a central CI/CD platform.
“You said three solutions?” Yes — this article demonstrates using socat (further reading at socat). Part 1 was using Docker-in-Docker and Part 3 is to run the Jenkins container as root user. Jump to those articles below.
What was wrong with using Docker-in-Docker
This article discusses the pros and cons of Docker-in-Docker and argues against using it for CI systems like Jenkins.
It suggests a better pattern would be to provide the container access to the host daemon directly via sharing a volume for its unix socket /var/run/docker.sock
— and this is possible on Windows too since we are using WSL — the primary obstacle we face is that the jenkins
user doesn’t have the required permissions.
Part 3 of this series set up Jenkins to run as root
user; this article will demonstrate an alternative using socat.
Solution using socat
The steps we will go through;
- Command line, step-by-step to set up Jenkins.
- Configure Jenkins via the Console UI and set up the “docker” plugin.
- Verify the set up via a couple of test jobs.
- Translate the command lines into a Docker Compose template.
Prerequisites
We assume you have Docker installed — for this demo I am running on a Windows 10 laptop with WSL enabled (Hyper-V is also okay).
Volumes
Before we start up, create a volume that you will use for your Jenkins home directory — that way it will persist between restarts.
docker volume create jenkins-data
Networking
We’re going to use a bridge network called jenkins
which we create by running the command docker network create jenkins
. In the rest of our configuration, we will attach all our containers to this network.
In order to give Jenkins access to the Docker daemon running on the host machine (Windows), we will use a socat container to publish the unix socket /var/run/docker.sock
(to the Docker daemon) as port 2375.
docker container run --name jenkins-docker \
--detach --restart unless-stopped \
--network jenkins --network-alias docker \
--volume /var/run/docker.sock:/var/run/docker.sock \
--publish 2375:2375 \
alpine/socat \
tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock
After running this command, the socat container will be listening on port 2375 and since we gave it the network alias of docker
then we will be able to reach it from Jenkins on tcp://docker:2375
.
Running Jenkins
We’re going to use the jenkinsci/blueocean
image that comes pre-built with Blue Ocean and you will see that we specify tcp://docker:2375
to communicate with the Docker host.
docker container run --name jenkins-blueocean \
--detach --restart unless-stopped \
--network jenkins \
--env DOCKER_HOST="tcp://docker:2375" \
--env DOCKER_TLS_VERIFY="" \
--volume jenkins-data:/var/jenkins_home \
--publish 8080:8080 --publish 50000:50000 \
jenkinsci/blueocean
Now that Jenkins is started, head over to http://localhost:8080 to go through the initial set up wizard.
Jenkins Set Up Wizard
We won’t go through the Jenkins set up wizard in any detail — the important thing to note however is how to access your admin user unlock code, which you can find this from your running container via the following command:
docker exec jenkins-blueocean cat /var/jenkins_home/secrets/initialAdminPassword
Configuring Docker Cloud
Once you have your Jenkins set up complete, we need to set up running our Jenkins slaves as Docker containers. Head over to “Manage Plugins” and install the docker plugin.

Once installed, go to Manage Nodes and Clouds and then Configure Clouds and Add a new cloud. The type of “docker” should automatically appear in the dropdown.
You want to set the Docker Host URI to tcp://docker:2375
and then run a Test Connection.

This is great — now we can reach the Docker daemon.
Configuring Docker Slaves/Agents
Next step is to set up an agent to run our pipelines against. Once you start developing, you can start building your own build containers and attaching these instead. For now, we shall use the jenkins/agent
image.
Relevant fields below include giving it a label and name. The label allows you to associate a job to a particular agent — so you can always run a Maven build on an Agent that has maven installed, for example.

Our Connect Method will be Attach Docker Container. This runs the Docker container on the host machine.
Save everything and we are now ready to create a test job.
Verifying it all works
You are now ready to create a job to check that all is set up and working correctly. Create a new freestyle job. I’ve called mine “test-agent”.
You want to select the agent that this job will run on.

Down under build, write a simple “hello world” message as a test.

Save and build your new job. Jenkins will download the image for your container and run the job upon it. On completion you should get output such as that shown below.

All done. Success!
Docker Compose
Command line is all well and good, but it’s much easier to define as a docker compose yaml file. Start up with docker-compose up -d
.
version: '3.8'networks:
jenkins-network:
name: jenkinsvolumes:
data:
name: jenkins-dataservices: socat:
container_name: jenkins-docker
image: alpine/socat
restart: unless-stopped
networks:
jenkins-network:
aliases:
- docker
expose:
- "2375"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock jenkins:
container_name: jenkins-blueocean
image: jenkinsci/blueocean
restart: unless-stopped
networks:
- jenkins-network
ports:
- 8080:8080
- 50000:50000
volumes:
- data:/var/jenkins_home
environment:
- DOCKER_HOST=tcp://docker:2375
- DOCKER_TLS_VERIFY=""
A note from the author
Thank you for reading this article and I hope you found time to read the original part 1 and could contrast against the solution in part 3 as well — I hope you found them useful and via one of the articles you settled on a technique that suited your personal set up.
All source code for these articles can be found on GitHub.