Automating Jenkins install and configuration with Docker and Terraform

automating jenkins install and configuration terraform docker

This post is part of Jenkins tutorials on Popularowl. In the previous sections we did manual install, configuration and production readiness for Jenkins.

This part is about automating the manual provisioning using infrastructure as a concept.

By the end of this tutorial you will have the automation scripts which will containerise and install Jenkins CI on virtual machine of your choice.

With auto-installed plugins, automatically skipped Jenkins setup wizard and pre created administrator user.


Building Jenkins as a Docker container

In this section we will create Docker container image containing our customised Jenkins setup.

By containerising our Jenkins CI server instance, we gain the ability to deploy it on multiple cloud native environments as immutable image. And the same image can run locally on your development machine as well.

First, let’s create file named Dockerfile with the following content.

FROM jenkins/jenkins:latest

# volume for Jenkins settings
VOLUME /var/jenkins_home

If we build Docker image from this file now it would pull the latest official container provided by Jenkins team and would create the custom volume for us.

But it’s not enough.

Skipping Jenkins default setup wizard

Remember the setup wizard and new user creation screens we filled in manually in the previous tutorial?

We would like to skip these steps in our Jenkins container, so when we start it its ready to go.

The experience we want – is that after Terraform has finished running, we should get a ready to be used Jenkins with admin user login screen.

In order to achieve this, we have to set the following Java environment option to instruct Jenkins to skip Setup Wizard during first startup.

ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false

Now we need to programatically add Jenkins admin user.

Automate Jenkins admin user setup

Right after the startup, Jenkins loads all the .groovy files it finds in init.groovy.d/ directory.

We will use this behaviour and write the custom Groovy DSL file which uses Jenkins internal API. It will create admin user with the predefined username and password. Here is the file.

import jenkins.model.*

def env = System.getenv()

def jenkins = Jenkins.getInstance()
if(!(jenkins.getSecurityRealm() instanceof HudsonPrivateSecurityRealm))
    jenkins.setSecurityRealm(new HudsonPrivateSecurityRealm(false))

if(!(jenkins.getAuthorizationStrategy() instanceof GlobalMatrixAuthorizationStrategy))
    jenkins.setAuthorizationStrategy(new GlobalMatrixAuthorizationStrategy())

def user = jenkins.getSecurityRealm().createAccount(env.JENKINS_USER, env.JENKINS_PASS)
jenkins.getAuthorizationStrategy().add(Jenkins.ADMINISTER, env.JENKINS_USER)

You can see that we are creating admin user, with username / password which we will provide as environment variables in Dockerfile.

This Groovy file will be copied over to container during the Docker build stage.

Installing Jenkins plugins from file

We also wanted to auto pre-install some selected plugins.

Jenkins official Docker image ships with the script which installs any plugin we pass as argument.

We are going to create the file named jenkins-plugins with the list of Jenkins plugins we want to be pre-installed.

Then we will use simple loop during our Docker container build to pass the plugin names to this plugin installation script one by one.

Update the Dockerfile with:

# install jenkins plugins
COPY ./jenkins-plugins /usr/share/jenkins/plugins
RUN while read i ; \ 
      do /usr/local/bin/ $i ; \
    done < /usr/share/jenkins/plugins

Our Dockerfile should now be completed.

You can find the source code version in the source files for this tutorial.

If you build the Docker image from this file, you will have ready to run Jenkins server.

Provisioning Host

Next, we are going to use Terraform for auto provisioning Digital Ocean virtual machine instance.

Terraform is a great tool, which allows you to maintain cloud infrastructure as a version controlled code. It has multiple providers to connect to the public cloud providers like AWS, Google Cloud, Azure, DigitalOcean etc.

This tutorial is not the Terraform 101. If you have to learn the basics, start here.

Create the file.

This file will hold the variables which we will use for automation. Add the following contents:

variable "token" {
  description = "Digital Ocean Api Token"

variable "region" {
  description = "Digital Ocean Region"
  default = "lon1"
variable "droplet_image" {
  description = "Digital Ocean Droplet Image"
  default = "debian-9-x64"

variable "jenkins_droplet_size" {
  description = "Droplet size for Jenkins server"
  default = "1gb"

# location of the private ssh key 
# used for ssh connection by terraform
# change the location if different on 
# your local machine
variable "pvt_sshkey" {
  description = "Location of the local private ssh key"
  default = "~/.ssh/id_rsa"

# ssh_fingerprint should be exported in the local
# shell environment to avoid hardcoded values
# see for examples
variable "ssh_fingerprint" {
  description = "Fingerprint of the public ssh key stored on Digital Ocean"

Next, create another file

This will be the main file Terraform will use for automation tasks. For now add the following content:

# main Terraform file to describe automation

# choose Digital Ocean provider
provider "digitalocean" {
  token = "${var.token}"

# create VM instance on Digital Ocean
resource "digitalocean_droplet" "jenkinsci-server" {
  image = "${var.droplet_image}"
  name = "jenkinsci-server"
  region = "${var.region}"
  size = "${var.jenkins_droplet_size}"
  ssh_keys = [

  connection {
        user = "root"
        type = "ssh"
        private_key = "${file(var.pvt_sshkey)}"
        timeout = "2m"

# print out ip address of created Jenkins server VM
output "service-ip" {
  value = "${digitalocean_droplet.jenkinsci-server.ipv4_address}"

You can see the variables we have defined earlier in the file referenced here.

We are choosing the Terraform provider, which in our case is Digital Ocean. Describing the name and size of the VM we want Terraform to create.

And specifying ssh connection details.

I’m referring to the location of the private ssh key on the local machine (the one where you are running Terraform).

Also to the public key fingerprint – this public key you will upload and store in Digital Ocean platform.

Digital Ocean token is the equivalent of API key and is specific to your account.

Another important bit – I’m not hardcoding the sensitive values of the key fingerprint or Digital Ocean token.

It is a bad practice to store such secrets in plain in the code.

We will export them as the environment variables with TF_VAR_xx prefix. Terraform will automatically have an access to these.

The below works for Mac OS / Linux. Windows is slightly different.

export TF_VAR_token=xxxxxxxxx
export TF_VAR_ssh_fingerprint=xxxxxxxxx

Now we are ready to initialise the Terraform project and create the VM server.

terraform init
terraform apply

Terraform should now connect to Digital Ocean, create the VM for you and establish the connectivity via ssh.

It will print out the IP address of newly created server.

You can run terraform destroy to remove the VM for now.

Installing Dependencies

Now add the following to your file.

provisioner "remote-exec" {
      inline = [

        "apt update",
        "apt -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common",
        "apt -y install nginx",
        "apt -y install ufw",
        # setup debian firewall
        "ufw status verbose",
        "ufw default deny incoming",
        "ufw default allow outgoing",
        "ufw allow ssh",
        "ufw allow 22",
        "ufw allow 80",
        "yes | ufw enable"        

remote-exec instructs Terraform to run commands via ssh terminal.

It’s a great way to automate any manual commands you want to run via ssh.

Once you run terraform apply again, terraform will execute all the commands as described in Give it a try.

Now, add all the manual commands we ran in the previous tutorial.

Your terraform will now be automating all these steps. In addition, we will also need Docker to be installed on the VM.

See the final version of main Terraform file in source code repository with all the dependencies added.

Launching Jenkins Docker container with Terraform

We now have all the necessary files and setup for automating the build of our Jenkins container, starting Jenkins server and provisioning Nginx / firewall in front of it.

Finally, add the following steps to file, remote-exec section.

# build jenkins image with default admin user
"cd/tmp && dockerbuild-tpopularowl/jenkins.",

# run newly built jenkins container on port 8080

This will tell Terraform to run Docker build command on the VM and after successful Docker build, start the docker container.


In this tutorial, we have created files and the setup needed for automating provisioning and setup of Jenkins CI server.

We used Docker and Terraform toolset to accomplish that.

The full source code of this tutorial can be found in dedicated repository on GitHub.

Did you like this post?
Subscribe to receive new Popularowl
tutorials and posts

2 Responses

  • Jeremy

    When I try to setup the admin user using the Groovy script I get this problem when I attempt to use the account:

    Access Denied
    admin is missing the Overall/Read permission

    Then I can’t access anything in the web frontend anymore.
    Any idea why this might be?
    I see this is a pretty recent post, so I wonder what I’m doing wrong.

    • Hi Jeremy,
      check if you have copied the line starting with jenkins.getAuthorizationStrategy() from the tutorial.
      this is the line which assigns user administrator privileges.

Post Your Comment

Your email address will not be published.