Thématique DevOps avec Ansible
Posté le 29/09/2017 dans Linux
Ansible est un configuration management tool, c'est-à-dire que c'est un outil qui va te permettre d'administrer tes serveurs et d'y déployer automatiquement tes applications.
Et franchement, ça bute !
C'est très puissant tout en étant relativement simple à prendre en main, à l'inverse d'outils plus compliqués comme Chef ou Puppet par exemple.
En gros, ça va remplacer tes bons vieux scripts shell ou fabfile.
Installation
Vagrant
Pour tester Ansible, tu vas utiliser Virtualbox avec Vagrant pour te monter deux petites VMs Ubuntu Xenial.
Sous Ubuntu, tu peux installer tout ça via la commande suivante et redémarrer ta machine si besoin:
sudo apt-get install virtualbox virtualbox-dkms vagrant
Dans l'idéal, essaye d'avoir une version assez récente de Vagrant. Les fichiers de conf peuvent changer selon les versions.
Ensuite, tu te crées le fichier Vagrantfile suivant dans ~/tuto_ansible/vagrant/Vagrantfile par exemple:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.define "vm1" do | vm1 |
vm1.vm.box = "ubuntu/xenial64"
config.vm.network :forwarded_port, guest: 22, host: 2200, id: "ssh"
config.vm.network :forwarded_port, guest: 80, host: 8010, id: "http"
end
config.vm.define "vm2" do | vm2 |
vm2.vm.box = "ubuntu/xenial64"
config.vm.network :forwarded_port, guest: 22, host: 2201, id: "ssh"
config.vm.network :forwarded_port, guest: 80, host: 8011, id: "http"
end
end
Et tu démarres tes deux VMs via:
cd ~/tuto_ansible/vagrant/
vagrant up
Ansible
Tu installes Ansible sous Ubuntu via :
sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible
Puis tu crées un fichier hosts à la racine du projet, dans ~/tuto_ansible/hosts:
[ubuntu]
vm1 ansible_host=127.0.0.1 ansible_port=2200 ansible_user=ubuntu ansible_become=yes env=test
vm2 ansible_host=127.0.0.1 ansible_port=2201 ansible_user=ubuntu ansible_become=yes env=prod
Et tu édites un fichier ansible.cfg qui va contenir ta configuration Ansible, dans ~/tuto_ansible/ansible.cfg:
[defaults]
inventory = hosts
Tu as désormais indiqué à Ansible d'utiliser tes deux Vms précédemment créées.
Tout est prêt !
La commande ansible
Déjà, tu te places dans le répertoire ~/tuto_ansible pour pouvoir lancer les commandes:
cd ~/tuto_ansible
Ansible a besoin de python sur les machines clientes, donc si c'est pas installé par défaut:
ansible all -m raw -a "apt install -y python" --ask-sudo-pass
L'astuce ici c'est que l'option -m raw permet d'exécuter directement une commande ssh sans Ansible.
Et tu essayes maintenant de contacter tes deux VMs via:
ansible all -m ping
Si tout est ok à ce niveau-là, tu peux passer à la suite. Sinon c'est qu'il y a un souci quelque-part.
Tu vas maintenant pouvoir utiliser la commande ansible pour faire des trucs sur les serveurs comme:
- Exécuter une commande pour afficher la liste des utilisateurs de la première machine:
ansible vm1 -m shell -a "cat /etc/passwd"
- S’assurer que openssl et bash sont à jour sur tous les serveurs ubuntu.
ansible ubuntu -m apt -a "name=openssl,bash state=latest"
- Créer un utilisateur ansible avec un shell /bin/bash.
ansible ubuntu -m user -a "name=ansible shell=/bin/bash"
- Installer la clef publique SSH de notre utilisateur sur l’utilisateur ansible.
ansible ubuntu -m authorized_key -a "user=ansible state=present key={{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- S’assurer des bons droits sur /etc/passwd (0644) et /etc/shadow (0400).
ansible ubuntu -m file -a "path=/etc/passwd mode=0664"
ansible ubuntu -m file -a "path=/etc/shadow mode=0400"
Playbooks
La commande ansible c'est bien mais ça va un moment. Ce que tu veux, c'est avoir une recette à exécuter qui s'occupe de mettre à jour ou non ce dont tu as besoin sur les machines distantes. Cette recette, ça s'appelle un playbook.
Tu vas donc écrire un playbook permettant de :
- installer le paquet sudo.
- créer un utilisateur ansible.
- importer une clé SSH publique pour cet utilisateur.
- configurer sudo pour cet utilisateur (sans mot de passe).
- installer Apache avec le support de PHP activé pour les distributions Ubuntu.
Tu crées le fichier ~/tuto_ansible/myplaybook1.yml :
---
- hosts: ubuntu
become: yes
tasks:
- name: "Installation de sudo sur {{ ansible_distribution }}"
apt:
name: sudo
state: latest
when: ansible_distribution == 'Ubuntu'
- name: Ajout d'un user
user:
name: ansible
shell: /bin/bash
- name: Clé ssh
authorized_key:
user: ansible
state: present
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- name: Ajout du user dans les sudoers
lineinfile:
dest: /etc/sudoers
state: present
line: 'ansible ALL=(ALL) NOPASSWD: ALL'
validate: 'visudo -cf %s'
- name: "Installation de apache sur {{ ansible_distribution }}"
apt:
name:
- apache2
- php
- libapache2-mod-php
state: latest
when: ansible_distribution == 'Ubuntu'
tags:
- install_apache
- name: Apache php
apache2_module:
name: php7.0
state: present
notify: Restart Apache
handlers:
- name: Restart Apache
service:
name: apache2
state: restarted
Regarde bien en détail le playbook:
- hosts précise sur quelles machines exécuter les tâches.
- become indique qu'il faut être sudoer.
- tasks contient les différentes tâches à lancer.
- apt, user, authorized_key, lineinfile, apache2_module et service sont des modules.
- when permet d'utiliser de la conditionnalité pour l'exécution des tâches.
- name, state, key, shell, dest, line et autres sont les paramètres des modules. Pour voir la doc d'un module, tu peux utiliser la commande:
ansible-doc apache2_module
Tu exécutes ton playbook:
ansible-playbook myplaybook1.yml
Et si tu te rends sur http://127.0.0.1:8010/ et http://127.0.0.1:8011/, tu obtiens bien la page par défaut de Apache:
wget http://127.0.0.1:8010/
wget http://127.0.0.1:8011/
Tu peux relancer plusieurs fois de suite le playbook, Ansible ne fera rien de plus sur les serveurs car rien n'a changé.
Templates
Dans ton playbook, tu peux également utiliser des templates pour déployer des fichiers de configuration. Si tu as l'habitude de Django ou Flask, ça tombe bien car c'est Jinja qui est utilisé par Ansible !
Tu vas maintenant mettre en place un message du jour (motd) sur les serveurs à l'aide d'un template.
Tu crées le template motd suivant dans ~/tuto_ansible/motd:
IP = {{ ansible_default_ipv4.address }}
OS = {{ ansible_distribution }}
{% if env == 'prod' %}
ENV = Production
{% elif env == 'test' %}
ENV = Test
{% endif %}
Et le playbook associé dans ~/tuto_ansible/motd.yml:
- hosts: ubuntu
become: true
tasks:
- template:
src: motd
dest: /etc/motd
owner: ansible
group: ansible
mode: 0640
backup: yes
Tu lances ton playbook et tu testes tout ça:
ansible-playbook motd.yml
Tu devrais voir:
ssh -p 2200 ubuntu@127.0.0.1
...
IP = 10.0.2.15
OS = Ubuntu
ENV = Test
Last login: Fri Sep 29 06:45:30 2017 from 10.0.2.2
ubuntu@ubuntu-xenial:~$
Et:
ssh -p 2201 ubuntu@127.0.0.1
...
IP = 10.0.2.15
OS = Ubuntu
ENV = Production
Last login: Fri Sep 29 06:45:30 2017 from 10.0.2.2
ubuntu@ubuntu-xenial:~$
Rôles
Ce qui serait bien, ça serait de pouvoir organiser un peu mieux tout ça pour que tes playbooks soient réutilisables. Tu vas pour ce faire créer un rôle apache qui va installer Apache et le configurer à l'aide d'un template.
C'est parti ! Tu crées un répertoire ~/tuto_ansible/roles qui contient l'arborescence suivante:
roles
└── apache
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
└── mysite.j2
Ou alors tu peux utiliser la commande ansible-galaxy pour initialiser l'arborescence complète d'un rôle:
ansible-galaxy init --offline --init-path ~/tuto_ansible/roles apache
Le dossier handlers va te permettre d'y mettre des tâches qui vont être exécutées à chaque notification de changement. C'est utile pour redémarrer Apache dès que c'est nécessaire par exemple.
Dans ~/tuto_ansible/roles/apache/handlers/main.yml, tu mets:
---
- name: Restart Apache
service:
name: apache2
state: restarted
Le dossiers tasks va tout simplement contenir tes tâches.
Dans ~/tuto_ansible/roles/apache/tasks/main.yml, tu mets:
---
- name: Install Apache
apt:
name: apache2
state: present
- name: Check Apache
service:
name: apache2
enabled: true
state: started
- name: Installation d'un vhost
template:
src: mysite.j2
dest: /etc/apache2/sites-available/mysite.conf
- name: a2ensite mysite
command: a2ensite mysite
notify:
- Restart Apache
Ça installe et démarre Apache, et ça déploie et active un site qui va utiliser la configuration du template mysite.j2.
Pour finir, dans le dossier templates sous ~/tuto_ansible/roles/apache/templates/mysite.j2, tu vas mettre la configuration de ton Virtual Host Apache:
<VirtualHost *:{{ http_port }}>
ServerAdmin webmaster@{{ domain }}
ServerName {{ domain }}
DocumentRoot /var/www/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Les variables http_port et domain seront à définir dans ton playbook principal. Tu édites donc un fichier ~/tuto_ansible/playbook-apache.yml et tu y configures ton rôle apache:
---
# role apache
- hosts: ubuntu
become: true
vars:
http_port: 80
domain: localhost
roles:
- apache
Tu l'exécutes:
ansible-playbook playbook-apache.yml
Et voilà Apache est bien installé et configuré !
Pour aller un peu plus loin, tu peux jeter un oeil aux rôles disponibles sur Galaxy, tu y trouveras sûrement ton bonheur !