TL;DR: example of Jenkins as code. There’s a step by step to configure your Jenkins as code using Ansible tool, and configuration-as-code plug-in at the end of the article. The final version of the OS will have Docker, Kubectl, Terraform, Liquibase, HAProxy (for TLS), Google SSO instructions, and Java installed for running the pipelines.
Why having our Jenkins coded?
One key benefit from having infrastructure and os level coded is the safety it gives to the software administrators. Think with me: what happens if your Jenkins stops working suddenly? What if something happens and nobody can log into it anymore? If these questions make you chill, let’s code our Jenkins!
What we will cover
- This article covers the tools presented in the image above:
- Vagrant for local tests.
- Packer tool for creating your SO image with your Jenkins ready to use
- Ansible for installing everything you need on your SO image (Jenkins, Kubectl, Terraform, etc).
- JCasC (Jenkins Configuration as Code) to configure your Jenkins after it is installed.
- You can also find some useful content for the Terraform part here and here.
See all the code for this article here: https://github.com/guisesterheim/Jenkins-As-Code
Special thanks to many Ansible roles I was able to found on GitHub and geerlingguy for many of the playbooks we’re using here.
1. How to run it
Running locally with Vagrant to test your configuration
The Vagrantfile is used for local tests only, and it is a pre-step before creating the image on your cloud with Packer
- Have (1) Vagrant installed (sudo apt install vagrant) and (2) Oracle’s VirtualBox
- How to run: navigate to the root of this repo and run
sudo vagrant up. After everything is complete, it will create a Jenkins accessible from your host machine at
localhost:6666. This will create a virtual machine and will install everything listed on the Vagrantfile
- How to SSH into the created machine: run
sudo vagrant ssh
- How to destroy the VM: run
sudo vagrant destroy
Packer is a tool to create an OS image (VM on Azure OR AMI on AWS)
packer build -var 'client_id=<client_id>' -var 'client_secret=<client_secret>' -var 'subscription_id=<subscription_id>' -var 'tenant_id=<tenant_id>' packer_config.json
- Once you have your AMI or Az VM Image created, go for your cloud console and create a new machine pointing to the newly created image.
Checkout the file
packer_config.json to see how packer will create your SO image and Azure instructions for it
PS: This specific packer_config.json file is configured to create an image on Azure. You can change it to run on AWS if you have to.
2. Let’s configure our Jenkins as Code!
I’m listing here a few key configurations among the several you will find in each of these Ansible playbooks:
- Java version: on ansible_config/site.yml
- Liquibase version: on ansible_config/roles/ansible-role-liquibase/defaults/main.yml
- Docker edition and version
- Terraform version
- Kubectl packages (adding kubedm or minikube as an example) on ansible_config/roles/ansible-role-kubectl/tasks/main.yml
- Jenkins configs (I will comment further)
- HAProxy for handling TLS (https) (will comment further)
3. Configuring your Jenkins
This Jenkins is configured automatically using the Jenkins plugin
configuration as code. All the configuration is listed on file
jenkins.yaml in this root. On that file, you can add your pipelines and credentials for those pipelines to consume. Full documentation and possibilities can be found here:
Below is the example you will find on the main repo:
- You can define your credentials on block one. There are a few possible credential types here. Check them all on the plugin’s docs
- With this, we create a folder
- Item 3 creates one pipeline job as example fetching it from a private GitLab repo that uses the credentials defined in item 1
The plugins that this Jenkins will have installed can be found at:
ansible_config/roles/ansible-role-jenkins/defaults/main.yml. If you need to get your current installed plugins, you can find how-to here:
On the imag below we can see:
- Your hostname: change it to a permanent hostname instead of localhost once you are configuring TLS
- The plugins list you want to have installed on your Jenkins
You can change Jenkins default admin password on file
ansible_config/roles/ansible-role-jenkins/defaults/main.yml attribute “jenkins_admin_password”. Check the image below:
- You can change admin user and password
- Another configuration you will change when activating TLS (https)
Jenkins’ configuration-as-code plug-in:
For JCasC to work properly, the file jenkins.yml in the project root must be added to Jenkins’ home (default /var/lib/jenkins/). This example has the keys to be used on pipelines and the pipelines as well. There are a few more options on JCasC docs.
Activating TLS (https) and Google SSO
- As shown on step “Jenkins Configuration”‘s images: Go for
ansible_config/roles/ansible-role-jenkins/defaults/main.yml. Uncomment line 15 and change it to your final URL. Comment line 16
- Go for
ansible_config/roles/ansible-role-haproxy/templates/haproxy.cfg. Change line 33 to use your final organization’s URL
- Rebuild your image with Packer (IMPORTANT! Your new image won’t work locally because you changed Jenkins configuration)
- Go for your cloud and deploy a new instance using your just created image
3.1 – TLS: Once you have your machine up and running, connect through SSH to perform the last manual steps: TLS and SSO Google authentication:
- Generate the .pem certificate file with the command
cat STAR.mycompany.com.crt STAR.mycompany.com.key > fullkey.pem. Remember to remove the empty row that is kept inside the generated fullkey.pem between the two certificates. To look at the file use
- Move the generated file to your running instance’s folder
- Restart HAProxy with
sudo service haproxy restart
Done! Your Jenkins is ready to run under https with valid certificates. Just point your DNS to the running machine and you’re done.
- Log in to Jenkins using regular admin credentials. Go to “Manage Jenkins” > “Global Security”. Under “Authentication” select “Login with Google” and fill in like below:
- Client id = client_id generated on your G Suite account.
- Client secret = client_secret
- Google Apps Domain = mycompany.com
PS: More information on how to generate a client ID and client secret on the plugin’s page: https://github.com/jenkinsci/google-login-plugin