Jusqu'à maintenant, je n'utilisais que les drivers docker
et vagrant
pour
provisionner des machines de tests avec molecule lors de mes développements de
roles et collections Ansible. Comme je n'ai plus assez de ressources à la maison
pour les provisionner, je me suis dit pourquoi utiliser des instances AWS EC2.
Après avoir tâtonnè longtemps, j'ai fini par réussir, j'ai décidé de vous en
faire profiter.
Je vais comme souvent utiliser quelques raccourcis pour tout le monde puisse réussir à reproduire ce tutoriel. Ici il faudrait créer la VM dans un réseau privé et non public et y accéder via un bastion par exemple.
{{%/notice %}}
Installation
Par défaut molécule n'installe que les drivers docker
et delegated
. Il faut
donc installer le driver ec2
, ainsi que la librairie boto3
.
pip install molecule molecule-ec2 boto3
Les dernières versions (2.13.6 et 2.14.0) de la lib ansible-core possède un bug sur le lookup file ! Solution de contournement en attendant la sortie d'ansible-core 2.13.7 on réinstalle la 2.13.5
pip install ansible==6.4.0 ansible-core==2.13.5
:::
Création de la configuration AWS
Maintenant que nous avons tout ce qu'il nous, passons à l'installation et la
configuration la cli awx
. Comme très souvent je vais utiliser
asdf pour l'installer.
asdf plugin add aws-cli
asdf install aws-cli latest
asdf global aws-cli latest
Passons à la configuration du compte en créant au prélable un compte sur IAM :
aws configure
AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: xxxxx/xx/xxxxxxxxxxxxxxxxxxxx
Default region name [None]: eu-west-3
Default output format [None]: json
Initatialisation du role Ansible avec le role EC2
Pour ceux qui ne connaissent pas molecule je vous renvoie à mon premier tutoriel. Créons le role :
molecule init role -d ec2 steph.pyenv
Configuration du scenario molecule
Bon il reste un peu de travail avant d'instancier notre première instance EC2.
Commencons par éditer le scenario avec le fichier présent dans le dossier
molecule/<nom_scenario>/molecule.yml
.
---
dependency:
name: galaxy
driver:
name: ec2
platforms:
- name: instance
image_owner: "099720109477"
image_name: "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20221201"
instance_type: t3a.micro
vpc_subnet_id: subnet-0b13a91a5bd16a5bf
key_inject_method: ec2
ssh_user: ubuntu
tags:
Name: molecule_instance
provisioner:
name: ansible
verifier:
name: ansible
Quelques explications sur les variables :
- image_owner : le nom du owner de l'AMI. Ici canonical
- image_name : le nom de l'AMI
- instance_type : le type d'instance. Ici une t3a.micro une des moins chères, quelques centimes/heures.
- vpc_subnet_id : le sous-réseau à utiliser. Dans mon exemple j'utilise le réseau publique accessible directement.
- key_inject_method : La méthode pour injecter la clé. J'utilise de l'injecter au moment de la création de l'instance.
- ssh_user: l'utilisateur défini dans l'image qui est fonction du type
d'AMI. Pour une ubuntu :
ubuntu
, pour une Amazon Linux,ec2_user
...
Toutes les variables sont documentés dans le fichier
molecule/<nom_scenario>/create.yml
Création et destruction de l'instance.
Attention la version actuelle du driver possède une petite qui fait planter le
converge. Editez le fichier molecule/<nom_scenario>/create.yml
et ajouter à la
ligne 217 ceci state: "running"
. Ce qui donne :
216 wait: true
217 state: "running"
218 vars:
219 platform_security_groups: "{{ item.security_groups or [item.security_group_name] }}"
Bon tout est prêt lancons le converge pour créer l'instance :
molecule converge
INFO default scenario test matrix: dependency, create, prepare, converge
INFO Performing prerun with role_name_check=0...
INFO Set ANSIBLE_LIBRARY=/home/vagrant/.cache/ansible-compat/4489a2/modules:/home/vagrant/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
INFO Set ANSIBLE_COLLECTIONS_PATH=/home/vagrant/.cache/ansible-compat/4489a2/collections:/home/vagrant/.ansible/collections:/usr/share/ansible/collections
INFO Set ANSIBLE_ROLES_PATH=/home/vagrant/.cache/ansible-compat/4489a2/roles:/home/vagrant/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
INFO Using /home/vagrant/.cache/ansible-compat/4489a2/roles/steph.pyenv symlink to current repository in order to enable Ansible to find the role using its expected full name.
INFO Running default > dependency
WARNING Skipping, missing the requirements file.
WARNING Skipping, missing the requirements file.
INFO Running default > create
PLAY [Create] ******************************************************************
TASK [Validate platform configurations] ****************************************
[WARNING]: Unable to find '/home/vagrant/.cache/molecule/pyenv/default/run-
config.yml' in expected paths (use -vvvvv to see paths)
ok: [localhost] => (item=instance)
TASK [Write run config to file] ************************************************
[WARNING]: Unable to find '/home/vagrant/.cache/molecule/pyenv/default/run-
config.yml' in expected paths (use -vvvvv to see paths)
changed: [localhost]
TASK [Generate local key pairs] ************************************************
changed: [localhost] => (item=instance)
TASK [Look up EC2 AMI(s) by owner and name (if image not set)] *****************
ok: [localhost] => (item=instance)
TASK [Look up subnets to determine VPCs (if needed)] ***************************
ok: [localhost] => (item=instance)
TASK [Validate discovered information] *****************************************
ok: [localhost] => (item=instance)
TASK [Create ephemeral EC2 keys (if needed)] ***********************************
changed: [localhost] => (item=instance)
TASK [Create ephemeral security groups (if needed)] ****************************
changed: [localhost] => (item=instance)
TASK [Create ephemeral EC2 instance(s)] ****************************************
changed: [localhost] => (item=instance)
TASK [Wait for instance creation to complete] **********************************
FAILED - RETRYING: [localhost]: Wait for instance creation to complete (300 retries left).
FAILED - RETRYING: [localhost]: Wait for instance creation to complete (299 retries left).
FAILED - RETRYING: [localhost]: Wait for instance creation to complete (298 retries left).
FAILED - RETRYING: [localhost]: Wait for instance creation to complete (297 retries left).
changed: [localhost] => (item=instance)
TASK [Collect instance configs] ************************************************
ok: [localhost] => (item=instance)
TASK [Write Molecule instance configs] *****************************************
changed: [localhost]
TASK [Start SSH pollers] *******************************************************
changed: [localhost] => (item=instance)
TASK [Wait for SSH] ************************************************************
[WARNING]: The 'finished' test expects an async task, but a non-async task was
tested
ok: [localhost] => (item=instance)
TASK [Wait for boot process to finish] *****************************************
Pausing for 120 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=15 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
INFO Running default > prepare
PLAY [Prepare] *****************************************************************
TASK [Make sure python3 is installed] ******************************************
ok: [instance]
PLAY RECAP *********************************************************************
instance : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
INFO Running default > converge
PLAY [Converge] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Include steph.pyenv] *****************************************************
PLAY RECAP *********************************************************************
instance : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Pour se connecter dessus puis la détruire :
molecule login
INFO Running default > login
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-1026-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Dec 4 15:20:15 UTC 2022
System load: 0.0927734375 Processes: 108
Usage of /: 20.0% of 7.57GB Users logged in: 0
Memory usage: 23% IPv4 address for ens5: 172.31.149.83
Swap usage: 0%
0 updates can be applied immediately.
Last login: Sun Dec 4 15:17:43 2022 from 91.166.20.90
-bash: warning: setlocale: LC_ALL: cannot change locale (fr_FR.UTF-8)
ubuntu@ip-172-31-149-83:~$ exit
molecule destroy
Quelques indications en cas difficultés
Destruction de la VM dans la console AWS
Il se peut que vous rencontriez quelques problèmes. Par exemple vous avez
détruit l'instance à la main dans la console EC2 (pas bien), résultat la
commande molecule destroy
plante. Pour rétablir la situation :
rm -rf ~/.cache/molecule/<nom_du_role>/<nom_scenario/>
Ouf, c'est moins compliqué que lorsque vous perdez le state terraform!
Utilisation dans une CI.
Attention à l'utilisation du scenario Test.
Si vous utilisez la commande molecule test
sur ne nombreux rôles, vous risquez
de détruire toutes les VM présentes dans le même subnet_id ! Donc 2 solutions,
Créez des subnet dédiés à chaque rôle ou retirer destroy
du scenario test.
Pour cela à la fin du fichier molecule.yml
ajoutez ces lignes :
scenario:
test_sequence:
- dependency
- cleanup
- create
- prepare
- converge
- cleanup
- destroy
Je dois vérifier s'il est possible de filtrer les instances par ta, ce qui serait plus simple à mettre en oeuvre.
D'autres cas
Si je trouve d'autres situations, je complèterai le billet.
Plus loin
Il ne vous reste plus qu'à développer vos roles et collections Ansible ! N'oubliez pas la sécurité avant tout en durcissant vos roles Ansible.
A bienôt.