Attention, cet article a plus d'une année d'ancienneté. Il est possible que les informations présentées ne soient plus à jour, spécialement dans le cadre d'un article technique.
Bonjour à tous,
Bon, à la base je voulais juste jouer avec l’API de DigitalOcean pour Ansible 2 et voir comment marchait la création / destruction de Droplets.
Ensuite, c’est parti en live je me suis dit que c’était un peu léger de faire un article juste là-dessus et je voulais vous parler d’Ansible de façon plus globale aussi alors je me suis dit que j’allais faire un semblant d’infrastructure pour servir d’exemple.
Cet article n’est pas une procédure, simplement un genre de « Get Started » plutôt complet. Le but n’est pas de reproduire une infrastructure totalement optimisée, fonctionnelle et sécurisée et vous verrez d’ailleurs que je ne me suis pas foulé à certains moments (utilisation de root, mot de passe par défauts dans certaines applis …).
Le but, c’est vraiment de voir comment utiliser Ansible pour du déploiement de masse automatisé et non pas de reproduire quelque chose de totalement fonctionnel (bien que ça marche pas trop mal au moment de la rédaction de cet article).
On verra aussi les quelques dangers d’Ansible et les problématiques (pas tellement) nouvelles que ça apporte.
Avant de commencer :
Cet article n’est pas accessible sans connaissance préalable d’Ansible et il n’y a aucun intérêt a faire un « click & run » brainless ici.
Si vous n’avez jamais touché à Ansible je vous conseille de lire tout ce que j’ai déjà écrit avant cet article.
L’hébergeur :
Bon, déjà j’ai décidé de faire tout ça chez DigitalOcean pour plusieurs raisons.
- Ils proposent une API nativement compatible avec Ansible 2
- Tarification à l’heure
- Ce n’est pas trop cher pour ce type d’expérimentation et donc accessible au plus grand nombre.
Alors, soyons d’accord sur le « pas trop cher ». Oui, au mois DigitalOcean est plus cher que ses concurrents français comme Scaleway ou OVH par contre eux au moins ils ont toujours le mérite de proposé des documentations claires, accessibles et « copy/paste ».
Ensuite, si vous utilisez mon lien de parrainage vous gagnez 10$ en crédit et moi je ne gagne rien tant que vous n’avez pas dépensé 25$ chez eux.
Pour info, ça m’a coûté ~2$ chez Digital Ocean pour faire cet article (les droplets ont tourné pendant 7 heures). Tout sera fait sur le Datacenter FRA1 (Francfort, Allemagne).
L’infrastructure :
En tout, on va déployer 8 Droplets. C’est vraiment pour faire une ébauche de déploiement de masse et surtout parce que la limite publique de déploiement est de 10 droplets chez DigitalOcean.
Comme ça, tout le monde pourra reproduire sans avoir à discuter avec le support pour faire évoluer la limite.
Voici la description des Droplets que l’on va déployer :
- 1 Debian 8 pour accueillir Ansible
- 2 Debian 8 pour un cluster NGINX + Unison
- 1 Ubuntu 16.04 pour le HAPROXY en frontal du cluster NGINX
- 3 Debian 8 pour un cluster galera (MariaDB)
- 1 Debian 8 pour un contrôleur Munin
Celui d’Ansible sera fait à la main, tout le reste sera (presque) totalement automatisé avec Ansible
Création du Droplet Ansible :
Commençons par le commencement, il va falloir que l’on crée notre Droplet pour héberger Ansible.
Créez un compte chez DigitalOcean et connectez-vous. Cliquez ensuite simplement sur le lien suivant et remplissez les informations manquantes :
Connectez-vous en root et éditez votre fichier sources.list avec la commande suivante :
nano /etc/apt/sources.list
Et ajoutez les backports de Debian :
#Ansible deb http://httpredir.debian.org/debian jessie-backports main contrib non-free deb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free
Lancez ensuite la commande suivante pour installer Ansible :
apt-get update && apt-get -t jessie-backports install ansible -y
Générez une clé privée ed25519 :
ssh-keygen -t ed25519
Ensuite, installez Python et les composants nécessaires pour Ansible :
apt-get install -y python python-simplejson python-pip git && pip install dopy
« Dopy » est l’API en Python de Digital Ocean pour information.
Récupération des playbooks et configurations Ansible :
J’ai mis tous les playbooks créés sur mon GitHub.
Le YAML utilisé par Ansible est une syntaxe très capricieuse basée sur l’indentation, ça permettra de s’affranchir des possibles erreurs de copier/coller.
Créez le dossier pour le labo :
mkdir -p ~/ansible-do-api/ && cd ~/
Récupérez les fichiers nécessaires :
git clone https://github.com/stylersnico/The-Great-Ansible-Experiment.git && cd The-Great-Ansible-Experiment mv * ~/ansible-do-api/ cd ~/ansible-do-api/
Vous remarquerez que j’ai laissé toutes les adresses IP en dur dans les playbooks et fichiers de configuration.
Comme ça, vous pourrez vous dessiner un schéma et voir exactement ce que j’ai fait et comment je l’ai fait et voir les liens qui ont étés créés entre les différents serveurs.
Vous remarquez aussi dans la suite de l’article que je vais vous dire de créer les fichiers de configuration.
Ils seront donc évidemment déjà présents, c’est juste pour vous éviter les problèmes d’indentation que peut apporter un copier/coller.
Création de Droplets de test :
Avant de se lancer dans la création d’une infrastructure complète, on va déjà voir comment marche le déploiement de droplets avec l’api DigitalOcean.
Créez d’abord une clé d’API Read/Write sur la page suivante, on en aura besoin pour gérer les droplets depuis Ansible :
Maintenant, appliquez votre clé d’API à tous les playbooks, par exemple :
sed -i "s/DO_API_KEY/20cd5ed666f62eb5a572cd976767249abbce03c16ee3fa9d934a7acdea0d242b/g" ~/ansible-do-api/playbooks/test/* sed -i "s/DO_API_KEY/20cd5ed666f62eb5a572cd976767249abbce03c16ee3fa9d934a7acdea0d242b/g" ~/ansible-do-api/playbooks/random-infra/*
Et créez votre premier playbook pour créer un droplet :
nano ~/ansible-do-api/playbooks/test/digitalocean.yml
On va le remplir avec ceci :
--- - hosts: digitalocean vars: do_token: DO_API_KEY tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure test droplet exists digital_ocean: > state=present command=droplet name=droplet-test unique_name=yes size_id=512mb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} register: droplet_test - name: Show Ip Adress debug: msg="IP is {{ droplet_test.droplet.ip_address }}"
On vérifie d’abord que la clé SSH existe en local avec la tâche ensure ssh key exists.
Ensuite, on copie la clé publique sur le compte DigitalOcean pour qu’elle soit utilisée lors du déploiement de serveurs avec la tâche ensure key exists at DigitalOcean.
On créer un droplet de test avec la tâche ensure test droplet exists.
Pour finir, on récupère son adresse IP dans la console avec la tâche Show Ip Adress.
Vous pourrez supprimer ce droplet de test en créant un autre playbook :
nano ~/ansible-do-api/playbooks/test/digitalocean-delete.yml
Que l’on remplit avec ceci :
--- - hosts: digitalocean vars: do_token: DO_API_KEY tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure test droplet is deleted digital_ocean: > state=absent command=droplet name=droplet-test unique_name=yes size_id=512mb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} register: droplet_test
Vous remarquerez que l’on a supprimé la tache pour renvoyer l’ip étant donné que l’on supprime le droplet ici.
On a simplement changé le paramètre state pour qu’il soit comme ceci state=absent indiquant a Ansible que la ressource ne devrait pas existé et quelle doit être supprimée si elle existe.
Maintenant, on va créer plusieurs Droplets de test en utilisant des boucles :
Créez votre playbook pour créer deux droplets :
nano ~/ansible-do-api/playbooks/test/digitalocean-multiple.yml
On va le remplir avec ceci :
--- - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - droplet-one - droplet-two tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure test droplets exists digital_ocean: > state=present command=droplet name={{ item }} unique_name=yes size_id=512mb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" register: droplet_details - name: Show details debug: msg="IP is {{ item.droplet.ip_address }}" with_items: "{{ droplet_details.results }}"
Vous pourrez les supprimer en créant un autre playbook :
nano ~/ansible-do-api/playbooks/test/digitalocean-multiple-delete.yml
On va le remplir avec ceci :
--- - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - droplet-one - droplet-two tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure test droplets are deleted digital_ocean: > state=absent command=droplet name={{ item }} unique_name=yes size_id=512mb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}"
Création d’une infrastructure complète :
Comme je l’ai déjà dit, on va rester en dessous de 10 Droplets pour faire cette infrastructure, car, c’est la limite de base de DigitalOcean, comme ça tout le monde pourra reproduire sans demander d’augmentation de limite.
Déploiement des droplets :
Commencez par créer le playbook pour déployer les droplets :
nano ~/ansible-do-api/playbooks/random-infra/deploy-droplets.yml
On va le remplir avec ceci :
--- #Here we deploy droplets for NGINX stack - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - nginx-01 - nginx-02 tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure web stack exist digital_ocean: > state=present command=droplet name={{ item }} unique_name=yes size_id=512mb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" register: droplet_details - name: Show details debug: msg="IP is {{ item.droplet.ip_address }}" with_items: "{{ droplet_details.results }}" #Here we deploy droplet for HA Proxy - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - loadbalancer-01 tasks: - name: ensure web stack exist digital_ocean: > state=present command=droplet name={{ item }} unique_name=yes size_id=512mb region_id=fra1 image_id=ubuntu-16-04-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" register: droplet_details - name: Show details debug: msg="IP is {{ item.droplet.ip_address }}" with_items: "{{ droplet_details.results }}" #Here we deploy droplets for the gallera MariaDB Cluster - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - galera-01 - galera-02 - galera-03 tasks: - name: ensure galera stack exists digital_ocean: > state=present command=droplet name={{ item }} unique_name=yes size_id=1gb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" register: droplet_details - name: Show details debug: msg="IP is {{ item.droplet.ip_address }}" with_items: "{{ droplet_details.results }}" #Here we deploy droplet for Munin - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - munin tasks: - name: ensure Munin droplet exist digital_ocean: > state=present command=droplet name={{ item }} unique_name=yes size_id=2gb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" register: droplet_details - name: Show details debug: msg="IP is {{ item.droplet.ip_address }}" with_items: "{{ droplet_details.results }}"
Lancez le playbook avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/deploy-droplets.yml
Maintenant, éditez le fichier hosts et ajoutez les adresses de vos droplets :
nano ~/ansible-do-api/hosts
Par exemple pour moi :
[digitalocean] localhost ansible_connection=local [loadbalancer] 46.101.201.239 ansible_connection=ssh ansible_user=root [nginx] 46.101.99.247 ansible_connection=ssh ansible_user=root 139.59.140.250 ansible_connection=ssh ansible_user=root [unisonmaster] 46.101.99.247 ansible_connection=ssh ansible_user=root [galera] 46.101.101.229 ansible_connection=ssh ansible_user=root 46.101.190.144 ansible_connection=ssh ansible_user=root 46.101.115.102 ansible_connection=ssh ansible_user=root [munin] 139.59.214.129 ansible_connection=ssh ansible_user=root
Après ça il faudra valider manuellement les empreintes ssh de chaque hôte.
Installez aussi les dépendances nécessaires :
ansible all -m raw -a "apt-get install -y python python-simplejson"
Sécurisation des droplets :
On va commencer par sécuriser les hôtes et les mettre à jour.
Dans un premier temps, installez tous les rôles qu’on va utiliser avec la commande suivante :
chmod +x roles.sh && ./roles.sh
Voici ce que l’on va accomplir :
- Déploiement de la configuration NTP
- Configuration de SSHD, Fail2Ban et unattended upgrades
- Installation de NeedRestart
- Installation et configuration de UFW
Un point sur la configuration du pare-feu (UFW) :
Le HAProxy aura le port 80 ouvert sur le monde.
Les serveurs NGINX auront le port 80 uniquement accessible depuis le HAProxy. Ils pourront librement communiquer entre eux.
Les serveurs Galera auront le port 3306 uniquement accessible depuis les serveurs NGINX. Ils pourront librement communiquer entre eux.
Le serveur Munin aura le port 80 ouvert sur le monde.
Le serveur Ansible aura le port 22 ouvert sur le monde.
Tous les serveurs (hors Ansible) auront le port 22 accessible uniquement depuis Ansible et le port 4949 accessible uniquement depuis Munin.
Créez maintenant le fichier de déploiement :
nano ~/ansible-do-api/playbooks/random-infra/security.yml
On va le remplir avec ceci :
--- #First of all - NTP - hosts: all roles: - role: resmo.ntp ntp_config_server: [0.de.pool.ntp.org, 1.de.pool.ntp.org, 2.de.pool.ntp.org, 3.de.pool.ntp.org] #SSH + auto-updates - hosts: all vars: security_ssh_port: 22 security_ssh_password_authentication: "no" security_ssh_permit_root_login: "without-password" security_ssh_usedns: "no" security_autoupdate_enabled: true security_fail2ban_enabled: true roles: - geerlingguy.security #Needrestart - hosts: all tasks: - name: Install NeedRestart apt: name=needrestart state=present #Firewall - hosts: loadbalancer roles: - franklinkim.ufw vars: ufw_rules: - { port: 22, rule: allow, from_ip: '46.101.227.239' } - { port: 80, rule: allow } - { port: 4949, rule: allow, from_ip: '139.59.214.129' } ufw_logging: full - hosts: nginx roles: - franklinkim.ufw vars: ufw_rules: - { port: 22, rule: allow, from_ip: '46.101.227.239' } - { port: 80, rule: allow, from_ip: '46.101.201.239' } - { port: 4949, rule: allow, from_ip: '139.59.214.129' } - { rule: allow, from_ip: '46.101.99.247' } - { rule: allow, from_ip: '139.59.140.250' } ufw_logging: full - hosts: galera roles: - franklinkim.ufw vars: ufw_rules: - { port: 22, rule: allow, from_ip: '46.101.227.239' } - { port: 3306, rule: allow, from_ip: '46.101.99.247' } - { port: 3306, rule: allow, from_ip: '139.59.140.250' } - { port: 4949, rule: allow, from_ip: '139.59.214.129' } - { rule: allow, from_ip: '46.101.101.229' } - { rule: allow, from_ip: '46.101.190.144' } - { rule: allow, from_ip: '46.101.115.102' } ufw_logging: full - hosts: munin roles: - franklinkim.ufw vars: ufw_rules: - { port: 22, rule: allow, from_ip: '46.101.227.239' } - { port: 80, rule: allow } - { port: 4949, rule: allow, from_ip: '139.59.214.129' } ufw_logging: full - hosts: digitalocean roles: - franklinkim.ufw vars: ufw_rules: - { port: 22, rule: allow } - { port: 4949, rule: allow, from_ip: '139.59.214.129' } ufw_logging: full
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/security.yml
Mise à jour des droplets :
Et oui, les mises à jour c’est le plus important dans une infrastructure.
Pour ça on va faire un playbook qui :
- Lance un apt-get update
- Lance un apt-get upgrade en conservant toujours les fichiers de configuration en place
- Lance NeedRestart pour redémarrer les services qui en ont besoin
- Lance un reboot si il y’en a besoin (Trust me dude, it’s safe).
Créez maintenant le playbook :
nano ~/ansible-do-api/playbooks/random-infra/apt-upgrade.yml
On va le remplir avec ceci :
- hosts: all tasks: - name: updates a server apt: update_cache=yes cache_valid_time=3600 - name: upgrade a server apt: upgrade=dist dpkg_options='force-confold,force-confdef' - name: Check if a reboot is required register: reboot stat: path=/var/run/reboot-required get_md5=no - name: Reboot the services shell: needrestart -ra -l when: reboot.stat.exists == false - name: Reboot the server command: /sbin/reboot when: reboot.stat.exists == true
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/apt-upgrade.yml
Déploiement des serveurs NGINX + HAProxy :
Bon, maintenant qu’on en as fini avec la base, on va déployer les deux serveurs NGINX et le HAPROXY.
Créez le playbook :
nano ~/ansible-do-api/playbooks/random-infra/nginx.yml
On va le remplir avec ceci :
--- - hosts: nginx roles: - role: bennojoy.nginx nginx_http_params: sendfile: "on" access_log: "/var/log/nginx/access.log" nginx_sites: - server: file_name: www.vhost listen: 80 server_name: _ root: "/var/www/html/" location1: {name: /, try_files: "$uri $uri/ /index.html"} location2: {name: /images/, try_files: "$uri $uri/ /index.html"}
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/nginx.yml
Maintenant, vous pouvez tester le bon fonctionnement des serveurs NGINX avec la commande suivante :
ansible loadbalancer -m shell -a 'curl -I 139.59.140.250 && curl -I 46.101.99.247'
Maintenant HAPROXY, créez le playbook :
nano ~/ansible-do-api/playbooks/random-infra/haproxy.yml
On va le remplir avec ceci :
- hosts: loadbalancer tasks: - name: install make apt: name=make state=present - hosts: loadbalancer vars: haproxy_frontends: http_front: - bind *:80 - default_backend http_back haproxy_backends: http_back: - balance roundrobin - server http1 139.59.140.250:80 check - server http2 46.101.99.247:80 check roles: - role: SimpliField.haproxy
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/haproxy.yml
Maintenant, vous pouvez tester le bon fonctionnement de HAPROXY avec la commande suivante (vous verrez le Roundrobin faire effet en la lançant plusieurs fois :
curl -I 46.101.201.239
Déploiement de Unison:
Unison nous servira à synchroniser les répertoires /var/www/ des deux serveurs NGINX ici.
Malheureusement, je ne nous ai pas trouvé de playbook qui installait correctement Unison de A à Z, il faudra donc configurer l’échange de clé SSH manuellement avec l’aide de cette procédure.
Créez le playbook :
nano ~/ansible-do-api/playbooks/random-infra/unison.yml
On va le remplir avec ceci :
- hosts: unisonmaster roles: - weareinteractive.unison vars: unison_configs: - name: sync src: /var/www dest: ssh://139.59.140.250//var/www unison_user: unison ignore: - ".*" - "~*"
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/unison.yml
Connectez-vous sur le master unison et testez la synchronisation avec la commande suivante :
unison /var/www ssh://139.59.140.250//var/www
Déploiement du cluster Galera (MariaDB) :
Dans un premier temps, il va falloir supprimer une section inutile du rôle utilisé pour Galera avec la commande suivante :
echo "" > /etc/ansible/roles/uoi-io.galera/tasks/firewall.yml
C’est inutile, car nous avons installé et configuré UFW au préalable.
Créez le playbook :
nano ~/ansible-do-api/playbooks/random-infra/galera.yml
On va le remplir avec ceci :
--- - hosts: galera roles: - uoi-io.galera vars: master: 46.101.101.229 mariadb_bind_address: 0.0.0.0 mariadb_max_connections: 4096 mariadb_maintenance_password: I3uL6AqJLHInv85x mariadb_root_password: 3248ew7dsYUG762 mariadb_hosts_allow: 10.0.% galera_node_address: "{{ ansible_eth0.ipv4.address }}" galera_pacemaker_support: false galera_clustercheck_user: clustercheck galera_clustercheck_password: Y3aH1l0ved2CH3CK galera_cluster_name: uoi-sql-cluster galera_sst_password: gr34tp4ss0rd galera_cluster_nodes: - 46.101.101.229 - 46.101.190.144 - 46.101.115.102
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/galera.yml
Vous pourrez vérifier le statut du Cluster sur chaque hôte avec la commande suivante :
ansible galera -m shell -a 'galera-status'
Déploiement de Munin-node :
On va maintenant déployer Munin-nodes sur tous les serveurs de l’infrastructure pour le monitoring.
Ensuite seulement on s’occupera du Master.
Créez le playbook :
nano ~/ansible-do-api/playbooks/random-infra/munin-nodes.yml
On va le remplir avec ceci :
- hosts: all roles: - { role: geerlingguy.munin-node } vars: munin_node_bind_host: "*" - hosts: all tasks: - name: Enable Munin Modules shell: "munin-node-configure --shell --families=contrib,auto | sh -x && service munin-node restart"
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/munin-nodes.yml
Maintenant, créez le playbook pour déployer le master :
nano ~/ansible-do-api/playbooks/random-infra/munin-nodes.yml
On va le remplir avec ceci :
--- - hosts: munin roles: - geerlingguy.munin vars: munin_htmldir: /var/cache/munin/www munin_hosts: - { name: "ansible", address: "46.101.227.239", extra: ["use_node_name yes"] } - { name: "haproxy", address: "46.101.201.239", extra: ["use_node_name yes"] } - { name: "nginx-01", address: "46.101.99.247", extra: ["use_node_name yes"] } - { name: "nginx-02", address: "139.59.140.250", extra: ["use_node_name yes"] } - { name: "galera-01", address: "46.101.101.229", extra: ["use_node_name yes"] } - { name: "galera-02", address: "46.101.190.144", extra: ["use_node_name yes"] } - { name: "galera-03", address: "46.101.115.102", extra: ["use_node_name yes"] } - hosts: munin roles: - role: bennojoy.nginx nginx_http_params: sendfile: "on" access_log: "/var/log/nginx/access.log" nginx_sites: - server: file_name: www.vhost listen: 80 server_name: _ root: "/var/cache/munin/www" location1: {name: /, try_files: "$uri $uri/ /index.html"}
Et lancez le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/munin-nodes.yml
Suppression de l’infrastructure :
Maintenant, il s’agit de supprimer tous les droplets créer précédemment (hormis Ansible).
Créez le playbook :
nano ~/ansible-do-api/playbooks/random-infra/destroy-droplets.yml
On va le remplir avec ceci :
--- - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - nginx-01 - nginx-02 tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure web stack is deleted digital_ocean: > state=absent command=droplet name={{ item }} unique_name=yes size_id=512mb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - loadbalancer-01 tasks: - name: ensure ssh key exists user: > name={{ ansible_user_id }} generate_ssh_key=yes ssh_key_file=.ssh/id_ed25519 - name: ensure key exists at DigitalOcean digital_ocean: > state=present command=ssh name=ansible_ssh_key ssh_pub_key={{ lookup('file', '~/.ssh/id_ed25519.pub') }} api_token={{ do_token }} register: my_ssh_key - name: ensure loadbalancer is deleted digital_ocean: > state=absent command=droplet name={{ item }} unique_name=yes size_id=512mb region_id=fra1 image_id=ubuntu-16-04-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - galera-01 - galera-02 - galera-03 tasks: - name: ensure galera stack is deleted digital_ocean: > state=absent command=droplet name={{ item }} unique_name=yes size_id=1gb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}" - hosts: digitalocean vars: do_token: DO_API_KEY droplets: - munin tasks: - name: ensure Munin droplet is deleted digital_ocean: > state=absent command=droplet name={{ item }} unique_name=yes size_id=2gb region_id=fra1 image_id=debian-8-x64 ssh_key_ids={{ my_ssh_key.ssh_key.id }} api_token={{ do_token }} with_items: "{{ droplets }}"
Et lancez-le avec la commande suivante :
cd ~/ansible-do-api/ ansible-playbook playbooks/random-infra/destroy-droplets.yml
Conclusion :
Déjà, si vous avez tout suivi et tout lu, félicitations et merci, vous arrivez au bout du plus gros article que j’ai jamais écrit (+3000 mots contre 300-600 en moyenne).
Pour l’anecdote, il m’a fallu une journée entière pour préparer l’infrastructure et une autre journée entière pour rédiger les articles en Français et Anglais, ça m’a donc légèrement occupé.
Ce qu’il faut retenir ?
- Vous pouvez garder les parties Sécurisation et Mise à jour des droplets pour de la production. C’est même un must-have.
- N’espérez pas monter une infrastructure sans travail et uniquement avec ce que vous trouvez sur Ansible Galaxy. Les partages sont très mal documentés, largement non fonctionnels et loin d’avoir le niveau de sécurité nécessaire pour de la production.
- Si vous développez vos propres rôles et que vous les publiez, alors soignez la documentation
bordel, testez-les et favorisez des playbooks simples et fonctionnels qui utilisent des variables clairement définissables et documentées dans lesbordel deREADME (Philosophies KISS / Unixnon de Zeus). - Évitez les dépendances au maximum et les projets types DebOps qui sont des usines à gaz à la syntaxe marquée comme deprecated sur Ansible 2.
- Si vous utilisez des dépendances, intégrez les de manière fluide et invisible dans le rôle ça évitera de se prendre la tête.
Si vous débutez sur Ansible, j’espère que ça vous aura permis d’appréhender un peu mieux les possibilités offertes par ce formidable outil.
Petite note supplémentaire, comme je l’ai dit, c’est uniquement de la démonstration que je fais dans cet article, il ne s’agit pas de tout reproduire de A à Z en pensant tenir une infrastructure complète, fonctionnelle et sécurisée. Tous les commentaires demandant du support seront donc supprimés.
Merci pour cet article.
Si vous souhaitez faire vos tests en local, il est possible également le faire via vagrant.
J’utilise beaucoup vagrant pour expérimenter mes roles/playbook sur des problématiques de clustering.
Un exemple (sans doc, mais un simple make lance tout le setup) : https://github.com/SimpliField/ansible-vagrant-examples/tree/master/mongo-rs
Salute,
Merci pour le partage, c’est très sympa comme expérience.
Tcho !