# ansible <!-- .element width="30%" --> ## ansible * outil de * provisioning * gestion de config * déploiemenet d'application * racheté par RedHat en octobre 2015 * outils équivalents * puppet, chief, salt ... ## ansible Φ * idempotence * héritage * réutilisabilité * parallélisation * automatisation #### toute intervention manuelle sur un système est une faute ... ## ... GRAVE! ## ansible * écrit en python * python 2 par défaut * marche bien en python 3 <3 * virtualenv * [<i class="fa fa-book" aria-hidden="true"></i> ansible](https://docs.ansible.com/) ## ansible * prérequis * sur la machine pilote (mgmt node) * ansible (donc python) * sur le(s) noeud(s) * une connextion ssh ou PowerShell * python ## ansible [](https://medium.com/formcept/configuration-management-and-continuous-deployment-cd0892dce998) ## terminologie * **mgmt node** (machine pilote) * machine sur laquelle ansible est installé * pilote la configuration de toutes les machines de l'inventaire * **inventory** (inventaire) * fichier contenant les ip ou les noms de domaine de toutes les machines à configurer * **playbook** * gère la configuration à déployer sur chaque machine ## terminologie * **task** * fichier où sont définies les actions réalisées par le playbook * **module** * actions plus ou moins complexes, utilisables à partir des **tasks** * ansible possède de nombreux [<i class="fa fa-book" aria-hidden="true"></i> modules natifs](https://docs.ansible.com/ansible/latest/modules/modules_by_category.html) * il est possible d'écrire ses propres modules. * **role** * permet d'organiser les playbooks en parties claires et réutilisables ## terminologie * **play** * est l'exécution d'un playbook sur une machine * **facts** * information collectée par ansible sur le système d'une machine à configurer * **handlers** * similaire aux **tasks** mais appelable à partir d'une **task** * redémarrage de service par exemple ## inventory * fichier texte au format *ini* * organiser par groupes * fixer des configurations * pour tous / par groupe / par machine * déclarer des variables * pour tous / par groupe / par machine ## inventory * [<i class="fa fa-book" aria-hidden="true"></i> inventory](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html) ```ini [criprod] pvecriprod2.isima.fr py.criprod.isima.fr gitlab-runner1.criprod.isima.fr [all:vars] environment = production ansible_python_interpreter = /usr/bin/python3 ansible_user = limosadm ``` ## tips ssh * utilisez ~/.ssh/config ``` Host pvecriprod2.isima.fr User limosadm IdentityFile ~/.ssh/keys/limosadm Host py.criprod.isima.fr User limosadm IdentityFile ~/.ssh/keys/limosadm ProxyCommand ssh pvecriprod2.isima.fr -W %h:%p ``` ## ad-hoc command ``` $ ansible all --inventory-file=inventory.ini --module-name ping pvecriprod2.isima.fr | SUCCESS => { "changed": false, "ping": "pong" } py.criprod.isima.fr | SUCCESS => { "changed": false, "ping": "pong" } gitlab-runner1.criprod.isima.fr | SUCCESS => { "changed": false, "ping": "pong" } ``` ## ad-hoc command ``` $ ansible criprod -a "/usr/bin/uptime" pvecriprod2.isima.fr | CHANGED | rc=0 >> 16:18:08 up 41 days, 23:11, 3 users, load average: 0.63, 0.18, 0.10 py.criprod.isima.fr | CHANGED | rc=0 >> 15:18:15 up 1 day, 21:51, 1 user, load average: 0.13, 0.03, 0.01 gitlab-runner1.criprod.isima.fr | CHANGED | rc=0 >> 15:18:15 up 1 day, 22:14, 1 user, load average: 0.00, 0.00, 0.00 ``` ## ad-hoc command * [<i class="fa fa-book" aria-hidden="true"></i> ad-hoc command](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html) * [Parallelism and Shell Commands](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#parallelism-and-shell-commands) * [File Transfer](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#file-transfer) * [Managing Packages](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#managing-packages) * [Users and Groups](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#users-and-groups) * [Deploying From Source Control](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#deploying-from-source-control) * [Managing Services](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#managing-services) * [Time Limited Background Operations](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#time-limited-background-operations) * [Gathering Facts](https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#gathering-facts) ## playbook [<i class="fa fa-book" aria-hidden="true"></i> playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks.html) my-playbook.yml ```yaml - name: my-playbook # ce que vous voulez hosts: criprod # ou all # ou n'importe quel nom de machine # ou n'importe quel nom de groupe remote_user: limosadm # prioritaire sur ansible_user de l'inventaire roles: - role: debug # le rôle debug sera exécuté par le playbook tags: debug # le tag debug sera ajouté à toutes les tâches du role debug my-variable: "pipo" # il ya d'autres endroit où mettre les variables # à suivre ... - role: vault-cli # le rôle vault-cli sera exécuté par le playbook tags: vault # le tag vault sera ajouté à toutes les tâches du role vault-cli ``` ## playbook ```shell $ ansible-playbook my-playbook.yml ``` exécute le playbook sur toutes les machines de l'inventaire ## playbook ```shell $ ansible-playbook my-playbook.yml --check --diff ``` `--check` simule les tâches à effectuer sans les effectuer (dry-run) `--diff` indique ce qui change ## playbook ```shell $ ansible-playbook my-playbook.yml -vvv ``` `-v`, `-vv`, `-vvv`, `-vvvv` pour la verbosité ## playbook ```shell $ ansible-playbook my-playbook.yml --list-tags ``` liste tous les tags disponibles dans le playbook ```shell $ ansible-playbook my-playbook.yml --tags debug ``` n'exécute que les tâches du playbook ayant un tag `debug` ```shell $ ansible-playbook my-playbook.yml --skip-tags debug ``` exécute toutes les tâches du playbook sauf celles ayant un tag `debug` ## playbook ```shell $ ansible-playbook my-playbook.yml --limit=py.isima.fr ``` exécute toutes les tâches du playbook sur py.isima.fr uniquement ## variables * nommage * pas de `-` pas de `.` * pas de numérique pure ## variables * affectation * [<i class="fa fa-book" aria-hidden="true"></i> inventaire](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#defining-variables-in-inventory) * [<i class="fa fa-book" aria-hidden="true"></i> `group_vars`, `host_vars`, ou `inventaire.ini`](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#hosts-and-groups) * [<i class="fa fa-book" aria-hidden="true"></i> playbook](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#defining-variables-in-a-playbook) * role * [<i class="fa fa-book" aria-hidden="true"></i> `default`](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-default-variables) * [<i class="fa fa-book" aria-hidden="true"></i> ligne de commande](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#passing-variables-on-the-command-line) #### [précédence des variables](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable) ## jinja [<i class="fa fa-book" aria-hidden="true"></i> templating](https://docs.ansible.com/ansible-container/container_yml/template.html) group_vars/all.yml ```yaml my-role: my-awesome-role ``` playbook.yml ```yaml roles: - role: "{{ my-role }}" ``` utilisable partout (playbook, role, tasks, template) ## filters [<i class="fa fa-book" aria-hidden="true"></i> filters](https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html) ```yaml "{{ item.path[:4] | replace('/', '-') }}" ``` * renvoie un path * sans les 4 derniers caractères * avec les `/` remplacés par des `-` ## lookup [<i class="fa fa-book" aria-hidden="true"></i> lookup](https://docs.ansible.com/ansible/latest/plugins/lookup.html) ```yaml vars: file_contents: "{{lookup('file', 'path/to/file.txt')}}" ``` [<i class="fa fa-book" aria-hidden="true"></i> lookup list](https://docs.ansible.com/ansible/latest/plugins/lookup.html#plugin-list) [<i class="fa fa-book" aria-hidden="true"></i> callback](https://docs.ansible.com/ansible/latest/plugins/callback.html) ## variable & secret ```yaml - debug: msg: "{{ lookup('env','PVE_NODE') }}" ``` lit une valeur à partir d'une variable d'environement ```yaml - debug: msg: "{{ lookup('hashi_vault', 'secret=secret/hi:value token=xxx url=http://myvault')}}" ``` lit une valeur à partir Vault (<strike>`ansible-vault`</strike>) ```yaml vars_prompt: - name: "name" prompt: "what is your name?" ``` les [<i class="fa fa-book" aria-hidden="true"></i> var_prompts](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html) permettent de lire les variables à partir de l'entrée standard. ## task [<i class="fa fa-book" aria-hidden="true"></i> debug](https://docs.ansible.com/ansible/latest/modules/debug_module.html) ```yaml - debug: msg: "System {{ inventory_hostname }} has uuid {{ ansible_product_uuid }}" ``` * [<i class="fa fa-book" aria-hidden="true"></i> raw](https://docs.ansible.com/ansible/latest/modules/raw_module.html) * n'utilise que ssh et pas python * permet d'installer python * [<i class="fa fa-book" aria-hidden="true"></i> command](https://docs.ansible.com/ansible/latest/modules/command_module.html#command-module) * [<i class="fa fa-book" aria-hidden="true"></i> shell](https://docs.ansible.com/ansible/latest/modules/shell_module.html) * comme **command** mais au travers d'un shell ## task ```yaml - shell: somescript.sh >> somelog.txt args: chdir: somedir/ creates: somelog.txt ``` [<i class="fa fa-book" aria-hidden="true"></i> register](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables) ```yaml shell: /usr/bin/foo register: foo_result ignore_errors: True ``` [<i class="fa fa-gitlab" aria-hidden="true"></i> register dans une liste](https://gitlab.isima.fr/cri/ansible-playbook-vault/blob/master/tasks/initialize.yml#L17) ## task [<i class="fa fa-book" aria-hidden="true"></i> loop](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html) ```yaml - user: name: "{{ item }}" state: present loop: - testuser1 - testuser2 ``` * marche avec * n'importe quelle variable itérable * [fileglob](https://docs.ansible.com/ansible/latest/plugins/lookup/fileglob.html) - list files matching a pattern * [filetree](https://docs.ansible.com/ansible/latest/plugins/lookup/filetree.html) - recursively match all files in a directory tree * ... ## task [<i class="fa fa-book" aria-hidden="true"></i> when](https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html) [<i class="fa fa-book" aria-hidden="true"></i> conditions](https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html) ```yaml - shell: echo "only on Red Hat 6, derivatives, and later" when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6 ``` ## [<i class="fa fa-book" aria-hidden="true"></i> set_fact](https://docs.ansible.com/ansible/latest/modules/set_fact_module.html) & pre_task ```yaml criprod: pvecriprod1: api_users: - proxmoxapi - vimazeno ``` ```yaml - name: provisionner l'environnement du noeud (pour y accéder plus facilement dans les roles) set_fact: _pve: "{ 'cluster': '{{ lookup('env','PVE_CLUSTER') }}', 'node': '{{ lookup('env','PVE_NODE') }}', 'host': '{{ lookup('env','PVE_HOST') }}'}" - name: provisionner les utilisateurs d'api pve uniquement du noeud (pour y accéder plus facilement dans les roles) set_fact: api_users: "{ 'api_users': {{ hostvars[inventory_hostname][_pve.cluster][_pve.node]['api_users'] }}}" - name: fusionner l'environnement du noeud (pour y accéder plus facilement dans les roles) set_fact: pve: "{{ _pve | combine(api_users) }}" ``` [<i class="fa fa-gitlab" aria-hidden="true"></i> exemple permettant de réorganiser les variables](https://gitlab.isima.fr/cri/stack/blob/master/ansible/pre-tasks/set-pve-vars.yml) ## tags tags au niveau tâches ```yaml - name: s'assurer que le fichier user.cfg existe file: dest: /etc/pve/user.cfg state: touch tags: [pve-users] ``` tags au niveau roles à l'inclusion dans le playbook ```yaml roles: - role: debug tags: debug ``` `always` tag spécial exécuté à tous les coups ## modules * [<i class="fa fa-book" aria-hidden="true"></i> file](https://docs.ansible.com/ansible/latest/modules/file_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> lineinfile](https://docs.ansible.com/ansible/latest/modules/lineinfile_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> copy](https://docs.ansible.com/ansible/latest/modules/copy_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> template](https://docs.ansible.com/ansible/latest/modules/template_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> stat](https://docs.ansible.com/ansible/latest/modules/stat_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> get_url](https://docs.ansible.com/ansible/latest/modules/get_url_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> unarchive](https://docs.ansible.com/ansible/latest/modules/unarchive_module.html) ## modules * [<i class="fa fa-book" aria-hidden="true"></i> package](https://docs.ansible.com/ansible/latest/modules/package_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> user](https://docs.ansible.com/ansible/latest/modules/user_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> systemd](https://docs.ansible.com/ansible/latest/modules/systemd_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> pip](https://docs.ansible.com/ansible/latest/modules/pip_module.html) * [<i class="fa fa-book" aria-hidden="true"></i> expect](https://docs.ansible.com/ansible/latest/modules/exepect_module.html) * `pip install pexpect` * [<i class="fa fa-book" aria-hidden="true"></i> ...](https://docs.ansible.com/ansible/latest/modules/modules_by_category.html) ## roles [<i class="fa fa-book" aria-hidden="true"></i> debops](https://docs.debops.org/en/master/) * [<i class="fa fa-github" aria-hidden="true"></i> bau-sec/ansible-openvpn-hardened](https://github.com/bau-sec/ansible-openvpn-hardened) * [<i class="fa fa-github" aria-hidden="true"></i> ...](https://github.com/) ### skeleton ``` ansible-galaxy init --role-skeleton /path/to/stack/ansible/roles/skeletons/role-with-vagrant gitlab ``` [<i class="fa fa-gitlab" aria-hidden="true"></i>ansible/roles/skeletons/role-with-vagrant](https://gitlab.isima.fr/cri/stack/tree/master/ansible/roles/skeletons/role-with-vagrant) ## remote roles `requirements.yml` ```yaml - name: vault-server src: git+ssh://git@gitlab.isima.fr/cri/ansible-playbook-vault.git path: ./ansible/roles/remotes ``` ``` $ ansible-galaxy install -f -r requirements.yml ``` ## ansible.cfg ```ini [defaults] roles_path = ./ansible/roles/remotes:./ansible/roles/apps:./ansible/roles/commons:./ansible/roles/services inventory = ./ansible/inventory.ini filter_plugins = ./ansible/plugins/filter: lookup_plugins = ./ansible/plugins/lookup: callback_plugins = ./ansible/plugins/callback: module_utils = ./ansible/module_utils: stdout_callback = anstomlog deprecation_warnings = False [privilege_escalation] become: yes become_user: root become_method: sudo ``` ## extend [<i class="fa fa-book" aria-hidden="true"></i> developing plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html) [<i class="fa fa-book" aria-hidden="true"></i> developing modules](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules.html)