Integrating Ansible with Jenkins: Automating Your CI/CD Pipeline
Integrate Ansible with Jenkins to run playbooks from CI/CD pipelines, manage SSH credentials, and deploy consistently.
Integrating Ansible with Jenkins: Automating Your CI/CD Pipeline
Integrating Ansible with Jenkins lets your CI/CD pipeline build an artifact, run tests, and deploy it with the same playbooks you use outside Jenkins. The main challenge is wiring credentials, inventory, and playbook execution without turning the pipeline into a pile of shell commands.
This guide shows a practical setup: Jenkins orchestrates the pipeline, while Ansible handles deployment and configuration on target hosts. The examples assume SSH-based Linux deployments, but the same pattern works with environment-specific inventories and roles.
How Jenkins and Ansible Fit Together
Before you write the pipeline, separate the responsibilities:
- Jenkins: Checks out code, builds artifacts, runs tests, collects logs, and decides when deployment stages run.
- Ansible: Connects to target hosts, copies artifacts, writes configuration, manages services, and keeps deployment steps idempotent.
Why Integrate Jenkins with Ansible?
This split gives your team a clean boundary:
- Jenkins stores the release flow in a
Jenkinsfile. - Ansible stores infrastructure actions in playbooks and roles.
- Inventory files decide which hosts belong to staging, production, or other environments.
- Jenkins credentials protect SSH keys, Vault passwords, and tokens.
Prerequisites for Integration
Before you begin, make sure you have:
- A working Jenkins controller and at least one agent that can run deployment jobs.
- Ansible installed on the Jenkins agent that runs
ansible-playbook. - Target machines reachable from that agent over SSH.
- A dedicated SSH key pair for automation.
- Application code, inventory, playbooks, and roles in version control.
Setting Up Jenkins for Ansible
Jenkins needs two things before it can run Ansible safely: the Ansible runtime on an agent and credentials for the target hosts.
1. Install the Ansible Plugin
You can call ansible-playbook directly from a shell step, but the Jenkins Ansible plugin can make configuration and output easier to manage.
- Navigate to
Manage Jenkins>Manage Plugins. - Go to the
Availabletab and search for "Ansible". - Select the "Ansible" plugin and click
Install without restartorDownload now and install after restart.
2. Configure SSH Credentials
Ansible will use SSH to connect to target servers. Store the private key in Jenkins credentials rather than in the repository.
- Go to
Manage Jenkins>Manage Credentials. - Select the credentials store used by your jobs.
- Click
Add Credentials. - Choose
SSH Username with private key. - Set a stable ID, such as
ansible-ssh-key. - Enter the SSH username used on target machines.
- Add the private key and save the credential.
Tip: Key Management Best Practices
- Never hardcode SSH private keys in a Jenkinsfile, inventory, or playbook.
- Use dedicated automation keys, not personal keys.
- Rotate keys on a schedule that matches your team's security policy.
Designing Your Jenkins Pipeline with Ansible
Use a Declarative Pipeline in a Jenkinsfile so deployment logic is reviewed with the application code.
Basic Pipeline Structure
Here is a compact example for a build, staging deploy, and gated production deploy:
// Jenkinsfile
pipeline {
agent any
environment {
// Define environment variables if needed
ANSIBLE_HOST_KEY_CHECKING = 'False' // Be cautious in production, prefer known_hosts
}
stages {
stage('Checkout Source') {
steps {
git 'https://your-scm-url/your-repo.git'
}
}
stage('Build Application') {
// This stage might build a JAR, WAR, Docker image, etc.
// Example: build a Spring Boot JAR
steps {
sh 'mvn clean package'
}
}
stage('Run Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('Deploy to Staging') {
steps {
script {
// Use the SSH agent to make the private key available to Ansible
sshagent(credentials: ['ansible-ssh-key']) {
// Execute Ansible playbook
sh 'ansible-playbook -i inventory/staging.ini playbooks/deploy_app.yml \n -e "app_version=$(cat target/VERSION)"'
}
}
}
}
stage('Deploy to Production') {
// This stage might require manual approval
input {
message "Proceed with deployment to Production?"
ok "Deploy to Production"
}
steps {
script {
sshagent(credentials: ['ansible-ssh-key']) {
sh 'ansible-playbook -i inventory/production.ini playbooks/deploy_app.yml \n -e "app_version=$(cat target/VERSION)"'
}
}
}
}
}
post {
always {
echo 'Pipeline finished.'
}
success {
echo 'Pipeline succeeded!'
// slackSend channel: '#deployments', message: "Deployment successful: ${env.BUILD_URL}"
}
failure {
echo 'Pipeline failed!'
// slackSend channel: '#deployments', message: "Deployment failed: ${env.BUILD_URL}"
}
}
}
Key Pipeline Details
agent anyworks for a demo. In production, use an agent label that guarantees Ansible is installed.sshagent(credentials: ['ansible-ssh-key'])exposes the private key only inside that block.ansible-playbook -i inventory/staging.ini playbooks/deploy_app.ymlkeeps the target environment explicit.- The production
inputblock adds a manual gate before a sensitive deployment. - Avoid disabling host key checking in production. Manage
known_hostson the Jenkins agent instead.
Example Ansible Playbook: Deploying a Web Application
Here is a simplified inventory/staging.ini and playbooks/deploy_app.yml for a Java web application. Your artifact name, service manager, and paths may differ.
inventory/staging.ini
[web_servers]
web1.example.com
web2.example.com
[database_servers]
db1.example.com
[all:vars]
ansible_user=ubuntu
playbooks/deploy_app.yml
---
- name: Deploy Web Application
hosts: web_servers
become: yes
vars:
app_name: my-webapp
app_path: /opt/{{ app_name }}
app_port: 8080
app_version: "{{ app_version | default('1.0.0') }}"
tasks:
- name: Ensure application directory exists
ansible.builtin.file:
path: "{{ app_path }}"
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0755'
- name: Copy application JAR to target
ansible.builtin.copy:
src: "target/{{ app_name }}-{{ app_version }}.jar"
dest: "{{ app_path }}/{{ app_name }}.jar"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0644'
notify: restart app service
- name: Ensure systemd service file exists
ansible.builtin.template:
src: templates/my-webapp.service.j2
dest: /etc/systemd/system/{{ app_name }}.service
owner: root
group: root
mode: '0644'
notify: restart app service
- name: Ensure app service is started and enabled
ansible.builtin.systemd:
name: "{{ app_name }}"
state: started
enabled: yes
handlers:
- name: restart app service
ansible.builtin.systemd:
name: "{{ app_name }}"
state: restarted
daemon_reload: yes
templates/my-webapp.service.j2 (Systemd service template)
[Unit]
Description={{ app_name }} Application
After=network.target
[Service]
User={{ ansible_user }}
ExecStart=/usr/bin/java -jar {{ app_path }}/{{ app_name }}.jar --server.port={{ app_port }}
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
This playbook creates the app directory, copies the built JAR, writes a systemd unit, and starts the service. The handler restarts the service only when the artifact or unit file changes.
Best Practices and Tips
- Keep playbooks idempotent so rerunning a failed pipeline does not create extra damage.
- Store Vault passwords in Jenkins credentials and pass them through a temporary password file or approved credential binding.
- Organize deployment logic into roles, such as
webserver,database, andapp_deploy. - Use separate inventories or
group_varsfor staging and production. - Run Ansible on dedicated Jenkins agents, not the controller.
- Use
-vor-vvonly when you need more detail; avoid leaking secrets into logs. - Test playbooks before Jenkins runs them, especially for production roles.
When to See a Professional
Bring in a Jenkins or platform administrator when the pipeline deploys to production, manages shared credentials, writes to many hosts, or needs audit controls. Credential handling, host key verification, and rollback behavior deserve a second review before the first production run.
Takeaway
Use Jenkins for orchestration and Ansible for deployment state. Keep credentials in Jenkins, keep playbooks in version control, make inventory explicit, and test the same Ansible commands outside the pipeline before you automate production deployment.