The target of this entry is explain how to setup a local Jenkins server to test your pipelines during their development stage, I think that could be quicker to use a local Jenkins server when you’re developing your pipelines or even your Groovy common libraries. To this lab we’re going to use Terraform with its Docker provider.
Let’s define first the Jenkins container requirements:
- 8080 port to access to Jenkins web interface
- Local directory to be used as Jenkins Home directory
- To attach build slave servers through JNLP (Java Web Start): map the port:
-p 50000:50000
- Environment variables:
- –env JAVA_OPTS=”-Dhudson.footerURL=http://acme.com”
Getting Terraform configuration
$ git clone https://github.com/neklaf/lab-jenkins-terraform-docker $ cd lab-jenkins-terraform-docker
Launching Jenkins container
$ terraform init Initializing the backend... Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "docker" (terraform-providers/docker) 2.7.0... ... * provider.docker: version = "~> 2.7" Terraform has been successfully initialized! ... $ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # docker_container.jenkins will be created + resource "docker_container" "jenkins" { + attach = false + bridge = (known after apply) + command = (known after apply) + container_logs = (known after apply) + entrypoint = (known after apply) + env = [ + "JAVA_OPTS=-Dhudson.footerURL=http://acme.com", ] + exit_code = (known after apply) + gateway = (known after apply) + hostname = (known after apply) + id = (known after apply) + image = "jenkins/jenkins:lts" + ip_address = (known after apply) + ip_prefix_length = (known after apply) + ipc_mode = (known after apply) + log_driver = "json-file" + logs = false + must_run = true + name = "jenkins" + network_data = (known after apply) + network_mode = "jenkins_net" + read_only = false + restart = "always" + rm = false + shm_size = (known after apply) + start = true + labels { + label = (known after apply) + value = (known after apply) } + mounts { + source = "jenkins_home" + target = "/var/jenkins_home" + type = "volume" } + ports { + external = 8080 + internal = 8080 + ip = "0.0.0.0" + protocol = "tcp" } } # docker_image.jenkins will be created + resource "docker_image" "jenkins" { + id = (known after apply) + latest = (known after apply) + name = "jenkins/jenkins:lts" } # docker_network.jenkins_net will be created + resource "docker_network" "jenkins_net" { + driver = (known after apply) + id = (known after apply) + internal = (known after apply) + ipam_driver = "default" + name = "jenkins_net" + options = (known after apply) + scope = (known after apply) + ipam_config { + aux_address = (known after apply) + gateway = (known after apply) + ip_range = (known after apply) + subnet = (known after apply) } } # docker_volume.jenkins_home will be created + resource "docker_volume" "jenkins_home" { + driver = (known after apply) + id = (known after apply) + mountpoint = (known after apply) + name = (known after apply) } Plan: 4 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
Let’s apply the plan:
$ terraform apply An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # docker_container.jenkins will be created + resource "docker_container" "jenkins" { + attach = false + bridge = (known after apply) + command = (known after apply) + container_logs = (known after apply) + entrypoint = (known after apply) + env = [ + "JAVA_OPTS=-Dhudson.footerURL=http://acme.com", ] + exit_code = (known after apply) + gateway = (known after apply) + hostname = (known after apply) + id = (known after apply) + image = "jenkins/jenkins:lts" + ip_address = (known after apply) + ip_prefix_length = (known after apply) + ipc_mode = (known after apply) + log_driver = "json-file" + logs = false + must_run = true + name = "jenkins" + network_data = (known after apply) + network_mode = "jenkins_net" + read_only = false + restart = "always" + rm = false + shm_size = (known after apply) + start = true + labels { + label = (known after apply) + value = (known after apply) } + mounts { + source = "jenkins_home" + target = "/var/jenkins_home" + type = "volume" } + ports { + external = 8080 + internal = 8080 + ip = "0.0.0.0" + protocol = "tcp" } } # docker_image.jenkins will be created + resource "docker_image" "jenkins" { + id = (known after apply) + latest = (known after apply) + name = "jenkins/jenkins:lts" } # docker_network.jenkins_net will be created + resource "docker_network" "jenkins_net" { + driver = (known after apply) + id = (known after apply) + internal = (known after apply) + ipam_driver = "default" + name = "jenkins_net" + options = (known after apply) + scope = (known after apply) + ipam_config { + aux_address = (known after apply) + gateway = (known after apply) + ip_range = (known after apply) + subnet = (known after apply) } } # docker_volume.jenkins_home will be created + resource "docker_volume" "jenkins_home" { + driver = (known after apply) + id = (known after apply) + mountpoint = (known after apply) + name = (known after apply) } Plan: 4 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes docker_volume.jenkins_home: Creating... docker_image.jenkins: Creating... docker_network.jenkins_net: Creating... docker_container.jenkins: Creating... docker_volume.jenkins_home: Creation complete after 0s [id=ab0fc7406a03bc9f60abba369480e6001e6d40aadc1e4cd77b42f2dda81f2354] docker_network.jenkins_net: Creation complete after 2s [id=300c0c7d88a63bf78a5e2f758b69317f647a60c050010da21170f8cb65ca9c2c] docker_image.jenkins: Still creating... [10s elapsed] docker_container.jenkins: Still creating... [10s elapsed] docker_image.jenkins: Still creating... [20s elapsed] docker_container.jenkins: Still creating... [20s elapsed] docker_image.jenkins: Still creating... [30s elapsed] docker_container.jenkins: Still creating... [30s elapsed] docker_image.jenkins: Still creating... [40s elapsed] docker_container.jenkins: Still creating... [40s elapsed] docker_image.jenkins: Still creating... [50s elapsed] docker_container.jenkins: Still creating... [50s elapsed] docker_image.jenkins: Still creating... [1m0s elapsed] docker_container.jenkins: Still creating... [1m0s elapsed] docker_image.jenkins: Still creating... [1m10s elapsed] docker_container.jenkins: Still creating... [1m10s elapsed] docker_image.jenkins: Still creating... [1m20s elapsed] docker_container.jenkins: Still creating... [1m20s elapsed] docker_image.jenkins: Creation complete after 1m23s [id=sha256:b2428543fab000c6b93cf4ac8d27ea243a4f798ca4e3ae09789630b93786ef31jenkins/jenkins:lts] docker_container.jenkins: Creation complete after 1m24s [id=cd83d4f4a60a3943bd755c1fbb10b972093bfd935159f931df292862824d3efc] Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Verification
The first step and the easiest one should be to browse to this URL http://localhost:8080:

Also some additional verifications from our side using the command line:
$ docker ps --filter name=jenkins CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 52053dff01d2 jenkins/jenkins:lts "/sbin/tini -- /usr/…" 16 minutes ago Up 16 minutes 127.0.0.1:8080->8080/tcp, 127.0.0.1:50000->50000/tcp jenkins $ docker inspect jenkins | jq -r '.[].Config.Env[]' | grep -i JAVA_OPTS JAVA_OPTS=-Dhudson.footerURL=http://acme.com $ docker inspect jenkins | jq -r '.[].HostConfig.RestartPolicy.Name' always $ docker inspect jenkins | jq -r '.[].HostConfig.NetworkMode' $ docker inspect jenkins | jq -r '.[].Mounts[].Name' $ docker inspect jenkins | jq -r '.[].Mounts[].Type'
Cleaning up
$ terraform destroy docker_image.jenkins: Refreshing state... [id=sha256:b2428543fab000c6b93cf4ac8d27ea243a4f798ca4e3ae09789630b93786ef31jenkins/jenkins:lts] docker_volume.jenkins_home: Refreshing state... [id=ab0fc7406a03bc9f60abba369480e6001e6d40aadc1e4cd77b42f2dda81f2354] docker_network.jenkins_net: Refreshing state... [id=300c0c7d88a63bf78a5e2f758b69317f647a60c050010da21170f8cb65ca9c2c] docker_container.jenkins: Refreshing state... [id=cd83d4f4a60a3943bd755c1fbb10b972093bfd935159f931df292862824d3efc] ... Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes docker_image.jenkins: Destroying... [id=sha256:b2428543fab000c6b93cf4ac8d27ea243a4f798ca4e3ae09789630b93786ef31jenkins/jenkins:lts] docker_volume.jenkins_home: Destroying... [id=ab0fc7406a03bc9f60abba369480e6001e6d40aadc1e4cd77b42f2dda81f2354] docker_network.jenkins_net: Destroying... [id=300c0c7d88a63bf78a5e2f758b69317f647a60c050010da21170f8cb65ca9c2c] docker_container.jenkins: Destroying... [id=cd83d4f4a60a3943bd755c1fbb10b972093bfd935159f931df292862824d3efc] docker_container.jenkins: Destruction complete after 1s docker_volume.jenkins_home: Destruction complete after 2s docker_network.jenkins_net: Destruction complete after 2s Error: Unable to remove Docker image: Error response from daemon: conflict: unable to delete b2428543fab0 (cannot be forced) - image is being used by running container cd83d4f4a60a $ docker rmi jenkins/jenkins:lts Untagged: jenkins/jenkins:lts Untagged: jenkins/jenkins@sha256:7ea1d29c621a10d1e231013f62e32f0eb726dde15a4c219e5010564a6766daa8 ...
Reference links:
- https://www.terraform.io/docs/providers/docker/index.html
- https://github.com/jenkinsci/docker
- https://medium.com/swlh/quickstart-ci-with-jenkins-and-docker-in-docker-c3f7174ee9ff
- https://medium.com/@Joachim8675309/docker-the-terraform-way-part-2-e979369028a6
- https://jenkins.io/doc/book/pipeline/docker/
—
“It is the mark of an educated mind to be able to entertain a thought without accepting it.”
— Aristotle, Metaphysics