Ansible

Automatisez votre infrastructure

Killian & pi

Les problèmes

Je veux modifier un paramètre dans la config ssh.


              PasswordAuthentication yes
              PermitRootLogin yes
              PrintMotd no
            

Les problèmes

Je veux modifier un paramètre dans la config ssh.


              PasswordAuthentication yes
              PermitRootLogin no
              PrintMotd no
            

Les problèmes

Je veux modifier un paramètre dans la config ssh.


              PasswordAuthentication yes
              PermitRootLogin no
              PrintMotd no
            
bash — me@bastion

                $ vim /etc/ssh/sshd_config/config
                $ ssh me@server1
                $ ssh me@server2
                ... (imaginez avec une centaine de serveurs !)
              

Les problèmes

Je veux re-déployer la même chose que sur un autre serveur.

  • Lire la doc
  • Regarder ce qu'on avait fait
  • Copier / coller des choses ?

Et si je veux avoir de légères différences ?

Ce qu'il faut

  • Un moyen de toucher plusieurs serveurs en même temps
  • Un moyen de reproduire sans erreur des procédures
  • Un outil simple et modulaire

Les solutions !

  • Ansible
  • NixOS
  • pyinfra
  • terraform
  • puppet, chef...

Ansible

  • Mature
  • Agentless
  • Utilise SSH (entre autres !)
  • Riche (communautaire)
  • Open source !

Présentation rapide

Installation

bash — localhost

                $ python3 -m venv venv
                $ source venv/bin/activate
                $ pip install ansible
                ...
                Successfully installed MarkupSafe-3.0.3 PyYAML-6.0.3 ansible-13.3.0 ansible-core-2.20.2 cffi-2.0.0 cryptography-46.0.5 jinja2-3.1.6 packaging-26.0 pycparser-3.0 resolvelib-1.2.1
              

Exemple

bash — localhost

                $ ansible -m ansible.builtin.ping all
                ansible2 | SUCCESS => {
                  "changed": false,
                  "ping": "pong"
                }
                ansible1 | SUCCESS => {
                    "changed": false,
                    "ping": "pong"
                }
              

Exemple

bash — localhost

                $ ansible-playbook playbooks/ping.yaml
                PLAY [all] ****************************************************
                
                TASK [Ping to test connectivity] ******************************
                ok: [ansible1]
                ok: [ansible2]
                
                PLAY RECAP ***************************************************
                ansible1 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
                ansible2 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
              

Ok, mais il s'est passé quoi, là ?

Exemple

Regardons le fichier playbooks/ping.yaml

On peut constater que c'est du yaml


              - hosts: all
                tasks:
                  - name: Ping to test connectivity
                    ansible.builtin.ping:
            

Pour vous aider à comprendre le yaml, voici ce que donnerait exactement la même configuration en JSON


                [{
                    "hosts": "all",
                    "tasks": [
                      {"name": "Ping to test connectivity",
                       "ansible.builtin.ping": null}
                    ]
                }]
              

En détail


                  - hosts: all
                    tasks:
                      - name: Ping to test connectivity
                        ansible.builtin.ping:
                
bash — localhost

                    $ ansible-playbook playbooks/ping.yaml
                    PLAY [all] *******************************************
                    
                    TASK [Ping to test connectivity] *********************
                    ok: [ansible1]
                    ok: [ansible2]
                    
                    PLAY RECAP ******************************************
                    ansible1 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
                    ansible2 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
                  

Les différentes parties de Ansible

  • Playbooks
  • Modules
  • Inventaire
  • Jinja2
  • Autres (roles, plugins, collections...)

Playbooks

C'est juste un fichier `yaml` avec une liste de choses à exécuter !

Mais quoi exécuter ?

Tâches


               - name: Ping to test connectivity
                 ansible.builtin.ping:
               - name: Install SSSD
                 register: result
                 ansible.builtin.apt:
                   name: sssd
                   state: present
               - name: Copy config
                 if: "some condition..."
                 ansible.builtin.copy:
                   src: ./sssd.conf
                   dest: /etc/sssd/sssd.conf
                   owner: root
                   group: root
                   mode: "0600"
            
  • Mots-clefs relatif aux tâches : ici
  • Modules disponibles : ici

Modules


                  - name: Copy config
                    if: "some condition..."
                    ansible.builtin.copy:
                      src: ./sssd.conf
                      dest: /etc/sssd/sssd.conf
                      owner: root
                      group: root
                      mode: "0600"
                

Modules


                  - name: Copy config
                    if: "some condition..."
                    ansible.builtin.copy:
                      src: ./sssd.conf
                      dest: /etc/sssd/sssd.conf
                      owner: root
                      group: root
                      mode: "0600"
                

Ça peut être équivalent à faire ça:

bash — localhost

                      $ scp ./sssd.conf user@remote:/etc/sssd/sssd.conf
                      $ chown root:root /etc/sssd/sssd.conf
                      $ chmod "0600" /etc/sssd/sssd.conf
                    

C'est ansible qui execute les actions, nous on ne dit que ce que l'on souhaite !

Modules

Les modules essayent d'être idempotents !

C'est à dire que demander 2 fois la même action ne l'exécutera qu'une fois.

bash — localhost

                $ ansible-playbook playbooks/copy_task.yaml
                ...
                TASK [Copy config] ********************************************
                changed: [ansible1]
                changed: [ansible2]
                ...

                $ ansible-playbook playbooks/copy_task.yaml
                ...
                TASK [Copy config] ********************************************
                ok: [ansible1]
                ok: [ansible2]
                ...
              

Quelques modules utiles

TODO: mettre des plugins utiles...

L'inventaire

A quoi correspond hosts: all ?

L'inventaire

Pour ça, il suffit de regarder un fichier d'inventaire.

Par exemple, inventory.yaml:


              production:
                hosts:
                  gitlabint.minet.lan:
                children:
                  dns_servers:
                    hosts:
                      ns1.minet.lan:
                      ns2.minet.lan:
            

L'inventaire

Pour ça, il suffit de regarder un fichier d'inventaire.

Par exemple, inventory.yaml:


              production:
                vars:
                  ansible_user: airopi
                hosts:
                  gitlabint.minet.lan:
                children:
                  dns_servers:
                    hosts:
                      ns1.minet.lan:
                      ns2.minet.lan:
                        ansible_user: root
            

Pour plus d'infos, référez-vous à la documentation.

Jinja2


              production:
                hosts:
                  ansible1:
                    ansible_host: 172.31.0.22
                    my_variable: "foo"
                  ansible2:
                    ansible_host: 172.31.0.23
                    my_variable: "bar"
            

Jinja2


              production:
                hosts:
                  ansible1:
                    ansible_host: 172.31.0.22
                    my_variable: "foo"
                  ansible2:
                    ansible_host: 172.31.0.23
                    my_variable: "bar"
            

On créer un playbook simple:


              - hosts: all
                tasks:
                  - name: "Create file with content"
                    content: "{{ my_variable }}"
                    dest: "/root/my_file.txt"
            
bash — localhost

                $ ssh root@172.31.0.22 cat /root/my_file.txt
                foo
                $ ssh root@172.31.0.23 cat /root/my_file.txt
                bar
              

Et tant d'autres choses à découvrir...