Integrazione di Ansible con Jenkins: Automatizzare la pipeline CI/CD
Integra Ansible con Jenkins per eseguire playbook da pipeline CI/CD, gestire credenziali SSH e distribuire in modo coerente.
Integrazione di Ansible con Jenkins: Automatizzare la tua pipeline CI/CD
Integrare Ansible con Jenkins permette alla tua pipeline CI/CD di creare un artefatto, eseguire test e distribuirlo con gli stessi playbook che usi al di fuori di Jenkins. La sfida principale è collegare credenziali, inventario ed esecuzione dei playbook senza trasformare la pipeline in un ammasso di comandi shell.
Questa guida mostra una configurazione pratica: Jenkins orchestra la pipeline, mentre Ansible gestisce la distribuzione e la configurazione sugli host di destinazione. Gli esempi presuppongono distribuzioni Linux basate su SSH, ma lo stesso schema funziona con inventari e ruoli specifici per ambiente.
Come si integrano Jenkins e Ansible
Prima di scrivere la pipeline, separa le responsabilità:
- Jenkins: Fa il checkout del codice, crea artefatti, esegue test, raccoglie log e decide quando eseguire le fasi di distribuzione.
- Ansible: Si connette agli host di destinazione, copia artefatti, scrive configurazioni, gestisce servizi e mantiene idempotenti i passaggi di distribuzione.
Perché integrare Jenkins con Ansible?
Questa suddivisione offre al tuo team un confine netto:
- Jenkins memorizza il flusso di rilascio in un
Jenkinsfile. - Ansible memorizza le azioni infrastrutturali in playbook e ruoli.
- I file di inventario decidono quali host appartengono a staging, produzione o altri ambienti.
- Le credenziali di Jenkins proteggono chiavi SSH, password Vault e token.
Prerequisiti per l'integrazione
Prima di iniziare, assicurati di avere:
- Un controller Jenkins funzionante e almeno un agente in grado di eseguire lavori di distribuzione.
- Ansible installato sull'agente Jenkins che esegue
ansible-playbook. - Macchine di destinazione raggiungibili da quell'agente tramite SSH.
- Una coppia di chiavi SSH dedicata per l'automazione.
- Codice applicativo, inventario, playbook e ruoli in un sistema di controllo versione.
Configurazione di Jenkins per Ansible
Jenkins necessita di due cose prima di poter eseguire Ansible in sicurezza: il runtime Ansible su un agente e le credenziali per gli host di destinazione.
1. Installare il plugin Ansible
Puoi chiamare ansible-playbook direttamente da un passaggio shell, ma il plugin Ansible di Jenkins può semplificare la gestione della configurazione e dell'output.
- Vai su
Gestisci Jenkins>Gestisci Plugin. - Vai alla scheda
Disponibilie cerca "Ansible". - Seleziona il plugin "Ansible" e clicca
Installa senza riavviooScarica ora e installa dopo il riavvio.
2. Configurare le credenziali SSH
Ansible utilizzerà SSH per connettersi ai server di destinazione. Memorizza la chiave privata nelle credenziali di Jenkins anziché nel repository.
- Vai su
Gestisci Jenkins>Gestisci Credenziali. - Seleziona il repository di credenziali utilizzato dai tuoi lavori.
- Clicca
Aggiungi Credenziali. - Scegli
Nome utente SSH con chiave privata. - Imposta un ID stabile, ad esempio
ansible-ssh-key. - Inserisci il nome utente SSH utilizzato sulle macchine di destinazione.
- Aggiungi la chiave privata e salva la credenziale.
Suggerimento: Buone pratiche per la gestione delle chiavi
- Non codificare mai le chiavi private SSH in un Jenkinsfile, inventario o playbook.
- Utilizza chiavi di automazione dedicate, non chiavi personali.
- Ruota le chiavi secondo una pianificazione che corrisponda alla politica di sicurezza del tuo team.
Progettare la pipeline Jenkins con Ansible
Utilizza una Pipeline Dichiarativa in un Jenkinsfile in modo che la logica di distribuzione venga revisionata insieme al codice dell'applicazione.
Struttura base della pipeline
Ecco un esempio compatto per una build, distribuzione su staging e distribuzione su produzione con approvazione:
// Jenkinsfile
pipeline {
agent any
environment {
// Definisci le variabili d'ambiente se necessario
ANSIBLE_HOST_KEY_CHECKING = 'False' // Attenzione in produzione, preferisci known_hosts
}
stages {
stage('Checkout Sorgente') {
steps {
git 'https://tuo-scm-url/tuo-repo.git'
}
}
stage('Build Applicazione') {
// Questa fase potrebbe creare un JAR, WAR, immagine Docker, ecc.
// Esempio: crea un JAR Spring Boot
steps {
sh 'mvn clean package'
}
}
stage('Esegui Test Unitari') {
steps {
sh 'mvn test'
}
}
stage('Distribuisci su Staging') {
steps {
script {
// Utilizza l'agente SSH per rendere disponibile la chiave privata ad Ansible
sshagent(credentials: ['ansible-ssh-key']) {
// Esegui il playbook Ansible
sh 'ansible-playbook -i inventory/staging.ini playbooks/deploy_app.yml \n -e "app_version=$(cat target/VERSION)"'
}
}
}
}
stage('Distribuisci su Produzione') {
// Questa fase potrebbe richiedere approvazione manuale
input {
message "Procedere con la distribuzione in Produzione?"
ok "Distribuisci in Produzione"
}
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 terminata.'
}
success {
echo 'Pipeline completata con successo!'
// slackSend channel: '#deployments', message: "Distribuzione riuscita: ${env.BUILD_URL}"
}
failure {
echo 'Pipeline fallita!'
// slackSend channel: '#deployments', message: "Distribuzione fallita: ${env.BUILD_URL}"
}
}
}
Dettagli chiave della pipeline
agent anyfunziona per una demo. In produzione, utilizza un'etichetta agente che garantisca l'installazione di Ansible.sshagent(credentials: ['ansible-ssh-key'])espone la chiave privata solo all'interno di quel blocco.ansible-playbook -i inventory/staging.ini playbooks/deploy_app.ymlmantiene esplicito l'ambiente di destinazione.- Il blocco
inputper la produzione aggiunge un gate manuale prima di una distribuzione sensibile. - Evita di disabilitare il controllo della chiave host in produzione. Gestisci invece
known_hostssull'agente Jenkins.
Esempio di playbook Ansible: Distribuzione di un'applicazione web
Ecco un inventory/staging.ini e playbooks/deploy_app.yml semplificati per un'applicazione web Java. Il nome dell'artefatto, il gestore dei servizi e i percorsi potrebbero differire.
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: Distribuisci Applicazione Web
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: Assicura che la directory dell'applicazione esista
ansible.builtin.file:
path: "{{ app_path }}"
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0755'
- name: Copia il JAR dell'applicazione sulla destinazione
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: riavvia servizio app
- name: Assicura che il file del servizio systemd esista
ansible.builtin.template:
src: templates/my-webapp.service.j2
dest: /etc/systemd/system/{{ app_name }}.service
owner: root
group: root
mode: '0644'
notify: riavvia servizio app
- name: Assicura che il servizio app sia avviato e abilitato
ansible.builtin.systemd:
name: "{{ app_name }}"
state: started
enabled: yes
handlers:
- name: riavvia servizio app
ansible.builtin.systemd:
name: "{{ app_name }}"
state: restarted
daemon_reload: yes
templates/my-webapp.service.j2 (Template del servizio Systemd)
[Unit]
Description={{ app_name }} Applicazione
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
Questo playbook crea la directory dell'app, copia il JAR creato, scrive un'unità systemd e avvia il servizio. Il handler riavvia il servizio solo quando l'artefatto o il file dell'unità cambiano.
Buone pratiche e suggerimenti
- Mantieni i playbook idempotenti in modo che rieseguire una pipeline fallita non crei danni aggiuntivi.
- Memorizza le password Vault nelle credenziali di Jenkins e passale tramite un file password temporaneo o un binding di credenziali approvato.
- Organizza la logica di distribuzione in ruoli, come
webserver,databaseeapp_deploy. - Utilizza inventari separati o
group_varsper staging e produzione. - Esegui Ansible su agenti Jenkins dedicati, non sul controller.
- Usa
-vo-vvsolo quando hai bisogno di maggiori dettagli; evita di far trapelare segreti nei log. - Testa i playbook prima che Jenkins li esegua, specialmente per i ruoli di produzione.
Quando consultare un professionista
Coinvolgi un amministratore Jenkins o di piattaforma quando la pipeline distribuisce in produzione, gestisce credenziali condivise, scrive su molti host o necessita di controlli di audit. La gestione delle credenziali, la verifica della chiave host e il comportamento di rollback meritano una seconda revisione prima della prima esecuzione in produzione.
Conclusione
Usa Jenkins per l'orchestrazione e Ansible per lo stato della distribuzione. Mantieni le credenziali in Jenkins, i playbook nel controllo versione, rendi l'inventario esplicito e testa gli stessi comandi Ansible al di fuori della pipeline prima di automatizzare la distribuzione in produzione.