TP 2 - Terraform đȘ et la crĂ©ation dâinfrastructure avec du code đ©âđ»
Mise en place
Allez sur la plateforme AWS Academy et accédez au cours AWS Academy Learner Lab. Puis cliquez sur Modules
> Learner Lab
. Lancez votre environnement en cliquant sur Start Lab
. Une fois le cercle passé au vert, cliquez sur AWS Details
et AWS CLI
. Ces clés permettent un accÚs programmatique à votre compte.
Ouvrez un terminal et exécutez la commande aws configure
. Un prompt va vous demander votre AWS Access Key ID, collez la valeur de aws_access_key_id
. Faites de mĂȘme pour la Secret Access Key. Pour la rĂ©gion par dĂ©faut, entrez âus-east-1â. Validez le dernier prompt. Allez ensuite modifier le fichier credentials
qui se trouve dans le dossier .aws
(attention ce dossier est caché).
Créez un dossier cloud-computing
avec la commande mkdir "cloud-computing"
. Déplacez-vous dans le dossier avec la commande cd "cloud computing"
. Clonez le dépÎt git du TP avec un git clone https://github.com/HealerMikado/Ensai-CloudComputingLab2.git
. Au début de chaque exercice, vous allez devoir exécuter un pipenv sync
dans le dossier de lâexercice. Cela va crĂ©er un environnement virtuel Python et y installer toutes les dĂ©pendances de lâexercice. Pour que VScode reconnaisse les modules que vous allez utiliser, il faut lui spĂ©cifier lâinterprĂ©teur quâil doit utiliser. Faites un Ctrl+Shift+P
, tapez Select Interpreter
et prenez lâinterprĂ©teur pipenv ex X cdktf ...
.
đŠ Ă cause du fonctionnement de Python, cela va multiplier les environnements virtuels et le stockage qui leur est associĂ©. Une solution moins gourmande en espace disque mais moins Ă©lĂ©gante est de rĂ©utiliser toujours le mĂȘme espace.
Mon premier script avec le CDK Terraform
Une instance de base
Ouvrez le fichier main.py
. Il contient lâarchitecture minimale du code nĂ©cessaire pour que vous puissiez rĂ©aliser le TP.
from constructs import Construct
from cdktf import App, TerraformStack, TerraformOutput
from cdktf_cdktf_provider_aws.provider import AwsProvider
from cdktf_cdktf_provider_aws.instance import Instance, InstanceEbsBlockDevice
from cdktf_cdktf_provider_aws.security_group import SecurityGroup, SecurityGroupIngress, SecurityGroupEgress
from user_data import user_data
class MyStack(TerraformStack):
def __init__(self, scope: Construct, id: str):
super().__init__(scope, id)
AwsProvider(self, "AWS", region="us-east-1")
TerraformOutput(
self, "public_ip",
value=instance.public_ip,
)
app = App()
MyStack(app, "cloud_commputing")
app.synth()
Voici tous les imports dont vous aurez besoin. Ils ne sont pas toujours Ă©vidents Ă trouver, câest pourquoi je vous les fournis.
La classe MyStack
va contenir toute votre architecture. Pour associer les services que vous allez créer à votre stack, vous allez passer en paramÚtre la stack courante à tous vos objets. Ainsi, tous les objets AWS que vous allez créer vont avoir en premier argument self
.
Maintenant, vous allez dĂ©finir votre premiĂšre ressource. La classe du cdktf associĂ©e Ă une instance EC2 dâAWS est la classe Instance
. Les deux premiers arguments Ă passer au constructeur de la classe Instance
sont la stack courante et un id sous la forme dâune chaĂźne de caractĂšres.
đ§ââïž Sauf rare exception, tous les objets que vous allez crĂ©er vont avoir comme premiers arguments la stack courante et un id.
instance = Instance(
self, "webservice")
Ensuite, via des paramĂštres nommĂ©s, vous allez dĂ©finir un peu plus en dĂ©tail votre instance. Rappelez-vous, pour une instance EC2, il vous faut dĂ©finir son OS (appelĂ© AMI chez AWS) et le type dâinstance.
Ajoutez Ă votre instance son AMI avec le paramĂštre ami
qui prendra comme valeur ami-04b4f1a9cf54c11d0
(câest lâidentifiant de lâAMI Ubuntu dans la rĂ©gion us-east-1
), et pour le type dâinstance, vous prendrez une t2.micro
. Exécutez votre architecture avec la commande cdktf deploy
dans le terminal. Connectez-vous au tableau de bord EC2 et vĂ©rifiez que votre instance est bien dĂ©marrĂ©e. NĂ©anmoins, si vous essayez de vous connecter en SSH Ă votre instance, vous allez voir que câest impossible. En effet, lors de la dĂ©finition de lâinstance, nous nâavons pas dĂ©fini la clĂ© SSH Ă utiliser et le security group de lâinstance. Tout cela fait que, pour le moment, lâinstance nâest pas accessible.
Configuration de la partie réseau
Vu que ce nâest pas intĂ©ressant Ă trouver seul, voici le code pour dĂ©finir le security group de lâinstance :
security_group = SecurityGroup(
self, "sg-tp",
ingress=[
SecurityGroupIngress(
from_port=22,
to_port=22,
cidr_blocks=["0.0.0.0/0"],
protocol="TCP",
description="Accept incoming SSH connection"
),
SecurityGroupIngress(
from_port=80,
to_port=80,
cidr_blocks=["0.0.0.0/0"],
protocol="TCP",
description="Accept incoming HTTP connection"
)
],
egress=[
SecurityGroupEgress(
from_port=0,
to_port=0,
cidr_blocks=["0.0.0.0/0"],
protocol="-1",
description="allow all egresse connection"
)
]
)
Ce Security Group nâaccepte que les connexions HTTP et SSH en entrĂ©e et permet tout le trafic en sortie. Pour associer ce Security Group Ă votre instance, vous allez devoir ajouter un paramĂštre security_groups
lors de la crĂ©ation de lâobjet. Attention, ce paramĂštre attend une liste de Security Groups. Pour dĂ©finir la clĂ©, ajoutez le paramĂštre key_name
avec comme valeur le nom de la clé (vockey
). Vous pouvez maintenant relancer votre instance avec un nouveau cdktf deploy
. Cela va rĂ©silier lâinstance prĂ©cĂ©dente et en crĂ©er une nouvelle.
Configuration des user data
Pour le moment, nous nâavons pas dĂ©fini les user data de lâinstance. Pour les ajouter, il faut simplement ajouter le paramĂštre user_data_base64
avec comme valeur la variable contenue dans user_data.py
(la valeur est dĂ©jĂ importĂ©e). Relancez votre stack et, aprĂšs quelques instants, vous pourrez vous connecter au webservice de lâinstance. Utilisez lâIP qui sâaffiche dans votre terminal aprĂšs un cdktf deploy
.
Configuration des disques (bonus)
Actuellement, lâinstance créée nâa quâun disque de 8 Go. Câest suffisant, mais il est possible de changer cela via Terraform. Par exemple, ajoutez ce bout de code Ă votre instance.
ebs_block_device= [InstanceEbsBlockDevice(
device_name="/dev/sda1",
delete_on_termination=True,
encrypted=False,
volume_size=20,
volume_type="gp2"
),
InstanceEbsBlockDevice(
device_name="/dev/sdb",
delete_on_termination=True,
encrypted=False,
volume_size=100,
volume_type="gp2"
)]
Le premier disque de lâinstance aura ainsi un volume de 20 Go, et un second disque sera attachĂ© avec un volume de 100 Go. Les deux disques seront supprimĂ©s en mĂȘme temps que lâinstance. Vous pouvez voir les deux disques en vous connectant Ă lâinstance en SSH et en exĂ©cutant la commande df -h
(disk free).
Mise en place dâun Auto Scaling Group et dâun Load Balancer
Ci-dessous, vous trouverez lâarchitecture finale que vous allez mettre en place pour ce TP. Elle est un peu plus dĂ©taillĂ©e que lors du prĂ©cĂ©dent TP pour faire apparaĂźtre chaque Ă©lĂ©ment que vous allez devoir dĂ©finir. Se dĂ©tacher de lâinterface graphique pour utiliser un outil IaC fait rĂ©aliser Ă quel point la console AWS masque de nombreux dĂ©tails. Tout implĂ©menter nâest pas difficile, mais est laborieux quand on nâest pas guidĂ©. Toutes les Ă©tapes sont dĂ©coupĂ©es pour ĂȘtre unitaires et simples. Elles consistent toutes Ă dĂ©finir un objet Python avec la bonne classe et les bons paramĂštres. Ce nâest pas simple de trouver cela seul, alors je vous donne tout. Il suffit de suivre le TP Ă votre rythme.
Vous trouverez le code de cet exercice dans le dossier ex 2 cdktf haute dispo
.
Launch Template
La premiĂšre Ă©tape va ĂȘtre de dĂ©finir le template des instances de lâAuto Scaling Group. Pour cela, vous allez utiliser la classe LaunchTemplate
. Comme un template est quasiment la mĂȘme chose quâune instance, lâobjet LaunchTemplate
va fortement ressembler Ă une instance, seuls les noms des paramĂštres vont changer (oui, il nây a pas de cohĂ©rence sur les noms). Ainsi, votre objet LaunchTemplate
va avoir comme paramĂštres :
- la stack courante,
- un id sous la forme dâun string,
-
image_id
qui va définir son image AMI, -
instance_type
qui va dĂ©finir le type dâinstance, -
user_data
qui va dĂ©finir les user data. Attention, mĂȘme si ce nâest pas prĂ©cisĂ©, elles doivent bien ĂȘtre encodĂ©es en base 64, -
vpc_security_group_ids
au lieu desecurity_groups
pour la liste des security groups, -
key_name
pour la clé SSH à utiliser.
Auto Scaling Group
Maintenant que le template est dĂ©fini, câest le moment de lâutiliser avec un Auto Scaling Group. Souvenez-vous, un Auto Scaling Group va maintenir un nombre dâinstances compris entre le min et le max dĂ©fini. La classe qui reprĂ©sente un ASG est simplement AutoscalingGroup
. Elle prend en paramĂštres :
- la stack courante,
- un id sous la forme dâun string,
-
min_size
,max_size
etdesired_capacity
pour la limite inférieure, supérieure, et la valeur initiale, -
launch_template
qui permet de spécifier le template à utiliser. Vous pouvez passer un dictionnaire contenant uniquement la cléid
avec comme valeur lâid du launch template que vous obtiendrez avec lâattributid
du launch template, -
vpc_zone_identifier
pour spĂ©cifier les sous-rĂ©seaux Ă utiliser pour lâAuto Scaling Group. Utilisez la variablesubnets
présente dans le fichier.
Il ne vous reste plus quâĂ lancer votre code. Il va crĂ©er les sous-rĂ©seaux nĂ©cessaires, un Launch Template et un ASG selon vos spĂ©cifications. Attendez quelques instants puis allez sur le tableau de bord EC2, vous devriez voir apparaĂźtre 3 instances.
Elastic Load Balancer
DerniĂšre piĂšce Ă dĂ©finir, le Load Balancer va avoir la charge de rĂ©partir les requĂȘtes entre les instances. La crĂ©ation via lâinterface a cachĂ© pas mal de choses et, au lieu de crĂ©er un simple objet, il faut en crĂ©er 3 :
- le Load Balancer en tant que tel,
- le Target Group qui va permettre de considĂ©rer lâASG comme une cible possible pour le Load Balancer,
- et un Load Balancer Listener pour relier les deux.
Load Balancer
Définir le Load Balancer est assez simple. Cela se fait avec la classe Lb
. En plus des classiques stack courante et id, elle prend en paramĂštre :
- son type avec le paramĂštre
load_balancer_type
. Dans le cas prĂ©sent, cela sera âapplicationâ, - les sous-rĂ©seaux avec lesquels il communique avec le paramĂštre
subnets
. Prenez la valeursubnets
déjà définie, - et les groupes de sécurité qui lui sont associés avec le paramÚtre
security_groups
. Le security group déjà défini convient trÚs bien. Attention, ce paramÚtre attend une liste.
Target Group
Le Target Group est également facile. Utilisez la classe LbTargetGroup
et passez la stack et un id. Il vous faut ensuite définir les paramÚtres :
-
port
en spécifiant le port 80 etprotocol
en spécifiantHTTP
car nous voulons que le TG soit accessible uniquement en HTTP sur le port 80, -
vpc_id
avec lâid du VPC dĂ©jĂ dĂ©fini. Cela est nĂ©cessaire car cela permet Ă AWS de savoir que les machines du Target Group seront dans le rĂ©seau.
Il faut maintenant associer votre Target Group Ă votre ASG. Cela passe par lâajout dâun attribut target_group_arns
dans lâASG. Cet attribut attend la liste des ARN (Amazon Resource Names) des Target Groups. Votre Target Group expose son ARN via lâattribut arn
.
Load Balancer Listener
Il ne nous reste plus quâĂ dire au Load Balancer de forwarder les requĂȘtes HTTP vers notre Target Group. Il faut utiliser lâobjet LbListener
pour ça. Il prend, en plus des paramÚtres habituels :
-
load_balancer_arn
qui est lâarn du Load Balancer. Pour rĂ©cupĂ©rer lâarn de votre Load Balancer, utilisez lâattributarn
, -
port
qui va prendre la valeur 80 car nous allons forwarder les requĂȘtes faites sur le port 80, -
protocol
qui va prendre la valeur HTTP car nous allons forwarder les requĂȘtes HTTP, -
default_action
oĂč nous allons dire ce que nous voulons faire, ici forwarder les requĂȘtes vers notre Target Group. Comme un Load Balancer Listener peut avoir plusieurs actions, ce paramĂštre attend une liste. Ensuite, notre action de forward va se dĂ©finir via un autre objet dont voici le codeLbListenerDefaultAction(type="forward", target_group_arn=target_group.arn)
.
Vous pouvez maintenant relancer votre code avec un cdktf deploy
, allez sur la page du load balancer, obtenir son adresse dns et accéder au endpoint /instance
. RafraĂźchissez la page et lâID affichez devrait changer rĂ©guliĂšrement.
Conclusion
Vous venez lors de ce TP de crĂ©er via du code toute une infrastructure informatique. MĂȘme si cela nâest pas simple Ă faire, le code que vous avez Ă©crit peut ĂȘtre maintenant rĂ©utiliser Ă volontĂ© et versionnĂ© via git. Il est ainsi partageable, et vous pouvez voir son Ă©volution. Il peut Ă©galement ĂȘtre utilisĂ© dans un pipeline de CI/CD pour que lâarchitecture soit dĂ©ployĂ©e automatiquement.
MĂȘme si les solutions IaC ont des avantages, je ne vous les recommande pas pour dĂ©couvrir un service. Explorer lâinterface dans un premier temps pour voir les options disponibles permet de mieux comprendre le service. Automatiser la crĂ©ation de services via du code par la suite si câest nĂ©cessaire.