Intégrer Ansible avec Jenkins : Automatiser votre pipeline CI/CD

Intégrez Ansible avec Jenkins pour exécuter des playbooks depuis des pipelines CI/CD, gérer les identifiants SSH et déployer de manière cohérente.

Intégrer Ansible avec Jenkins : Automatiser votre pipeline CI/CD

Intégrer Ansible avec Jenkins permet à votre pipeline CI/CD de construire un artefact, d'exécuter des tests et de le déployer avec les mêmes playbooks que vous utilisez en dehors de Jenkins. Le principal défi est de connecter les identifiants, l'inventaire et l'exécution des playbooks sans transformer le pipeline en un amas de commandes shell.

Ce guide présente une configuration pratique : Jenkins orchestre le pipeline, tandis qu'Ansible gère le déploiement et la configuration sur les hôtes cibles. Les exemples supposent des déploiements Linux via SSH, mais le même modèle fonctionne avec des inventaires et des rôles spécifiques à l'environnement.

Comment Jenkins et Ansible s'articulent

Avant d'écrire le pipeline, séparez les responsabilités :

  • Jenkins : Récupère le code, construit les artefacts, exécute les tests, collecte les journaux et décide quand les étapes de déploiement sont lancées.
  • Ansible : Se connecte aux hôtes cibles, copie les artefacts, écrit la configuration, gère les services et maintient les étapes de déploiement idempotentes.

Pourquoi intégrer Jenkins avec Ansible ?

Cette séparation offre à votre équipe une limite claire :

  1. Jenkins stocke le flux de livraison dans un Jenkinsfile.
  2. Ansible stocke les actions d'infrastructure dans des playbooks et des rôles.
  3. Les fichiers d'inventaire déterminent quels hôtes appartiennent à la préproduction, à la production ou à d'autres environnements.
  4. Les identifiants Jenkins protègent les clés SSH, les mots de passe Vault et les jetons.

Prérequis pour l'intégration

Avant de commencer, assurez-vous d'avoir :

  • Un contrôleur Jenkins fonctionnel et au moins un agent capable d'exécuter des tâches de déploiement.
  • Ansible installé sur l'agent Jenkins qui exécute ansible-playbook.
  • Des machines cibles accessibles depuis cet agent via SSH.
  • Une paire de clés SSH dédiée à l'automatisation.
  • Le code de l'application, l'inventaire, les playbooks et les rôles dans un système de contrôle de version.

Configuration de Jenkins pour Ansible

Jenkins a besoin de deux choses avant de pouvoir exécuter Ansible en toute sécurité : l'environnement d'exécution Ansible sur un agent et les identifiants pour les hôtes cibles.

1. Installer le plugin Ansible

Vous pouvez appeler ansible-playbook directement depuis une étape shell, mais le plugin Ansible de Jenkins peut faciliter la configuration et la gestion des sorties.

  1. Accédez à Manage Jenkins > Manage Plugins.
  2. Allez dans l'onglet Available et recherchez "Ansible".
  3. Sélectionnez le plugin "Ansible" et cliquez sur Install without restart ou Download now and install after restart.

2. Configurer les identifiants SSH

Ansible utilisera SSH pour se connecter aux serveurs cibles. Stockez la clé privée dans les identifiants Jenkins plutôt que dans le dépôt.

  1. Allez dans Manage Jenkins > Manage Credentials.
  2. Sélectionnez le magasin d'identifiants utilisé par vos tâches.
  3. Cliquez sur Add Credentials.
  4. Choisissez SSH Username with private key.
  5. Définissez un ID stable, par exemple ansible-ssh-key.
  6. Saisissez le nom d'utilisateur SSH utilisé sur les machines cibles.
  7. Ajoutez la clé privée et enregistrez l'identifiant.

Astuce : Bonnes pratiques pour la gestion des clés

  • Ne codez jamais en dur les clés privées SSH dans un Jenkinsfile, un inventaire ou un playbook.
  • Utilisez des clés d'automatisation dédiées, pas des clés personnelles.
  • Renouvelez les clés selon un calendrier correspondant à la politique de sécurité de votre équipe.

Conception de votre pipeline Jenkins avec Ansible

Utilisez un pipeline déclaratif dans un Jenkinsfile afin que la logique de déploiement soit examinée avec le code de l'application.

Structure de base du pipeline

Voici un exemple compact pour une construction, un déploiement en préproduction et un déploiement en production avec validation :

// Jenkinsfile
pipeline {
    agent any

    environment {
        // Définir les variables d'environnement si nécessaire
        ANSIBLE_HOST_KEY_CHECKING = 'False' // Soyez prudent en production, préférez known_hosts
    }

    stages {
        stage('Checkout Source') {
            steps {
                git 'https://your-scm-url/your-repo.git'
            }
        }

        stage('Build Application') {
            // Cette étape peut construire un JAR, WAR, image Docker, etc.
            // Exemple : construire un JAR Spring Boot
            steps {
                sh 'mvn clean package'
            }
        }

        stage('Run Unit Tests') {
            steps {
                sh 'mvn test'
            }
        }

        stage('Deploy to Staging') {
            steps {
                script {
                    // Utiliser l'agent SSH pour rendre la clé privée disponible à Ansible
                    sshagent(credentials: ['ansible-ssh-key']) {
                        // Exécuter le playbook Ansible
                        sh 'ansible-playbook -i inventory/staging.ini playbooks/deploy_app.yml \n                            -e "app_version=$(cat target/VERSION)"'
                    }
                }
            }
        }

        stage('Deploy to Production') {
            // Cette étape peut nécessiter une approbation manuelle
            input {
                message "Procéder au déploiement en Production ?"
                ok "Déployer en 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 terminé.'
        }
        success {
            echo 'Pipeline réussi !'
            // slackSend channel: '#deployments', message: "Déploiement réussi : ${env.BUILD_URL}"
        }
        failure {
            echo 'Pipeline échoué !'
            // slackSend channel: '#deployments', message: "Déploiement échoué : ${env.BUILD_URL}"
        }
    }
}

Détails clés du pipeline

  • agent any fonctionne pour une démonstration. En production, utilisez un label d'agent garantissant qu'Ansible est installé.
  • sshagent(credentials: ['ansible-ssh-key']) expose la clé privée uniquement à l'intérieur de ce bloc.
  • ansible-playbook -i inventory/staging.ini playbooks/deploy_app.yml rend l'environnement cible explicite.
  • Le bloc input de production ajoute une validation manuelle avant un déploiement sensible.
  • Évitez de désactiver la vérification de la clé d'hôte en production. Gérez plutôt known_hosts sur l'agent Jenkins.

Exemple de playbook Ansible : Déploiement d'une application web

Voici un inventory/staging.ini et un playbooks/deploy_app.yml simplifiés pour une application web Java. Le nom de votre artefact, votre gestionnaire de services et vos chemins peuvent différer.

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: Déployer l'application 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: S'assurer que le répertoire de l'application existe
      ansible.builtin.file:
        path: "{{ app_path }}"
        state: directory
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
        mode: '0755'

    - name: Copier le JAR de l'application vers la cible
      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: redémarrer le service de l'application

    - name: S'assurer que le fichier de service systemd existe
      ansible.builtin.template:
        src: templates/my-webapp.service.j2
        dest: /etc/systemd/system/{{ app_name }}.service
        owner: root
        group: root
        mode: '0644'
      notify: redémarrer le service de l'application

    - name: S'assurer que le service de l'application est démarré et activé
      ansible.builtin.systemd:
        name: "{{ app_name }}"
        state: started
        enabled: yes

  handlers:
    - name: redémarrer le service de l'application
      ansible.builtin.systemd:
        name: "{{ app_name }}"
        state: restarted
        daemon_reload: yes

templates/my-webapp.service.j2 (Modèle de service systemd)

[Unit]
Description=Application {{ app_name }}
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

Ce playbook crée le répertoire de l'application, copie le JAR construit, écrit une unité systemd et démarre le service. Le gestionnaire redémarre le service uniquement lorsque l'artefact ou le fichier d'unité change.

Bonnes pratiques et conseils

  • Maintenez les playbooks idempotents afin que la réexécution d'un pipeline échoué ne cause pas de dommages supplémentaires.
  • Stockez les mots de passe Vault dans les identifiants Jenkins et transmettez-les via un fichier de mot de passe temporaire ou une liaison d'identifiants approuvée.
  • Organisez la logique de déploiement en rôles, comme webserver, database et app_deploy.
  • Utilisez des inventaires séparés ou des group_vars pour la préproduction et la production.
  • Exécutez Ansible sur des agents Jenkins dédiés, pas sur le contrôleur.
  • Utilisez -v ou -vv uniquement lorsque vous avez besoin de plus de détails ; évitez de divulguer des secrets dans les journaux.
  • Testez les playbooks avant que Jenkins ne les exécute, en particulier pour les rôles de production.

Quand faire appel à un professionnel

Faites appel à un administrateur Jenkins ou de plateforme lorsque le pipeline déploie en production, gère des identifiants partagés, écrit sur de nombreux hôtes ou nécessite des contrôles d'audit. La gestion des identifiants, la vérification de la clé d'hôte et le comportement de restauration méritent une seconde vérification avant le premier déploiement en production.

À retenir

Utilisez Jenkins pour l'orchestration et Ansible pour l'état du déploiement. Conservez les identifiants dans Jenkins, les playbooks dans le contrôle de version, rendez l'inventaire explicite et testez les mêmes commandes Ansible en dehors du pipeline avant d'automatiser le déploiement en production.