{"id":458,"date":"2025-10-14T01:55:00","date_gmt":"2025-10-14T01:55:00","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=458"},"modified":"2025-10-14T01:55:00","modified_gmt":"2025-10-14T01:55:00","slug":"docker-containers-as-build-slaves-jenkins","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=458","title":{"rendered":"How to Setup Docker containers as Build Agents for Jenkins"},"content":{"rendered":"<p>This article guides you to set up Jenkins build inside a Docker container using Docker-based Jenkins build agents.<\/p>\n<p>The resource utilization of the Jenkins agents is very less if you do not have builds happening continuously. It is better to use ephemeral Docker containers as Jenkins agents for better resource utilization in this scenario.<\/p>\n<p>As you know, spinning up a new container takes less than a minute; every build spins up a new container, builds the project, and is destroyed. This way, you can reduce the number of static Jenkins build VMs.<\/p>\n<h2 id=\"docker-containers-as-build-agentsslaves\">Docker Containers as Build Agents\/Slaves<\/h2>\n<p>In this guide, I will walk you through the steps for configuring <a href=\"https:\/\/devopscube.com\/what-is-docker\/\" rel=\"noreferrer noopener\">Docker Containers<\/a> as build agents.<\/p>\n<p>I assume that you have a Jenkins server up and running. If you do not have one, follow this tutorial. <a href=\"https:\/\/devopscube.com\/install-configure-jenkins-2-0\/\" rel=\"noopener noreferrer\">How to setup Jenkins 2<\/a><\/p>\n<p>If you want docker based Jenkins setup, you can follow this tutorial -&gt; <a href=\"https:\/\/discuss.devopscube.com\/t\/how-to-setup-jenkins-using-docker-with-a-host-mount\/83?ref=devopscube.com\" rel=\"noopener noreferrer\">Setup Jenkins On a Docker container<\/a><\/p>\n<p><strong>Let&#8217;s Implement It<\/strong><\/p>\n<h2 id=\"configure-a-docker-host-with-remote-api-important\">Configure a Docker Host With Remote API [Important]<\/h2>\n<p>The first thing we should do is set up a docker host. Jenkins server will connect to this host for spinning up the build agent containers. I am going to use the Centos server as my docker host. You can use any OS which supports Docker.<\/p>\n<p>Jenkins master connects to the docker host using REST APIs. So we need to enable the remote API for our docker host.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-docker-slave-1.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"590\" height=\"320\"><figcaption><span style=\"white-space: pre-wrap;\">Click to view in HD<\/span><\/figcaption><\/figure>\n<p>Make sure the following ports are enabled in your server firewall to accept connections from Jenkins master.<\/p>\n<p><!--kg-card-begin: html--><\/p>\n<table>\n<tbody>\n<tr>\n<td>Docker Remote API port<\/td>\n<td>4243<\/td>\n<\/tr>\n<tr>\n<td>Docker Hostport Range<\/td>\n<td>32768 to 60999 <\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><!--kg-card-end: html--><\/p>\n<p><code>32768 to 60999<\/code> is used by Docker to assign a host port for Jenkins to connect to the container. Without this connection, the build slave would go in a pending state.<\/p>\n<p>Lets get started,<\/p>\n<p><strong>Step 1: <\/strong>Spin up a VM, and install docker on it. You can follow the official<a href=\"https:\/\/docs.docker.com\/engine\/installation\/?ref=devopscube.com\" rel=\"noopener noreferrer\"> documentation for installing docker. <\/a>based on the Linux distribution you use. Make sure the docker service is up and running.<\/p>\n<p><strong>Step 2: L<\/strong>og in to the server and open the docker service file <code>\/lib\/systemd\/system\/docker.service<\/code>. Search for <code>ExecStart<\/code> and replace that line with the following.<\/p>\n<pre><code class=\"language-bash\">ExecStart=\/usr\/bin\/dockerd -H tcp:\/\/0.0.0.0:4243 -H unix:\/\/\/var\/run\/docker.sock<\/code><\/pre>\n<p><strong>Step 3: <\/strong>Reload and restart docker service.<\/p>\n<pre><code class=\"language-bash\">sudo systemctl daemon-reload\nsudo service docker restart<\/code><\/pre>\n<p>Step 4: Validate API by executing the following curl commands. Replace <code>54.221.134.7<\/code> with your host IP.<\/p>\n<pre><code class=\"language-bash\">curl http:\/\/localhost:4243\/version\ncurl http:\/\/54.221.134.7:4243\/version<\/code><\/pre>\n<p>Check the <a href=\"https:\/\/scriptcrunch.com\/enable-docker-remote-api\/?ref=devopscube.com\" rel=\"noreferrer noopener\">docker remote API<\/a> article for a detailed explanation of Docker API.<\/p>\n<p>Once you enabled and tested the API, you can now start building the docker slave image.<\/p>\n<h2 id=\"create-a-jenkins-agent-docker-image\">Create a Jenkins Agent Docker Image<\/h2>\n<p>I have created a <a href=\"https:\/\/hub.docker.com\/r\/bibinwilson\/jenkins-slave\/?ref=devopscube.com\">Jenkins docker image for maven<\/a>. You can use this image or use its <a href=\"https:\/\/github.com\/bibinwilson\/jenkins-docker-slave?ref=devopscube.com\" rel=\"noopener noreferrer\">Dockerfile<\/a> as a reference for creating your own.<\/p>\n<p>If you are creating the image on your own, its image should contain the following minimum configurations to act as a slave.<\/p>\n<ol>\n<li><code>sshd<\/code> service running on port 22.<\/li>\n<li>Jenkins user with password.<\/li>\n<li>All the required application dependencies for the build. For example, for a java maven project, you need to have git, java, and maven installed on the image.<\/li>\n<\/ol>\n<p>Make sure the <code>sshd<\/code> service is running and can be logged into the containers using a username and password. Otherwise, Jenkins will not be able to start the build process.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note: <\/strong><\/b>The default ssh username is <b><strong style=\"white-space: pre-wrap;\">jenkins and the <\/strong><\/b>password is also <b><strong style=\"white-space: pre-wrap;\">jenkins<\/strong><\/b> as per the given Dockerfile. You will have to use these credentials in the below configuration.<\/div>\n<\/div>\n<h2 id=\"configure-jenkins-server-with-docker-plugin\">Configure Jenkins Server With Docker Plugin<\/h2>\n<p><strong>Step 1<\/strong>: Head over to Jenkins Dashboard &#8211;&gt; Manage Jenkins &#8211;&gt; Manage Plugins.<\/p>\n<p><strong>Step 2<\/strong>: Under the Available tab, search for &#8220;Docker&#8221; and install the docker cloud plugin and restart Jenkins. Here is the <a href=\"https:\/\/plugins.jenkins.io\/docker-plugin?ref=devopscube.com\" rel=\"noreferrer noopener\">official plugin site<\/a>. Make sure you install the right plugin as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-docker-plugin-min-1.png\" class=\"kg-image\" alt=\"Install Jenkins Docker Plugin\" loading=\"lazy\" width=\"593\" height=\"489\"><\/figure>\n<p><strong>Step 3: <\/strong>Once installed, head over to Jenkins Dashboard &#8211;&gt; Manage Jenkins &#8211;&gt; Configure system.<\/p>\n<p><strong>Step 4<\/strong>: Under &#8220;<code>Configure System<\/code>&#8220;, there will be a section named &#8220;<strong>cloud<\/strong>&#8221; at the last. There you can fill out the docker host parameters for spinning up the slaves.<\/p>\n<p><strong>Step 5:<\/strong> Under docker, you need to fill out the details as shown in the image below.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note<\/strong><\/b>: Replace &#8220;Docker URI&#8221; with your docker host IP. For example, <code spellcheck=\"false\" style=\"white-space: pre-wrap;\">tcp:\/\/10.128.0.3:4243<\/code> You can use the &#8220;Test connection&#8221; to test if Jenkins is able to connect to the Docker host.<\/div>\n<\/div>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/configure-docker-cloud-min-1.png\" class=\"kg-image\" alt=\"configure Jenkins docker cloud\" loading=\"lazy\" width=\"633\" height=\"387\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/configure-docker-cloud-min-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/configure-docker-cloud-min-1.png 633w\"><\/figure>\n<p><strong>Step 6:<\/strong> Now, from &#8220;<strong>Docker Agent Template<\/strong>&#8221; dropdown, click th<strong>e <\/strong>&#8220;Add <strong>Docker template<\/strong>&#8221; and fill in the details based on the explanation and the image given below and save the configuration.<\/p>\n<ol>\n<li><strong>Labels<\/strong> &#8211; Identification for the docker host. It will be used in the Job configuration. Here we use<code> java-docker-slave<\/code><\/li>\n<li><strong>Name:<\/strong> Name of the docker template. Here we use the same name as label ie, java-docker-slave<\/li>\n<li><strong>Docker Image<\/strong> &#8211;<code> bibinwilson\/jenkins-slave:latest<\/code> or the image that you created for the slave.<\/li>\n<li><strong>Remote Filing System Root<\/strong> &#8211; Home folder for the user you have created. In our case, it&#8217;s \/home\/jenkins<\/li>\n<li><strong>Credentials<\/strong> &#8211; click add and enter the SSH username and password that you have created for the docker image. Leave the rest of the configuration as shown in the image below and click save. If you are using my Docker image, the user will be <code>jenkins<\/code> &amp; password is also  <code>jenkins<\/code>.<\/li>\n<\/ol>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note:<\/strong><\/b> There are additional configurations like registry authentication and container settings that you might have to use when configuring this set up in the corporate network.<\/div>\n<\/div>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/docker-template-min-1.png\" class=\"kg-image\" alt=\"Jenkins Docker agent tempalte configuration\" loading=\"lazy\" width=\"653\" height=\"770\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/docker-template-min-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/docker-template-min-1.png 653w\"><\/figure>\n<p>You can also use JNLP-based slave agents. For this, the configurations need a little change as shown below. Primarily the <code>docker image name<\/code> and the <code>connect method<\/code>.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-grey\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note:<\/strong><\/b> For JNLP to work, you need to enable the JNLP connection port (50000) in Jenkins&#8217;s global security configuration (<code spellcheck=\"false\" style=\"white-space: pre-wrap;\">TCP port for inbound agents)<\/code>. Also, the Jenkins master firewall should be able to accept this connection form the docker host.<\/div>\n<\/div>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-docker-jnlp-min-1.png\" class=\"kg-image\" alt=\"Docker jnlp agent template configuration\" loading=\"lazy\" width=\"621\" height=\"403\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/jenkins-docker-jnlp-min-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-docker-jnlp-min-1.png 621w\"><\/figure>\n<p>By default, the workspace will not be persisted in the host. However, if you want the workspace to be persistent, add a host volume path under container settings.<\/p>\n<p>For example, if you want the workspace to be available at <code>\/home\/ubuntu<\/code>, you can add the volume path as shown below.<code> \/home\/jenkins<\/code> is the path inside the container.<\/p>\n<pre><code>\/home\/ubuntu:\/home\/jenkins<\/code><\/pre>\n<p>Towards the right of the Volumes option, if you click the question mark, it will show you additional volume options as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/container-volume-min-1.png\" class=\"kg-image\" alt=\"mount volume to Jenkins docker agent\" loading=\"lazy\" width=\"609\" height=\"315\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/container-volume-min-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/container-volume-min-1.png 609w\"><\/figure>\n<h2 id=\"building-docker-images-using-docker-agents\">Building Docker Images using Docker Agents<\/h2>\n<p>There are use cases where you have to <a href=\"https:\/\/devopscube.com\/build-docker-image\/\">build Docker images<\/a> in the CI process.<\/p>\n<p>You can achieve that using Docker based Jenkins agent as well.<\/p>\n<p>If you are planning to run docker in docker for your CI process, you can mount the host <code>docker.sock<\/code> as volume to execute docker commands.<\/p>\n<p>Check out my <a href=\"https:\/\/devopscube.com\/run-docker-in-docker\/\" rel=\"noreferrer noopener\">article on running docker in docker<\/a> to know how to run docker in docker.<\/p>\n<h2 id=\"test-jenkins-build-inside-a-docker-container\">Test Jenkins Build Inside a Docker container<\/h2>\n<p>Now that you have the slave configurations ready, we will test the docker agent plugin using a freestyle job.<\/p>\n<ol>\n<li>Create a freestyle job, select &#8220;<code>Restrict where this project can be run<\/code>&#8221; option and select the docker host as a slave using the label.<\/li>\n<li>Add a shell build step which echoes a simple &#8220;<code>Hello World<\/code>&#8220;<\/li>\n<\/ol>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/docker-slave-freestyle-job-min-1.png\" class=\"kg-image\" alt=\"Jenkins build job with container as build agent\" loading=\"lazy\" width=\"955\" height=\"1698\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/docker-slave-freestyle-job-min-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/docker-slave-freestyle-job-min-1.png 955w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>If you have done all the configurations right, Jenkins will spin up a container, builds the project, and destroys the container once the build is done.<\/p>\n<p>First, you will see a pending notification as Jenkins tries to deploy a container on run time and establishes an SSH connection. After a few seconds, your job will start building.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-330.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"569\" height=\"50\"><\/figure>\n<p>You can check the build logs in your jobs console output as shown below.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/docker-slave-output-min-1.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"530\" height=\"127\"><\/figure>\n<p>Also, you can check out the video explaining the whole process.<\/p>\n<figure class=\"kg-card kg-embed-card\"><iframe loading=\"lazy\" width=\"160\" height=\"90\" src=\"https:\/\/www.youtube.com\/embed\/yb6DodK6mbg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen=\"\"><\/iframe><\/figure>\n<h2 id=\"possible-errors\"><strong>Possible Errors:<\/strong><\/h2>\n<ol>\n<li><strong>Jenkins is not able to deploy containers on the host:<\/strong>&#8211; Please make sure you have proper connectivity to the docker host on API port.<\/li>\n<li><strong>Jenkins builds goes in the pending state forever:<\/strong>&#8211; Make sure you have Docker host ports (32768 to 60999) access from Jenkins master to docker host.<\/li>\n<li><strong>JNLP slaves go into the pending state<\/strong>: Make sure you have enabled the JNLP port in the Jenkins global security configuration.<\/li>\n<\/ol>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>In this article, I walked you through the process of setting up dynamic Jenkins Docker  agents<\/p>\n<p>If you want to build Jenkins inside a Docker container, and you don&#8217;t have a <a href=\"https:\/\/devopscube.com\/setup-kubernetes-cluster-kubeadm\/\" rel=\"noreferrer noopener\">Kubernetes setup<\/a>, this is the best option.<\/p>\n<p>If you have a Kubernetes setup, then you consider setting up the agents on Kubernetes. You can check my blog on <a href=\"https:\/\/devopscube.com\/jenkins-build-agents-kubernetes\/\">Kubernetes based Jenkins build agents<\/a> to for more details.<\/p>\n<p>It can be further customized to fit your specific use cases.<\/p>\n<p>Please let me know your thoughts in the comment section. Also, don&#8217;t forget to share this article \ud83d\ude42<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/docker-containers-as-build-slaves-jenkins\/\" target=\"_blank\" rel=\"noopener noreferrer\">How to Setup Docker containers as Build Agents for Jenkins \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/docker-containers-as-build-slaves-jenkins\/<\/p>\n","protected":false},"author":1,"featured_media":459,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-458","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/458","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=458"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/458\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/459"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=458"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=458"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=458"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}