Skip to content

Ansible

Vue d'ensemble

Ansible est une plateforme d'automatisation open-source qui simplifie l'orchestration, la gestion de configuration et le déploiement d'applications. Sans agent et déclaratif, il utilise SSH pour communiquer avec les systèmes cibles.

Philosophie

"Simple, agentless automation - Automatisez tout ce qui peut l'être, de manière simple et reproductible."

Avantages clés

Sans agent (Agentless)

  • SSH natif : Pas d'installation sur les cibles
  • Push model : Contrôle centralisé
  • Sécurité : Utilise l'infrastructure SSH existante
  • Simplicité : Déploiement immédiat

Déclaratif et idempotent

  • YAML : Syntaxe lisible et simple
  • Idempotence : Exécutions multiples sûres
  • État désiré : Décrit le résultat final
  • Reproductible : Résultats identiques

Écosystème riche

  • Modules : 3000+ modules intégrés
  • Collections : Packages réutilisables
  • Galaxy : Partage communautaire
  • AWX/Tower : Interface graphique

Architecture

Composants principaux

  • Control Node : Machine exécutant Ansible
  • Managed Nodes : Serveurs cibles
  • Inventory : Liste des hôtes
  • Playbooks : Scripts d'automatisation
  • Modules : Unités d'exécution

Structure projet typique

ansible-project/
├── inventories/
│   ├── production/
│   │   ├── hosts.yml
│   │   └── group_vars/
│   └── staging/
├── playbooks/
├── roles/
├── collections/
└── ansible.cfg

Configuration

Inventory exemple

# inventories/production/hosts.yml
all:
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
      vars:
        http_port: 80
        max_clients: 200

    databases:
      hosts:
        db1.example.com:
        db2.example.com:
      vars:
        mysql_port: 3306
        mysql_root_password: "{{ vault_mysql_password }}"

    nomad_cluster:
      hosts:
        nomad1.example.com:
        nomad2.example.com:
        nomad3.example.com:
      vars:
        nomad_datacenter: dc1

Playbook exemple

# playbooks/webserver.yml
---
- name: Configure web servers
  hosts: webservers
  become: yes
  vars:
    packages:
      - nginx
      - certbot
      - python3-certbot-nginx

  tasks:
    - name: Install packages
      package:
        name: "{{ packages }}"
        state: present

    - name: Start and enable nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

    - name: Configure nginx virtual hosts
      template:
        src: nginx-vhost.j2
        dest: "/etc/nginx/sites-available/{{ inventory_hostname }}"
        backup: yes
      notify: reload nginx

    - name: Enable virtual host
      file:
        src: "/etc/nginx/sites-available/{{ inventory_hostname }}"
        dest: "/etc/nginx/sites-enabled/{{ inventory_hostname }}"
        state: link
      notify: reload nginx

  handlers:
    - name: reload nginx
      systemd:
        name: nginx
        state: reloaded

Rôles (Roles)

Structure d'un rôle

roles/nginx/
├── tasks/main.yml
├── handlers/main.yml
├── templates/
│   └── nginx.conf.j2
├── files/
├── vars/main.yml
├── defaults/main.yml
└── meta/main.yml

Exemple de rôle

# roles/nginx/tasks/main.yml
---
- name: Install nginx
  package:
    name: nginx
    state: present

- name: Configure nginx
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    backup: yes
  notify: restart nginx

- name: Ensure nginx is running
  systemd:
    name: nginx
    state: started
    enabled: yes

Intégrations

Avec Terraform

# Playbook utilisant des outputs Terraform
- name: Configure infrastructure provisioned by Terraform
  hosts: "{{ terraform_inventory }}"
  vars:
    terraform_state: "{{ lookup('file', 'terraform.tfstate') | from_json }}"
    database_endpoint: "{{ terraform_state.outputs.database_endpoint.value }}"

  tasks:
    - name: Configure application with database endpoint
      template:
        src: app-config.j2
        dest: /etc/app/config.yml
      vars:
        db_host: "{{ database_endpoint }}"

Avec Vault

# Récupération secrets depuis Vault
- name: Deploy application with Vault secrets
  hosts: appservers
  vars:
    vault_addr: "https://vault.example.com:8200"

  tasks:
    - name: Get database credentials from Vault
      uri:
        url: "{{ vault_addr }}/v1/secret/data/database"
        headers:
          X-Vault-Token: "{{ vault_token }}"
      register: vault_response

    - name: Configure application
      template:
        src: app.conf.j2
        dest: /etc/app/app.conf
      vars:
        db_password: "{{ vault_response.json.data.data.password }}"
      no_log: true

Avec GitLab CI

# .gitlab-ci.yml
stages:
  - deploy

deploy_infrastructure:
  stage: deploy
  image: quay.io/ansible/ansible-runner:latest
  before_script:
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - echo "$VAULT_TOKEN" > .vault_token
  script:
    - ansible-playbook -i inventories/production playbooks/site.yml
  only:
    - main

Collections Ansible

Installation collections

# requirements.yml
collections:
  - community.general
  - ansible.posix
  - community.crypto
  - kubernetes.core

# Installation
ansible-galaxy collection install -r requirements.yml

Utilisation collections

- name: Manage Kubernetes resources
  kubernetes.core.k8s:
    name: myapp
    api_version: apps/v1
    kind: Deployment
    namespace: production
    definition:
      spec:
        replicas: 3

Cas d'usage avancés

Configuration Nomad cluster

- name: Setup Nomad cluster
  hosts: nomad_servers
  become: yes

  tasks:
    - name: Install Nomad
      unarchive:
        src: "https://releases.hashicorp.com/nomad/{{ nomad_version }}/nomad_{{ nomad_version }}_linux_amd64.zip"
        dest: /usr/local/bin
        remote_src: yes
        creates: /usr/local/bin/nomad

    - name: Configure Nomad server
      template:
        src: nomad-server.hcl.j2
        dest: /etc/nomad.d/nomad.hcl
      notify: restart nomad

    - name: Start Nomad service
      systemd:
        name: nomad
        state: started
        enabled: yes

Déploiement application Laravel

- name: Deploy Laravel application
  hosts: webservers

  tasks:
    - name: Clone application repository
      git:
        repo: "{{ app_repository }}"
        dest: "{{ app_path }}"
        version: "{{ app_version }}"
      notify: 
        - install dependencies
        - run migrations

    - name: Set application permissions
      file:
        path: "{{ item }}"
        owner: www-data
        group: www-data
        mode: '0755'
        recurse: yes
      loop:
        - "{{ app_path }}/storage"
        - "{{ app_path }}/bootstrap/cache"

  handlers:
    - name: install dependencies
      composer:
        command: install
        working_dir: "{{ app_path }}"
        no_dev: yes

    - name: run migrations
      command: php artisan migrate --force
      args:
        chdir: "{{ app_path }}"

Monitoring avec Prometheus

- name: Configure Prometheus monitoring
  hosts: monitoring

  tasks:
    - name: Generate Prometheus configuration
      template:
        src: prometheus.yml.j2
        dest: /etc/prometheus/prometheus.yml
      vars:
        scrape_configs:
          - job_name: 'ansible-managed-nodes'
            static_configs:
              - targets: "{{ groups['all'] | map('extract', hostvars, 'ansible_default_ipv4') | map(attribute='address') | list }}"

Bonnes pratiques

Structure et organisation

  • Rôles modulaires : Responsabilité unique
  • Variables hierarchiques : group_vars, host_vars
  • Secrets chiffrés : Ansible Vault
  • Tests : Molecule pour validation

Performance

  • Parallelism : Ajuster forks
  • Facts caching : Redis ou fichiers
  • Optimisations SSH : ControlMaster, pipelining

Ressources