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
- Documentation : docs.ansible.com
- Galaxy : galaxy.ansible.com
- Community : forum.ansible.com