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 a manual install, configuration and production readiness for Jenkins CI server.

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

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.

Prerequisites

  • Access to the Debian Linux server. You can use VirtualBox locally or one of the cloud platforms (We are using Digital Ocean cloud as example in this tutorial).
  • Docker installed (Mac or Windows).

Building Jenkins as a Docker container

In this section we will create a 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 went ahead and build Docker image from this file now, it would pull the latest official container provided by Jenkins CI team and would create the custom volume for us.

But we need couple more extras.

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 Docker container starts it its ready to go.

The experience we want - is that after Terraform has finished running its steps, we should get a ready to be used Jenkins instance 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 a 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.*
import hudson.security.*

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)
user.save()
jenkins.getAuthorizationStrategy().add(Jenkins.ADMINISTER, env.JENKINS_USER)

jenkins.save()

In the above script we are creating Jenkins CI admin user, with username / password which we will define ss environment variables in Dockerfile.

We also add line to Dockerfile to copy above groovy file to the container image. Update the Dokerfile with following

ENV JENKINS_USER admin
ENV JENKINS_PASS admin

# Jenkins runs all the grovy files from init.groovy.d dir
# use this for creating a default admin user
COPY default-user.groovy /usr/share/jenkins/ref/init.groovy.d/

Installing Jenkins plugins from list

Next, we want to pre-install selected Jenkins CI plugins within container image.

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

We will use this funcionality and create the file named jenkins-plugins with the list of Jenkins plugins we need to be pre-installed.

Then we will use simple while loop to pass the plugin names to plugin installation script one by one.

Update the Dockerfile with the following

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

Our Dockerfile is now be completed.

You can find source files for this tutorial on GitHub.

If you now build the Docker image from this Dockerfile, you will have ready to run conteiner with preconfigured Jenkins CI server.

Lets deploy this to actual virtual server.

Provisioning Cloud Host

Next, we are going to use Terraform for auto provisioning Digital Ocean virtual machine instance and orchestrate Jenkins CI installment for us.

We will also use a Terraform foundation project we created in the previous tutorial on Popularowl. This project gives you a basic Terraform structure for starting new VMs on Digital Ocean cloud platform.

Clone the above repo and we will build our steps on top of foundation code.

Installing Dependencies

Update main.tf file with the following

...
provisioner "remote-exec" {
inline = [

# steps to setup docker ce
"apt update",
"apt -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common",
"curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -",
"add-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable\" ",
"apt update",
"apt-cache policy docker-ce",
"apt -y install docker-ce",

# build Jenkins container image with default admin user
"cd /tmp && docker build -t popularowl/jenkins .",

# run newly built jenkins container on port 8080
"docker run -d --name jenkins-server -p 8080:8080 popularowl/jenkins",

# install remaining dependencies
"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",

# update nginx configuration
"rm -f /etc/nginx/sites-enabled/default",
"cp -f /tmp/jenkins-proxy /etc/nginx/sites-enabled",
"service nginx restart"
]
}
...

remote-exec instructs Terraform to run commands on the cloud VM via ssh terminal. All the above shell lines will run one by one.

They will install Docker CE, build Docker image from Dockerfile, start the container, install and configure Nginx web server and finally, setup firewall to only allow specific requests.

Copy files

We also need to instruct Terraform to copy over the configuration files we have created in the previous steps.

Update main.tf with following

...
// copy the files to newly created instance
provisioner "file" {
source = "files/jenkins-proxy"
destination = "/tmp/jenkins-proxy"
}

provisioner "file" {
source = "files/Dockerfile"
destination = "/tmp/Dockerfile"
}

provisioner "file" {
source = "files/jenkins-plugins"
destination = "/tmp/jenkins-plugins"
}

provisioner "file" {
source = "files/default-user.groovy"
destination = "/tmp/default-user.groovy"
}
...

See the a final version of Terraform code after all the changes applied.

Create and Destroy

Now you have fully funcioning Terraform project which can be ran by using

terraform init
terraform plan
terraform apply
terraform destroy

Summary

We now have the recreatable Jenkins CI installation with preconfigured admin user and pre installed plugins.

Similar posts