TASK: [common/base | Start ntp service] *************
ok: [front-1]
TASK: [common/base | Set ulimits] *******************
changed: [front-1]
....
PLAY RECAP *************************************************
front-1 : ok=12 changed=9 unreachable=0 failed=0
Concepts de bases
- Inventaires
- Playbooks
- Rôles
Inventaire
Liste de machines, groupes et variables
Inventaire statique
prod-front-1 ansible_ssh_host="123.42.0.1"
prod-front-2 ansible_ssh_host="123.42.0.2"
prod-api-1 ansible_ssh_host="123.42.0.3"
prod-api-2 ansible_ssh_host="123.42.0.4"
[frontservers]
prod-front-1
prod-front-2
[appservers]
prod-api-1
prod-api-2
[appservers:vars]
ssl_certs="blurb.space.pem"
[all:children]
frontservers
appservers
[all:vars]
ansible_ssh_user="admin"
ansible_ssh_private_key_file="/ops/ssh/admin.id_rsa"
Playbooks
- Description réutilisable de configuration
- Fichiers YAML
- Collection de plays
- Suite de tâches ciblant un groupe de machines
- Tâche : appel d'un module
Tâche
Appel d'un module avec des paramètres
- name: MongoDB | Create user
user: name="{{ mongodb_user }}" group="{{ mongodb_group }}"
shell=/bin/bash
- name: Base | Install base packages
apt: name="{{ item }}" state=present
with_items:
- ntp
- htop
- zsh
- curl
- apt-transport-https
- fail2ban
Exemple de playbook pour installer haproxy
# install-haproxy.yml
---
- hosts: webservers
sudo: yes
vars:
haproxy_version: 1.5.8-3+deb8u1
tasks:
- name: haproxy | Install haproxy
apt: name="haproxy={{ haproxy_version }}" state=present
- name: haproxy | Start haproxy
service: name=haproxy state=started
> ansible-playbook -i inventory/prod install-haproxy.yml
Templates de fichiers de configuration - Jinja2
Fichier dynamiquement générés en fonction de ...
>
Templates Jinja2
# ansible/playbooks/roles/ha-api/tasks/main.yml
- name: ha-api | Configure haproxy
template:
src="haproxy.cfg.j2"
dest="/etc/haproxy/haproxy.cfg"
owner=root mode=644
# ansible/playbooks/roles/ha-api/template/haproxy.cfg.j2
...
listen stats :6789
mode http
stats enable
stats hide-version
stats realm HAProxy-Statistics
stats uri /
stats auth admin:{{ haproxy_admin_password }}
...
# ansible/inventory/integ
[ha-api-servers:vars]
haproxy_admin_password="UyY5LHwE7GfgVouOXFkoVdZ"
Handlers
Tâche exécutée seulement si une autre tâche 'changed' et 'notify'
# ansible/playbooks/roles/ha-api/tasks/main.yml
---
- name: ha-api | Configure haproxy
template: src=haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg
notify: reload haproxy
# ansible/playbooks/roles/ha-api/handlers/main.yml
---
- name: reload haproxy
service: name=haproxy state=reloaded
Installation
> apt-get install python pip
> pip install ansible==1.9.4
Exécution
> ansible $group -i $inventory -m $module -a "$parameters"
> ansible-playbook -i $inventory $playbook $options
> ansible api-servers -i inventory/integ -m command -a "docker ps"
> ansible-playbook -i inventory/prod playbooks/all.yml -t common
Organisation en rôles
ansible/playbooks/roles/base/haproxy
├── defaults
│ └── main.yml
├── files
│ └── default
├── hanlers
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
└── haproxy.cfg.j2
# ansible/playbooks/api-servers.yml
---
- hosts: api-servers
sudo: yes
gather_facts: false
roles:
- { role: base/docker, tags: ["base", "docker"] }
- { role: base/docker-py, tags: ["base", "docker-py"] }
- { role: api-server, tags: ["api-server"] }
Démo
- Update the version of the app
- > ansible-playbook ...
- zZzZ ...
- Enjoy :-)
Vault
Chiffrage symétrique des variables
# Creation
> ansible-vault create inventory/group_vars/prod.yml
# Edition
> ansible-vault edit inventory/group_vars/prod.yml
# Password prompt
> ansible-playbook site.yml --ask-vault-pass
# Password file/script
> ansible-playbook --vault-password-file "~/.vault_pass.py"
452 modules
- apt, pip, get_url, service
- user, group
- template, file, copy
- shell, uri
- ufw, docker
- mail, irc, hipchat, slack
- ...
Templates Jinja2
# ansible/playbooks/roles/ha-api/templates/haproxy.cfg.j2
...
{% if env == "internal" %}
stats socket /run/haproxy/admin.sock mode 660 level admin
{% endif %}
...
# ansible/playbooks/roles/ha-api/templates/haproxy.cfg.j2
...
backend apiservers
http-check expect status 200
# server prod-api-1 149.202.168.198:8080 check
# server prod-api-2 149.202.168.199:8080 check
# Loop on apiservers group
{% for h in groups['apiservers'] -%}
server {{ hostvars[h]['inventory_hostname'] }} \
{{ hostvars[h]['ansible_ssh_host'] }}:8080 check
{% endfor %}
...
Tips - Options utiles
# Filtrage par tags
-t tag1,tag2
# Filtrage par machines
-l node1,node2
# Vérification des tâches exécutées
--list-tasks
# Vérification des machines impactées
--list-hosts
# Dry-run
--check --diff
# Mode verbose
-vvvv
Tricks
Debugger des variables
- debug: msg="Debug var truc: {{ truc }}"
Tagguer pour n'exécuter qu'une tâche
- name: rsyslog | Update apt
apt: update_cache=yes cache_valid_time=3600
tags: ["base", "apt-update"]
Tips
register, ignore_errors, failed_when, when
tasks:
- name: Check presence of the metrics daemon
shell: ls /etc/init.d/metricsd
register: metricsd_present
ignore_errors: yes
failed_when: "'No such file' in metricsd_present.stderr"
tags: [metrics-daemon]
- name: Register metrics daemon apt source list
shell: wget -O /etc/apt/sources.list.d/metrics.list http://dl.myrepo.com/debian/metrics.list
when: metricsd_present|failed
tags: [metrics-daemon]
Module - notification
- name: ActoFront | Deploy | HipChat notification
hipchat:
token="{{ hipchat_token }}"
room="ops"
color="yellow"
from="ansible-bot"
msg="[{{ env }}] {{ inventory_hostname }}
{{ actofront_name}}-{{ actofront_version_todeploy.stdout }}
- DEPLOYED (Open)"
msg_format="html"
notify="yes"
ignore_errors: yes
Module - uri
- name: Register machine to the monitoring platform
uri:
url="{{ monitoring_url }}//api/v0/devices"
method=POST
HEADER_X-Auth-Token="{{ monitoring_api_token }}"
HEADER_Content-Type="application/json"
body='{
"hostname":"{{ inventory_hostname }}.{{ admin_dns_zone }}",
"community":"{{ monitoring_community }}"
}'
status_code="201"
Inventaire dynamique
> inv.sh --list
{
"apiservers": ["api-1", "api-2"],
"frontservers": ["front-1", "front-2"]
}
> inv.sh --host front-1
{
"name": "front-1",
"ansible_ssh_user": "admin",
"ansible_ssh_host": "123.42.0.1",
"ansible_ssh_private_key_file": "/ops/ssh/admin.id_rsa"
}
Démo
- 1 Front + 1 HAProxy + X API
- ansible-playbook ...
- zZzZ ...
- Enjoy :-)