"Ansible Automation for CI/CD: Seamless SonarQube Integration and Deployment Solutions"
The Ansible project workflow involves setting up three EC2 instances of type t2.medium
, establishing SSH connectivity with keys, and installing Ansible on the master VM. An Ansible playbook is then created to automate the installation of JDK 17, Java, Maven, Docker, SonarQube, and Trivy. The CI/CD pipeline includes cloning the repository, pulling the latest updates, and performing code compilation, testing, and SonarQube analysis. Environment variables are securely managed using Ansible Vault. The application is built into a JAR file, and Docker management involves building and tagging the Docker image, scanning it with Trivy, and pushing it to Docker Hub.
Deployment is managed through Docker containers. Updates are controlled by the docker-container-condition.sh
script, which ensures that the deployment always uses the latest Docker image named secret-santa
. When changes occur in the source code, Ansible triggers the script to check for updates. The script then stops the existing Docker container, creates a new image reflecting the latest changes, and redeploys the updated container. In real-time projects, Docker volumes are commonly used to persist and safeguard data. However, for this demo project, Docker volumes are not utilized.
SSH Key Configuration (Master):
# sudo apt update
# ssh-keygen
# cd /home/ubuntu/.ssh
# cat id_rsa.pub (paste the public key to target servers)
# ssh-keyscan -H <target-1 IP> >> ~/.ssh/known_hosts
# ssh-keyscan -H <target-2 iP> >> ~/.ssh/known_hosts
SSH Connection Setup for Target Servers:
# cd /home/ubuntu/.ssh
# vi authorized_keys
# chmod 700 ~/.ssh
# chmod 600 ~/.ssh/authorized_keys
After setting up SSH keys for target servers, the next step is to configure Ansible on the master node. Here’s a detailed guide for configuring Ansible on the master node:
Configuring Ansible on the Master:
# mkdir shazia
# cd shazia
# ansible
# sudo apt install ansible
# ansible --version
Here’s a sample Ansible playbook YAML file designed to install JDK 17, Java, Maven, Docker, SonarQube, and Trivy on a Debian-based system (such as Ubuntu). The playbook starts by updating the package index to ensure the latest package information is available. It then uses apt
to install JDK, Maven, and Docker, adds Docker’s official GPG key and repository to get the latest Docker version, and installs Docker Compose by downloading and installing it. Next, it downloads, unzips, and sets up SonarQube in the /opt
directory and installs Trivy using a .deb
package. Finally, the playbook performs cleanup by removing temporary files created during the installation. Adjust paths and versions as needed for your specific environment and requirements.
Installing Tools Using YML:
# vi install-tools.yml
---
- name: Install Java, Docker, SonarQube, and Trivy
hosts: all
become: yes
tasks:
- name: update repo
command: sudo apt update
- name: Install OpenJDK 17
apt:
name: openjdk-17-jre-headless
state: present
- name: Install Maven
apt:
name: maven
state: present
- name: Install Docker
apt:
name: docker.io
state: present
- name: Set permissions for Docker socket
command: chmod 666 /var/run/docker.sock
become: true
- name: Run SonarQube container
command: docker run -d -p 9000:9000 sonarqube:lts-community
become: true
- name: Install dependencies for Trivy
apt:
name: "{{ item }}"
state: present
loop:
- wget
- apt-transport-https
- gnupg
- lsb-release
- name: Add GPG key for Trivy
shell: wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
become: true
- name: Add Trivy repository
shell: echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
become: true
- name: Update apt cache
apt:
update_cache: yes
- name: Install Trivy
apt:
name: trivy
state: present
- name: Download SonarScanner
get_url:
url: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.0.2856-linux.zip
dest: /tmp/sonar-scanner-cli-4.8.0.2856-linux.zip
- name: Install unzip
apt:
name: unzip
state: present
- name: Unzip SonarScanner
unarchive:
src: /tmp/sonar-scanner-cli-4.8.0.2856-linux.zip
dest: /home/ubuntu/
remote_src: yes
creates: /home/ubuntu/sonar-scanner-4.8.0.2856-linux
Configuring the Ansible Inventory:
By default, Ansible uses /etc/ansible/hosts
for the inventory file. We can use this file or create a custom inventory file. To create a custom inventory file, you can place it anywhere on the master node, for example, /home/ubuntu/inventory
# vi inventory
[web]
< target-1 IP >
< target-2 IP >
Now, run the Ansible playbook using the following command:
# ansible-playbook -i inventory install-tools.yml
The docker-container-condition.sh
script manages Docker containers based on specific conditions. In this project, it ensures that the deployment uses the latest Docker image by performing the following actions: it stops the existing container, creates a new Docker image if there are updates to the source code, and redeploys the container with the updated image.
# vi docker-container-condition.sh
#!/bin/bash
# Define the name of the Docker container
container_name="secret-santa"
# Check if the Docker container exists
if docker ps -a --format '{{.Names}}' | grep -q "^$container_name$"; then
# Stop the Docker container
echo "Stopping Docker container $container_name..."
docker stop $container_name
# Remove the Docker container
echo "Removing Docker container $container_name..."
docker rm $container_name
else
echo "Docker container $container_name does not exist."
fi
To access SonarQube, enter the IP address of the target server followed by port 9000 in your browser. After logging in to SonarQube, navigate to Administration, select Security, and then click Generate Tokens to create a new authentication token. This token is essential for integrating SonarQube with Ansible Vault and for configuring credentials.yml
.
We utilize Ansible Vault to securely manage environment variables, including Docker credentials (username and password), SonarQube URL, and token. This approach ensures that sensitive information is encrypted and protected, providing a secure method for handling configuration details required for deployment and integration.
# ansible-vault create credentials.yml
We configure the cicd.yaml
file to define the Continuous Integration and Continuous Deployment (CI/CD) pipeline. This configuration includes specifying stages for building, testing, code analysis, and deployment. It integrates various tools and processes to automate the workflow, ensuring efficient and reliable software delivery.
# vi cicd.yaml
---
- name: Clone or pull repository, build with Maven, and run SonarQube scanner
hosts: all
become: yes
vars:
repository_url: https://github.com/shazia-massey/secretsanta-generator.git
vars_files:
- credentials.yml
tasks:
- name: Clone or pull repository
ansible.builtin.git:
repo: "{{ repository_url }}"
dest: /home/ubuntu/secretsanta-generator
update: yes
register: git_result
- name: Check if repository was cloned or updated
debug:
msg: "{{ git_result }}"
- name: Copy shell script to remote server
copy:
src: docker-container-condition.sh
dest: /home/ubuntu/secretsanta-generator/docker-container-condition.sh
- name: Permissions on shell script
command: chmod +x docker-container-condition.sh
args:
chdir: /home/ubuntu/secretsanta-generator
- name: Execute shell script
command: ./docker-container-condition.sh
args:
chdir: /home/ubuntu/secretsanta-generator
- name: Run mvn compile
command: mvn compile
args:
chdir: /home/ubuntu/secretsanta-generator
- name: Run mvn Test
command: mvn test
args:
chdir: /home/ubuntu/secretsanta-generator
- name: Execute SonarScanner
ansible.builtin.command:
_raw_params: >
/home/ubuntu/sonar-scanner-4.8.0.2856-linux/bin/sonar-scanner
-Dsonar.host.url={{ SONARQUBE_URL }}
-Dsonar.login={{ SONARQUBE_TOKEN }}
-Dsonar.projectKey=Santa
-Dsonar.projectName=Santa
-Dsonar.java.binaries=.
chdir: /home/ubuntu/secretsanta-generator
- name: Run mvn build
command: mvn package
args:
chdir: /home/ubuntu/secretsanta-generator
- name: Build & Tag Docker Image
command: docker build -t masseys/santa:latest .
args:
chdir: /home/ubuntu/secretsanta-generator
- name: Scan Docker Image
command: trivy image --format table -o trivy-image-report.html
masseys/santa:latest
- name: Log in to Docker registry
command: docker login -u {{ docker_username }} -p {{ docker_password }}
- name: Push Docker Image
command: docker push masseys/santa:latest
- name: Deploy To Container
command: docker run -d --name secret-santa -p 8080:8080 masseys/santa:latest
# ansible-playbook -i inventory cicd.yaml --ask-vault-pass
From this project, I acquired expertise in using Ansible for automation, optimizing development workflows, managing Docker containers, and implementing effective credential security practices.
Subscribe to my newsletter
Read articles from Shazia Massey directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by