Provision d'instances AWS EC2 avec Ansible

Prérequis

Prérequis aws-cli

Une installation du programme aws-cli (Installation de l’AWS CLI), sa configuration (Configuration de l’AWS CLI) et le paramétrage des variables d’environnement sont des pré-requis.

Prérequis AWS EC2

Pour lancer une instance EC2, il est nécessaire de disposer de quelques ressource préalable :

  1. AMI : une image de référence
  2. VPC : un switch virtuel auquel va se connecter l’instance EC2 avec des règles d’accès entrant (au minimum TCP22)
  3. Clé : une clé privée SSH pour se connecter à l’instance. Il est nécessaire de prendre connaissance du nom d’utilisateur

Exemple simple d’approvisionnement

On trouvera ici un exemple simple et pédagogique d’approvisonnement d’instances AWS EC2 avec Ansible.

Une installation du programme aws-cli (Installation de l’AWS CLI), sa configuration (Configuration de l’AWS CLI) et le paramétrage des variables d’environnement sont des pré-requis. Veuillez-vous documenter sur l’usage des modules ec2_* avec Ansible qui indique la présence des librairies boto/boto3 pour la version de Python utilisée par le noeud de contrôle.

Je recommande de ne pas encoder les clés d’accès (access key) et secrète (_secretkey) dans le livre de jeu contrairement à ce que l’on peut voir dans la documentation.

Pour des tâches d’approvisionnement, des modèles Cloudformation ou avec Terraform sont probablement des alternatives à explorer. CloudFormation est une technologie Amazon pour définir un stack Cloud comme un document JSON ou YAML. Les modules Ansible fournissent une interface plus facile à utiliser que CloudFormation dans de nombreux cas sans définir de document JSON/YAML complexe. Toutefois, pour les utilisateurs qui ont décidé d’utiliser CloudFormation, il existe un module Ansible qui peut être utilisé pour appliquer un modèle CloudFormation sur AWS. Lors de l’utilisation d’Ansible avec CloudFormation, Ansible sera généralement utilisé avec un outil comme Packer pour construire des images, et CloudFormation lancera ces images, ou ansible sera invoqué à travers les données utilisateur une fois que l’image sera en ligne, ou une combinaison des deux.

L’image AMI ami-04c58523038d79132 est une image Ubuntu Bionic pour la région eu-west-1. Le livre de jeu crée autant d’instances qu’il y en a dans la liste instance_name, dans cet exemple deux instances : “ansible-node1” and “ansible-node2”.

Le livre de jeu qui réalise les tâches suivantes :

  1. Vérifie la présence du programme aws-cli.
  2. S’assure de la présence d’une paire de clés.
  3. Recueille des informations sur le réseau VPC EC2 dans la région.
  4. Recueille des informations sur le sous-réseau VPC EC2 dans la région.
  5. S’assure de la présence d’un Groupe de Sécurité.
  6. Configure et lance les instances.
  7. Affiche les adresses IP des instances.

Vous trouverez dans ce livre de jeu la démonstration de concepts fondamentaux sur Ansible :

  • De manière générale la manipulation de variables Ansible.
  • L’idempotence mise en oeuvre la tâche “1) Check if aws-cli is installed”.
  • Le lookup sur le système de fichier local pour placer son contenu comme valeur d’un argument du module ec2_key dans la tâche “2) Ensure key pair is present”.
  • La boucle dans une variable “registered” et l’usage des “conditionals” dans la dernière tâche.

Voici le livre de jeu :

---
#Based on https://github.com/PacktPublishing/Learning-Ansible-2.X-Third-Edition/blob/master/Chapter05/playbooks/aws_simple_provision.yaml
- name: "PROVISION EC2 INSTANCES"
  hosts: localhost
  vars:
    unique_value: trainer1
    default_ssh_username: "ubuntu" #Only for printing informations
    pubkey_path: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    region: "eu-west-1"
    ami: "ami-04c58523038d79132"
    instance_type: "t2.micro"
    instance_name:
      - "ansible-node1-{{ unique_value }}"
      - "ansible-node2-{{ unique_value }}"
  tasks:
    - name: "1) Check if aws-cli is installed"
      command: "which aws"
      register: aws_result
      failed_when: "'FAILED' in aws_result.stderr"
      changed_when: "aws_result.rc != 0"
    - name: "2) Ensure key pair is present"
      ec2_key:
        name: "admin-{{ unique_value }}"
        key_material: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    - name: "3) Gather information of the EC2 VPC net in {{ region }}"
      ec2_vpc_net_info:
        region: "{{ region }}"
      register: aws_ec2_net
    - name: "4) Gather information of the EC2 VPC subnet in {{ region }}"
      ec2_vpc_subnet_info:
        region: "{{ region }}"
        filters:
          vpc-id: '{{ aws_ec2_net.vpcs.0.id }}'
      register: aws_ec2_subnet
    - name: "5) Ensure Open Security Group is present"
      ec2_group:
        name: "ossg {{ unique_value }}"
        description: Open Security Group
        region: "{{ region }}"
        vpc_id: '{{ aws_ec2_net.vpcs.0.id }}'
        rules:
          - proto: all
            cidr_ip: 0.0.0.0/0
        rules_egress:
          - proto: all
            cidr_ip: 0.0.0.0/0
      register: aws_ec2_ossg
    - name: "6) Setup instances as present"
      ec2:
        assign_public_ip: True
        image: "{{ ami }}"
        region: "{{ region }}"
        key_name: "admin-{{ unique_value }}"
        exact_count: 1
        count_tag:
          Name: '{{ item }}'
        instance_tags:
          Name: '{{ item }}'
        instance_type: "{{ instance_type }}"
        group_id: '{{ aws_ec2_ossg.group_id }}'
        vpc_subnet_id: '{{ aws_ec2_subnet.subnets.0.id }}'
        volumes:
          - device_name: /dev/sda1
            volume_type: standard
            volume_size: 10
            delete_on_termination: True
      register: aws_ec2_instances
      loop: "{{ instance_name }}"
    - name: "7) print the ip adresses"
      debug:
        msg: "Connect to your {{ item.tagged_instances.0.tags.Name }} with 'ssh {{ default_ssh_username }}@{{ item.tagged_instances.0.public_ip }}'"
      loop: "{{ aws_ec2_instances.results }}"
      when: item.tagged_instances.0.public_ip

Questions :

  • Comment inverser l’intention du livre de jeu soit lui demander d’activer ou supprimer les ressources ?
  • Comment utiliser des hôtes dans un iventaire existant ?
  • Comment ajouter dynamiquement ces ressources dans l’inventaire ?
  • Comment porter ce livre de jeu en rôle avec la fonction d’activation ou de suppression de ressource ?