Integrating Ansible with Jenkins in a CI/CD process

  • Vagrant and libvirt to create the infrastructure for this lab
  • SonarSource to bring up quality analysis to the CI/CD process
  • Maven to set and deploy the Java project
  • GIT for source code management and control
  • Nexus is the repository for artifact binaries
  • Jenkins to orchestrate the CI/CD pipeline flow
  • And finally, Ansible to create all infrastructure for this lab and the to provision the application

The infrastructure architecture

Figure 1 illustrates the overall architecture for this lab. It has some elements of ALM (Application Lifecycle Management) to emulate a real-world scenario and apply our CI/CD demo pipeline flow.

  • Github is where our project is hosted and where Jenkins will poll for changes to start the pipeline flow.
  • SonarSource is our source code analysis server. If anything goes wrong during the analysis (e.g. not enough unit tests), the flow is interrupted. This step is important to guarantee the source code quality index.
  • Nexus is the artifact repository. After a successful compilation, unit tests and quality analyses, the binaries are uploaded into it. Later those binaries will be downloaded by Ansible during the application deployment.
  • The Ansible Playbook, which is a YAML file integrated in the application source code, deploys the Spring Boot App on to a CentOS machine.
  • Jenkins is our CI/CD process orchestrator. It is responsible to put all the pieces together, resulting in the application successfully deployed in the target machine.
  • To put this infrastructure together, we built an Ansible Playbook using roles from the Ansible Galaxy community. More about this Playbook is discussed further in this article. If you are new to Ansible, check this article about how to get started. Spoiler alert: Ansible Galaxy will be your primary source to learn Ansible.
  • The environment for the virtual machines in this lab was managed by Vagrant with libvirt. Details about how this was done could be seen in the project Vagrant ALM at Github.

Example Pipeline Flow

Now that the tools and the architecture of this lab are well known, let’s explore the CI/CD pipeline flow built for this lab. Note that the purpose of this pipeline is for demonstration only and may lack steps that a real-world CI/CD process might have.

Ansible Playbooks

Let’s dig through the Playbooks used in this lab to get more details about what has been done until now. Ansible played a fundamental role twice in this lab. First, it automated all the infrastructure for this lab, then we used it as a tool to deploy our application through Jenkins pipeline.

Infrastructure provisioning

There’s no secret in here. With a little knowledge about how Ansible works, you could create a lab (or even a production environment) using community Ansible roles like the ones used in this lab to create an ALM excerpt. The mindset behind this process was discussed in my other article: “A developer’s shortcut to getting started with Ansible”, please check it out for a comprehensive review of this process.

---
- name: Deploy Jenkins CI
hosts: jenkins_server
remote_user: vagrant
become: yes

roles:
- geerlingguy.repo-epel
- geerlingguy.jenkins
- geerlingguy.git
- tecris.maven
- geerlingguy.ansible

- name: Deploy Nexus Server
hosts: nexus_server
remote_user: vagrant
become: yes

roles:
- geerlingguy.java
- savoirfairelinux.nexus3-oss

- name: Deploy Sonar Server
hosts: sonar_server
remote_user: vagrant
become: yes

roles:
- wtanaka.unzip
- zanini.sonar

- name: On Premises CentOS
hosts: app_server
remote_user: vagrant
become: yes

roles:
- jenkins-keys-config
- name: Deploy Jenkins CI
hosts: jenkins_server
remote_user: vagrant
become: yes
roles:
- geerlingguy.repo-epel
- geerlingguy.jenkins
- geerlingguy.git
- tecris.maven
- geerlingguy.ansible

Application deployment

The pipeline has been designed to prepare the application binaries, now called “artifact”, and to upload them in Nexus. The artifact can be reached in Nexus by an URL usually called Artifact URL. Ansible is also part of the pipeline and will receive the Artifact URL as the input for deployment. Thus, Ansible will be responsible not only for the deployment but also for the machine provisioning.

---
- name: Install Java
hosts: app_server
become: yes
become_user: root
roles:
- geerlingguy.java
- name: Download Application from Repo
hosts: app_server
tasks:
- get_url:
force: yes
url: "{{ lookup('env','ARTIFACT_URL') }}"
dest: "/tmp/{{ lookup('env','APP_NAME') }}.jar"
- stat:
path: "/tmp/{{ lookup('env','APP_NAME') }}.jar"
- name: Setup Spring Boot
hosts: app_server
become: yes
become_user: root
roles:
- { role: pellepelster.springboot-role,
spring_boot_file: "{{ lookup('env','APP_NAME') }}.jar",
spring_boot_file_source: "/tmp/{{ lookup('env','APP_NAME') }}.jar",
spring_boot_application_id: "{{ lookup('env','APP_NAME') }}"
}
  1. Install Java based on a pre-defined role from Ansible Galaxy
  2. Download the binaries from the Nexus repository based on the input from Jenkins
  3. Set up the application as a Spring boot service again using a role from the community
def artifactUrl = "http://${NEXUS_URL}/repository/ansible-meetup/${repoPath}/${version}/${pom.artifactId}-${version}.jar"withEnv(["ARTIFACT_URL=${artifactUrl}", "APP_NAME=${pom.artifactId}"]) {
echo "The URL is ${env.ARTIFACT_URL} and the app name is ${env.APP_NAME}"
// install galaxy roles
sh "ansible-galaxy install -vvv -r provision/requirements.yml -p provision/roles/"
ansiblePlaybook colorized: true,
credentialsId: 'ssh-jenkins',
limit: "${HOST_PROVISION}",
installation: 'ansible',
inventory: 'provision/inventory.ini',
playbook: 'provision/playbook.yml',
sudo: true,
sudoUser: 'jenkins'
}

Tips and tricks

There are some tips that I would like to share to shorten your way towards using Ansible with Jenkins:

  1. Prepare the target host with the Jenkins user and its SSH keys. The target host could be a pod on Red Hat OpenShift, a Virtual Machine, bare metal, etc. Doesn’t matter. Ansible needs a way to connect to the host to perform its magic.
  2. Set the Jenkins user’s private key on the credentials repository. That way you can easily retrieve it on the pipeline code and send it as a parameter to the Ansible plugin.
  3. Before running the deploy Playbook, consider installing all required roles on the Jenkins server. This could be done by performing a good old shell script run on the requirements file during the pipeline execution: “sh “ansible-galaxy install -vvv -r provision/requirements.yml -p provision/roles/”.
  4. You may face some situations where you need to deploy the application only on a specific host (for a blue-green deployment, for example). You could do this by using the “-limit” parameter on the Ansible Playbook execution.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store