AWS scheduled startup/shutdown

Amazon Web Services (AWS) est très bien interfacé avec Ansible. Nous allons voir dans cet article comment créer quelques économies d’infrastructure en designant un planficateur de démarrage et d’arrêt d’instances. Nous partirons du principe que vous avez déjà utilisé AWS et que vous avez déjà vu les bases d’Ansible. Nous utiliserons ici une syntaxe ansible 2.0

Architecture

L’architecture de notre scheduler est simple, un cron va faire tourner périodiquement ansible pour envoyer des ordres d’arrêt et extinction à la plateforme EC2 d’AWS en fonction d’un tag sur une instance. Les instances qui devront être démarrées à une heure précise auront le tag starthour, les instances qui devront être éteintes à une heure précise le tag stophour

Playbook Ansible

Nous allons créer un playbook qui va se baser sur un rôle que nous nommerons amazon_scheduler. Editons notre fichier de playbook /etc/ansible/playbooks/amazon_scheduler.yml

---
- hosts: localhost
  connection: local
  become: false
  roles:
    - amazon_scheduler

La configuration de ce playbook permet de la lancer avec un utilisateur non privilégié sur la machine locale.

Role Ansible

Créons maintenant notre role ansible

mkdir -p /etc/ansible/roles/amazon_scheduler/{tasks,vars,default}

Variables

Peuplons le fichier de variables par défaut du rôle (default/main.yml) avec une seule variable correspondant à la region AWS sur laquelle nous allons travailler. Note: Vous pourrez bien entendu externaliser cette région afin d’agir sur plusieurs points du globe facilement.

---
region: 'eu-west-1'

Dans le répertoire de variables du rôle, créez un fichier _vars/defaulthost.yml contenant le hash vide suivant:

---
aws_env: {}

Et un fichier au nom d’hôte de la machine faisant tourner le cron contenant les informations d’authentification AWS réelles.

---
 aws_env:  AWS_ACCESS_KEY_ID: KAMLD8ELAM64AD
 AWS_SECRET_ACCESS_KEY=MSLds51A54cdsq+sdf1s+d2d+dqs59

Note: je vous conseille de sceller le fichier contenant les informations AWS dans une vault ansible chiffrée. Cette méthode permettra ainsi d’avoir une configuration statique pour votre runner automatique et, par défaut d’utiliser la configuration de votre machine personnelle pour vos tests ou actions manuelles.

Actions

Editez maintenant le fichier tasks/main.yml et indiquez le contenu suivant:

---
- name: "Initialize some host specific configuration"
  include_vars: "{{ item }}"
  with_first_found:
    - "{{ ansible_hostname }}.yml"
    - "default_host.yml"
  tags: [stop, start]

- include: stop.yml
  environment: "{{ aws_env }}"
  tags:
    - stop

- include: start.yml
  environment: "{{ aws_env }}"
  tags:
    - start

Notre point d’entrée va dans un premier temps charger nos variables dynamiques par host avant de déclarer 2 sous actions, une pour démarrer et une pour stopper des machines. Chaque sous action dispose en prime d’un accès aux variables d’environnement AWS chargées dynamiquement. Passons maintenant à l’action stop (tasks/stop.yml)

---
- name: EC2 | Stopping instances
  ec2:
    instance_ids: []
    instance_tags:
      stophour: "{{ stophour | default(ansible_date_time.hour) }}"
      region: '{{ region }}'
      state: stopped
      wait: True

Cette action est très simple, on demande au module ec2 d’arrêter toutes les machines avec le tag stophour correspondant à une variable ansible stophour arbitraire. Cette action est appliquée sur notre région statique, spécifiée dans default/main.yml. On attend également que les machines soient éteintes avant de rendre la main. De manière analogue,

---
- name: EC2 | Starting instances
  ec2:
    instance_ids: []
    instance_tags:
      starthour: "{{ starthour | default(ansible_date_time.hour) }}"
    region: '{{ region }}'
    state: running
    wait: True

Arborescence Ansible finale

Vous devriez maintenant avoir l’arborescence ansible suivante:

  • playbooks
    • amazon_scheduler.yml
  • roles
    • amazon_scheduler
      • defaults
        • main.yml
      • tasks
        • main.yml
        • start.yml
        • stop.yml
      • vars
        • default_host.yml
        • ansible_launcher_hostname.yml

Test du playbook

Vous pouvez maintenant tester un scheduler avec une heure précise en invoquant le playbook avec une heure précise et une action précise:

ansible-playbook /etc/ansible/playbooks/amazon_scheduler.yml --tags stop -e stophour=21

Planification cron

Vos schedulers ansible sont prêts. Vous n’avez plus qu’à aller sur votre machine hôte de déploiement Ansible et créer le cron suivant:

0 * * * * ansible ansible-playbook /etc/ansible/playbooks/amazon_scheduler.yml

Configuration AWS

Allez maintenant sur votre console AWS et ajoutez les tags stophour et starthour sur les instances que vous souhaitez allumer et éteindres à horaires fixes. AWS EC2 TagsNote: vous pouvez bien entendu utiliser le module _ec2_tags_ d’Ansible pour industrialiser cette action

Conclusion

Vous pouvez désormais économiser vos ressources AWS (et accessoirement faire quelques économies) en planifiant simplement l’allumage et l’extinction de vos machines. Quelques idées intéressantes en vous basant ce scheduler:

  • Allumer des machines uniquement sur des périodes ouvrées pour vos développeurs
  • Activer certaines machines de production à certaines heures afin d’absorber les pics de charge (ce n’est pas la seule solution, loin de là).