TP 2 - Ope Tofu đŸȘ 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, validez à vide, et faites pareil pour la Secret AccessKey. Cherchez le dossier caché .aws (dans votre dossier personnel sous Linux et Mac, dans votre dossier user sur windows) et collez le contenu de AWS CLI dans le fichier credentials.

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.

Mon premier script avec OpenTofu

Une instance de base

Ouvrez le fichier instance.tf. Il contient l’architecture minimale du code nĂ©cessaire pour que vous puissiez rĂ©aliser le TP.

provider "aws" {
  region = "us-east-1"
}


# Pour récupérer l'IP de la VM
output "instance_public_ip" {
  description = "Adresse IP publique de l'instance EC2"
  value       = aws_instance.ubuntu_vm.public_ip
}

Maintenant, vous allez dĂ©finir votre premiĂšre ressource. Elle sera de type aws_instance et vous l’appelerez ubuntu_vm. Le doc complĂšte de cette ressource se trouve ici : https://search.opentofu.org/provider/hashicorp/aws/latest/docs/resources/instance

Ensuite, via des paramĂštres, 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 t3.micro. ExĂ©cutez votre architecture avec la commande tofy apply 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 :

resource "aws_security_group" "web_sg" {
  name        = "web-sg"
  description = "Autorise SSH (22) et HTTP (80) en entrée, tout en sortie"
  vpc_id      = data.aws_vpc.default.id

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    description = "Tout trafic sortant"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web-sg"
  }
}

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 d’id de Security Groups. pour rĂ©cupĂ©rer l’id fait simplement aws_security_group.web_sg.id. Et pour avoir une liste, mettez le tout entre [] 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 tofu apply. 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 OpenTofu. Par exemple, ajoutez ce bout de code Ă  votre instance.

# Disque principal (root)
root_block_device {
    volume_size = 20
    volume_type = "gp3"
}
ebs_block_device {
    device_name = "/dev/sdf"   # nom logique dans EC2
    volume_size = 100
    volume_type = "gp3"
    delete_on_termination = true
}

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 opentofu 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 ressource aws_launch_template. Comme un template est quasiment la mĂȘme chose qu’une instance, l’objet aws_launch_template 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 aws_launch_template va avoir comme paramĂštres :

  • 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 de security_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 aws_autoscaling_group. Elle prend en paramĂštres :

  • min_size, max_size et desired_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 les clĂ© id avec comme valeur l’id du launch template que vous obtiendrez avec l’attribut id du launch template (aws_launch_template.non_de_votre_lauche_template.id) et la clĂ© version que vous mettrez Ă  "$Latest" ,
  • vpc_zone_identifier pour spĂ©cifier les sous-rĂ©seaux Ă  utiliser pour l’Auto Scaling Group. Utilisez la variable subnets 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 ressource aws_lb. 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 valeur subnets 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 et protocol en spĂ©cifiant HTTP 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 aws_lb_listener 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’attribut arn,
  • 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. Vous allez mettre
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.votre_target_groupe.arn
  }

Vous pouvez maintenant relancer votre code avec un tofu apply, 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.