Infrastructure As Code sous AWS avec Terraform

Magazine
Marque
GNU/Linux Magazine
Numéro
216
Mois de parution
juin 2018
Spécialité(s)


Résumé

Dans cet article, je vous propose de plonger au cœur de Terraform, outil permettant d’automatiser le déploiement d’infrastructures complètes sur des plateformes IaaS avec un langage de description simple et flexible.


Body

 

Ces dernières années, de nombreux outils sont apparus visant à rapprocher les méthodes de travail des développeurs de celles des sysadmins dans le but d’automatiser, de simplifier et de sécuriser les déploiements. Des outils comme Puppet, Salt, Chef ou Ansible ont ainsi rapidement émergé pour l’administration des systèmes d’exploitation et des applications.

Alors que le Cloud et la généralisation des API se sont développés, sont apparus cette fois des outils similaires pour l’orchestration de l’infrastructure socle. Plutôt que de déployer manuellement, nous allons pouvoir travailler avec des documents textuels décrivant l’état du système souhaité, intégrables dans des systèmes de gestion de version de type GIT et bénéficier des avantages qui s’ensuivent.

Terraform s’inscrit dans cette démarche en fournissant des interfaces vers plusieurs clouds : Azure, Google, OpenStack, AWS, etc. C’est ce dernier que je vais utiliser pour la démonstration. Il sera donc nécessaire de disposer d’un compte AWS, sachant qu’un compte gratuit est suffisant pour explorer l’ensemble des éléments que nous allons parcourir. Qui dit interface ne dit cependant pas abstraction, chaque cloud (provider) possède ses caractéristiques et Terraform ne propose pas de passer de l’un à l’autre sans réécriture massive du code.

Alors que des outils tels que Puppet ou Ansible disposent de modules vers plusieurs clouds publics, leur finalité est tournée vers la gestion de configuration. Terraform ou CloudFormation (l’outil proposé par Amazon) sont orientés orchestration d’infrastructures et s’acquitteront mieux de la tâche. Ainsi, il n’est pas nécessaire dans le code d’écrire les dépendances entre les éléments, ce que l’on ferait avec Puppet par exemple. C’est l’orchestrateur de Terraform qui se charge de réaliser le graphe de séquencement à votre place.

1. Déploiement d’une première machine virtuelle

1.1 Préparation de l’environnement

L’installation de Terraform ne saurait être plus simple. En effet, Terraform est écrit en Go et est distribué sous la forme d’un binaire compilé en statique. Il suffit de télécharger le zip de l’application et une fois celui-ci extrait, s’assurer que le binaire se trouve bien dans le PATH :

$ curl -O https://releases.hashicorp.com/terraform/0.11.2/terraform_0.11.2_linux_amd64.zip

$ unzip terraform_0.11.2_linux_amd64.zip

$ cp terraform /usr/local/bin

Afin de pouvoir dialoguer avec l’API AWS, il est nécessaire d’avoir préalablement créé un compte Programmatic Access sur le portail AWS. Nous allons ensuite pouvoir définir dans un fichier main.tf les credentials obtenus pour la région souhaitée, pour ma part il s’agit de la région eu-west-3. Une région est une zone géographique dans laquelle l’infrastructure sera déployée. Une région dispose elle-même de plusieurs datacenters regroupés en zones de disponibilité. Bien répartir une infrastructure au sein des zones de disponibilité permet de disposer du meilleur taux de disponibilité possible. La région eu-west-3 correspond à la nouvelle région France. Cela va sans dire, ce fichier doit être protégé au plus haut niveau.

provider "aws" {

  access_key = "ABCD1234J54PXLDF4IC4WMVA"

  secret_key = "28prpojfngldfgPcgiv79Q/J+8o7ksdfsTjmmE2QQBRa"

  region     = "eu-west-3"

}

On va enfin pouvoir lancer la commande terraform init qui va permettre d’instancier notre environnement et indiquer à Terraform qu’il aura besoin du plugin aws :

$ terraform init

Initializing provider plugins...

- Checking for available provider plugins on https://releases.hashicorp.com...

- Downloading plugin for provider "aws" (1.7.1)...

The following providers do not have any version constraints in configuration,

so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking

changes, it is recommended to add version = "..." constraints to the

corresponding provider blocks in configuration, with the constraint strings

suggested below.

* provider.aws: version = "~> 1.7"

[...]

1.2 Instanciation d’une VM :

Une VM AWS est une ressource de type Instance EC2. Pour déployer une VM dans cet environnement, il suffit de déclarer trois éléments, un nom, un modèle de dimensionnement de serveur et enfin un modèle de système d’exploitation. Voici donc à quoi ressemble notre fichier hosts.tf contenant ces éléments élémentaires :

resource "aws_instance" "srv1" {

  ami = "ami-8ee056f3"

  instance_type = "t2.micro"

  tags {

    Name = "srv1"

  }

}

L’étape suivante consiste à générer le fichier de plan. Terraform va entreprendre de lister les étapes nécessaires pour arriver à l’état décrit dans les fichiers de configuration.

$ terraform plan -out=terraform.plan

Refreshing Terraform state in-memory prior to plan...

The refreshed state will be used to calculate this plan, but will not be

persisted to local or remote state storage.

------------------------------------------------------------------------

An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

  + create

Terraform will perform the following actions:

  + aws_instance.srv1

      id:                           <computed>

      ami:                          "ami-8ee056f3"

[...]

      instance_type:                "t2.micro"

[...]

Plan: 1 to add, 0 to change, 0 to destroy.

À ce stade, Terraform n’a encore poussé aucune modification sur le tenant AWS. La génération du plan est justement l’étape de revue des changements avant validation en production ou intégration au système de gestion de version. En cas de modification concurrente, jouer un plan plutôt que d’appliquer les configurations en cours permet de s’assurer de ce qui sera précisément déroulé. Pour déployer les changements, il faut appliquer le plan :

$ terraform apply terraform.plan

aws_instance.srv1: Creating...

  ami:                          "" => "ami-8ee056f3"

  [...]

aws_instance.srv1: Still creating... (10s elapsed)

aws_instance.srv1: Creation complete after 15s (ID: i-06d8b2e3fcd42e3c6)

 

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Voilà, en seulement 15 lignes de code, nous nous sommes connectés à notre infrastructure AWS et nous avons créé notre premier serveur.

1.3 Connexion SSH

Notre VM est déployée dans notre cloud AWS, elle dispose d’une adresse IP publique, toutefois, il ne nous est pas possible encore de nous y connecter. Il nous manque en effet deux choses, une règle de firewall dans notre Security Group AWS autorisant les connexions SSH ainsi qu’une clé RSA pour l’authentification par clé publique. Il faut savoir que dans une infrastructure AWS, le filtrage est réalisé au niveau de l’enveloppe de la machine virtuelle via le Security Group. Un Security Group contient une ou plusieurs règles de filtrage et le même groupe peut être affecté à plusieurs instances.

Définissons donc un fichier securitygroups.tf pour autoriser le SSH entrant depuis notre adresse IP :

resource "aws_security_group" "sg_ssh" {

  name = "sg_ssh"

  description = "Permettre le SSH depuis mon IP"

  ingress {

    from_port = 22

    to_port   = 22

    protocol  = "tcp"

    cidr_blocks = ["1.2.3.4/32"]

  }

  egress {

    from_port = 0

    to_port   = 0

    protocol  = "-1"

    cidr_blocks = ["0.0.0.0/0"]

  }

}

Dans un second fichier sshkeys.tf, nous allons indiquer notre clé publique ssh préalablement générée avec la commande ssh-keygen :

resource "aws_key_pair" "sshdeploy" {

  key_name   = "aws-ssh-key"

  public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCw/0DWBotXagD8mHGge0AcbaSIOadyJ6L65BGt99OoeRcZaYzCa2djY1dPCTUOtjbUrm7bLO8Yg7YePivJEEbnke2SbEJ8g2ClJ5tpmVV84v7TyVAcU1EcAM81h/NLEdm9jC6bPp0I0bgiTNtqypPZNPRN9V5HPG9xmHpotg05irkbhtGiNRQ3hmFsFOKkvz4Ch27s8oFIYyy0juUxWnqByV5XfW32rcBt5u4UkKGdMNi/KXlHJPCkp6WgZsTFuIiHi0RgHrRQUuKn5i+0lKePKtlb7fS2IukKLVfrJwc76AxfJ0C9UZj4KRcd/dtu6Wtt4oMRKgQxqRyjpfkGfT9j julien@private"

}

Notre clé publique SSH et notre Security Group sont des définitions de ressources réutilisables dans plusieurs composants EC2. Nous allons désormais les appliquer à l’instance précédemment déployée. Le fichier hosts.tf devient donc :

resource "aws_instance" "srv1" {

  ami = "ami-8ee056f3"

  instance_type = "t2.micro"

  key_name = "aws-ssh-key"

  tags {

    Name = "srv1"

  }

  security_groups = ["${aws_security_group.sg_serveurs.name}"]

}

Relançons notre plan pour voir comment Terraform se comporte :

$ terraform plan -out=terraform.plan

Refreshing Terraform state in-memory prior to plan...

The refreshed state will be used to calculate this plan, but will not be

persisted to local or remote state storage.

aws_instance.srv1: Refreshing state... (ID: i-06d8b2e3fcd42e3c6)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

  + create

-/+ destroy and then create replacement

 

Terraform will perform the following actions:

-/+ aws_instance.srv1 (new resource required)

      id:                                    "i-06d8b2e3fcd42e3c6" => <computed> (forces new resource)

[...]

      security_groups.3547975260:            "" => "sg_serveurs" (forces new resource)

      security_groups.3814588639:            "default" => "" (forces new resource)

[...]

  + aws_key_pair.sshdeploy

[...]

  + aws_security_group.sg_serveurs

[...]

Plan: 3 to add, 0 to change, 1 to destroy.

------------------------------------------------------------------------

This plan was saved to: terraform.plan

To perform exactly these actions, run the following command to apply:

    terraform apply "terraform.plan"

Le plan nous apprend qu'il va ajouter deux éléments : les security group et la clé SSH. Il nous apprend surtout que pour pouvoir mettre en œuvre les éléments requis, il devra supprimer la VM et la recréer.

Un terraform apply plus tard, il est désormais possible de se connecter à la machine recréée. Pour retrouver l’adresse IP de la VM nouvellement déployée pour s’y connecter, c’est simple, elle est stockée dans le fichier tfstate :

$ grep public_ip terraform.tfstate

                            "associate_public_ip_address": "true",

                            "public_ip": "52.47.127.27",

Le compte utilisateur à utiliser se nomme ec2-user qui est le compte par défaut :

$ ssh ec2-user@52.47.127.27

The authenticity of host '52.47.127.27 (52.47.127.27)' can't be established.

ECDSA key fingerprint is SHA256:Vct9yEmZjaLCHHI/Da3sfQkQ1uS+oKN2jmh/HYCFI/A.

Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '52.47.127.27' (ECDSA) to the list of known hosts.

       __|  __|_  )

       _|  (     /   Amazon Linux AMI

      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/

1 package(s) needed for security, out of 1 available

Run "sudo yum update" to apply all updates.

1.4 Ajout d’un volume à notre instance

L’ajout d’un volume ESB (Elastic Block Storage) se fait en deux étapes. Premièrement, il faut créer le volume avec la volumétrie attendue et dans une seconde déclaration, il faut attacher ce volume à l’instance EC2. Ajoutons donc ces lignes à notre fichiers hosts.tf :

resource "aws_volume_attachment" "ebs_att" {

  device_name = "/dev/xvdb"

  volume_id   = "${aws_ebs_volume.www_srv1.id}"

  instance_id = "${aws_instance.srv1.id}"

}

resource "aws_ebs_volume" "www_srv1" {

  availability_zone = "${aws_instance.example.availability_zone}"

  size              = 10

}

Il suffit de lancer les commandes terraform plan et terraform apply décrites plus haut pour lancer le déploiement.

Pour l’attachement du volume, Terraform est capable de récupérer son id via une variable qu’il définit (aws_ebs_volume.www_srv1.id) obtenue depuis le type de ressource et le nom de celle-ci.

Il est également possible d’attacher un volume directement dans une ressource aws_instance :

  ebs_block_device {

    device_name = "/dev/xvdb"

    volume_size = 10

  }

Toutefois, dans cette configuration, Terraform va procéder à une nouvelle création de la ressource  aws_instance au lieu de créer une ressource EBS et de faire un appel à Attach pour la lier à l’instance. Il est donc important de vérifier ce que le plan va réaliser sur celle-ci.

1.5 Ajout de la post installation

À l’issue du déploiement de l’instance, AWS permet d’exposer un script de post-installation via l’attribut user_data qui est passé à la VM lors de son premier démarrage via le service de métadonnées. Celui-ci est accédé par l’instance via une requête sur l’adresse http://169.254.169.254/latest/meta-data/. Ces scripts permettent de manière non exhaustive de réaliser les tâches suivantes :

  • mise à jour du système ;
  • déploiement d’un agent de gestion de configuration type Puppet ou Chef ;
  • installation de paquets ;
  • création de comptes utilisateurs ;
  • configurer le gestionnaire de paquets ;
  • commandes shell, etc.

Deux modes opératoires sont supportés, un simple script bash conventionnel ou Cloud Init qui permet d’exploiter un langage de description de plus haut niveau et donc de s’affranchir jusqu’à un certain point de la distribution. Inconvénient cependant, certaines commandes peuvent faire doublon avec Puppet ou Chef. Petit bémol avec AWS, l’instance Cloud Init proposée n’embarque pas l’ensemble des fonctionnalités de l’outil.

Je vous propose à titre d’illustration ce court exemple qui met à jour les packages et installe quelques paquets élémentaires.

#cloud-config

# Mise à jour des packages

repo_update: true

repo_upgrade: true

packages:

 - screen

 - htop

 - httpd

runcmd:

 - service httpd start

 - chkconfig httpd on

code

On ajoute également dans la déclaration de notre ressource aws_instance une indication précisant que le service de métadonnées doit être contacté. La déclaration de l’instance devient donc :

resource "aws_instance" "srv1" {

  ami = "ami-8ee056f3"

  instance_type = "t2.micro"

  key_name = "aws-ssh-key"

  tags {

    Name = "srv1"

  }

  security_groups = ["${aws_security_group.sg_serveurs.name}"]

  user_data = "${file("postinstall.yml")}"

}

Naturellement, il faudra passer par le couple terraform plan et terraform apply pour déployer une nouvelle instance disposant de cette post install. Afin d’identifier une anomalie à la post installation, il est possible de rajouter cette ligne dans le fichier afin de générer un log :

output : { all : '| tee -a /var/log/cloud-init-output.log' }

1.6 Fin de partie

L’une des fonctionnalités essentielles de Terraform réside dans sa capacité à gérer l’ensemble du cycle de vie du projet décrit dans les configurations. Nous avons vu précédemment les étapes de provisionning et de mise à jour, la dernière phase du cycle de vie consiste à détruire l’infrastructure lorsqu’elle n’est plus utilisée. Comme Terraform maintient la liste des ressources qu’il gère, il est simple pour lui de construire le graphe de suppression de celles-ci. De plus, Terraform ne touchera que les ressources qu’il gère directement.

Contrairement à un outil comme Chef ou Puppet qui va demander de positionner une condition de suppression sur chacune des ressources gérées, Terraform gère les actions au niveau global via une simple commande (nécessitant heureusement une confirmation) terraform destroy :

$ terraform destroy

[...]

An execution plan has been generated and is shown below.

Resource actions are indicated with the following symbols:

  - destroy

Terraform will perform the following actions:

  - aws_ebs_volume.www_srv1

  - aws_instance.srv1

  - aws_key_pair.sshdeploy

  - aws_security_group.sg_serveurs

  - aws_volume_attachment.ebs_att

Plan: 0 to add, 0 to change, 5 to destroy.

Do you really want to destroy?

  Terraform will destroy all your managed infrastructure, as shown above.

  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

[...]

Destroy complete! Resources: 5 destroyed.

2. Une infrastructure complète

Jusqu’ici nous avons joué avec une unique machine virtuelle afin d’effleurer les possibilités de l’outil. Voyons au travers d’un projet plus réaliste et pertinent l’utilisation de cet outil. Je vous propose ainsi de  mettre en œuvre un réseau dédié hébergeant deux serveurs web, un load balancer frontal, la gestion du DNS et enfin une base de données MariaDB en mode Database As A Service.

2.1 Mettons en place le réseau

Pour ce nouveau projet, nous allons conserver nos deux fichiers main.tf et sshkeys.tf. Je tiens à préciser que les noms de fichiers que j’ai donnés jusqu’ici n’ont rien d’impératif, mais sont là pour donner un semblant d’organisation. Commençons par déclarer un VPC, pour Virtual Private Cloud, c’est-à-dire un réseau isolé et dédié, avec une passerelle par défaut pour les instances qui seront déployées par la suite.

resource "aws_vpc" "vpc_main" {

  cidr_block = "172.16.0.0/16"

  enable_dns_support = true

  enable_dns_hostnames = true

}

resource "aws_internet_gateway" "default" {

  vpc_id = "${aws_vpc.vpc_main.id}"

}

resource "aws_route" "wan_access" {

  route_table_id          = "${aws_vpc.vpc_main.main_route_table_id}"

  destination_cidr_block  = "0.0.0.0/0"

  gateway_id              = "${aws_internet_gateway.default.id}"

}

Ce VPC disposera de deux réseaux que nous allons explicitement placer dans deux zones de disponibilité au sein de la région eu-west.

resource "aws_subnet" "webservers-a" {

  vpc_id                  = "${aws_vpc.vpc_main.id}"

  cidr_block              = "172.16.10.0/24"

  map_public_ip_on_launch = true

  availability_zone = "eu-west-3a"

}

resource "aws_subnet" "webservers-b" {

  vpc_id                  = "${aws_vpc.vpc_main.id}"

  cidr_block              = "172.16.20.0/24"

  map_public_ip_on_launch = true

  availability_zone = "eu-west-3b"

}

2.2 Des variables

Afin de factoriser notre code, nous allons procéder à un début de définition de variables. En pratique, il serait souhaitable de maximiser l’utilisation des variables au sein de vos configurations Terraform. Par souci de lisibilité, je ne les ai pas utilisées jusqu’ici et je les présente pour ouvrir des perspectives au lecteur.

variable "http_port" {

  description = "Port pour les requêtes HTTP"

  default = 80

}

variable "ssh_port" {

  description = "Port pour les requêtes SSH"

  default = 22

}

variable "mariadb_port" {

  description = "Port pour les connexions MariaDB"

  default = 3306

}

2.3 Déclarons deux instances

Maintenant que nos réseaux sont en place, nous allons pouvoir y positionner un serveur web sur chacun d’entre eux. Je déroge aux bonnes pratiques en affectant une adresse IP publique à ces instances. Le but étant de vous permettre d’y accéder simplement. Par souci de simplicité, le user_data est un simple script shell.

resource "aws_instance" "www-a" {

  ami = "ami-8ee056f3"

  instance_type = "t2.micro"

  key_name = "aws-ssh-key"

  vpc_security_group_ids = ["${aws_security_group.sg_www.id}"]

  user_data = <<EOF

#!/bin/bash

yum -y update

yum -y install httpd

chkconfig httpd on

service httpd start

EOF

  subnet_id              = "${aws_subnet.webservers-a.id}"

  associate_public_ip_address = "true"

}

resource "aws_instance" "www-b" {

  ami = "ami-8ee056f3"

  instance_type = "t2.micro"

  key_name = "aws-ssh-key"

  vpc_security_group_ids = ["${aws_security_group.sg_www.id}"]

  user_data = <<EOF

#!/bin/bash

yum -y update

yum -y install httpd

chkconfig httpd on

service httpd start

EOF

  subnet_id              = "${aws_subnet.webservers-b.id}"

  associate_public_ip_address = "true"

}

resource "aws_security_group" "sg_www" {

  name = "sg_www"

  vpc_id = "${aws_vpc.vpc_main.id}"

  ingress {

    from_port = "${var.http_port}"

    to_port   = "${var.http_port}"

    protocol  = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  ingress {

    from_port = "${var.ssh_port}"

    to_port   = "${var.ssh_port}"

    protocol  = "tcp"

    cidr_blocks = ["1.2.3.4/32"]

  }

  ingress {

    from_port   = 0

    to_port     = 0

    protocol    = "icmp"

    cidr_blocks = ["0.0.0.0/0"]

  }

2.4 Ajoutons un équilibreur de charge

Enfin, on peut déclarer notre équilibreur de charge ou Elastic Load Balancer en langage AWS. Il est raccroché aux deux sous-réseaux avec nos deux instances précédentes en backend.

resource "aws_elb" "http-lb" {

  name = "http-lb"

  subnets = ["${aws_subnet.webservers-a.id}","${aws_subnet.webservers-b.id}"]

  security_groups = ["${aws_security_group.sg_elb.id}"]

  instances       = ["${aws_instance.www-a.id}", "${aws_instance.www-b.id}"]

  listener {

    lb_port = "${var.http_port}"

    lb_protocol = "http"

    instance_port = "${var.http_port}"

    instance_protocol = "http"

  }

  health_check {

    healthy_threshold = 2

    unhealthy_threshold = 2

    timeout = 3

    interval = 5

    target = "TCP:${var.http_port}"

  }

}

resource "aws_security_group" "sg_elb" {

  name = "sg_elb"

  vpc_id = "${aws_vpc.vpc_main.id}"

  ingress {

    from_port = "${var.http_port}"

    to_port   = "${var.http_port}"

    protocol  = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  ingress {

    from_port   = 0

    to_port     = 0

    protocol    = "icmp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  egress {

    from_port = 0

    to_port   = 0

    protocol  = "-1"

    cidr_blocks = ["0.0.0.0/0"]

  }

  lifecycle {

    create_before_destroy = true

  }

}

Comme vous avez dû vous en rendre compte, les instances sont raccrochées à un sous domaine AWS, dans mon cas eu-west-3.compute.amazonaws.com. Plutôt qu’aller ouvrir le portail EC2 ou utiliser la peu appropriée commande grep que je vous ai fait utiliser précédemment, nous allons utiliser la fonctionnalité des outputs. Ainsi, à l’issue de l’instanciation de la ressource ELB, nous allons afficher son FQDN afin de pouvoir valider simplement le bon fonctionnement.

output "elb_dns_name" {

  value = "${aws_elb.http-lb.dns_name}"

}

À ce stade, si vous appliquez votre plan, l’accès à l’adresse renvoyée par Terraform doit déjà vous permettre d’afficher une belle « Amazon Linux AMI Test Page ».

2.5 Du DNS as a Service

Le DNS AWS c’est plutôt sympathique, mais dans la vie réelle, les utilisateurs accèdent aux ressources avec un nom de domaine personnalisé. AWS propose un service de DNS as a Service appelé Route53. Il existe une notion de DNS privé pour les ressources internes du VPC ou de DNS public pour les ressources exposées. Nous allons déclarer le sous-domaine aws.domaine.fr à adapter avec votre propre domaine et déclarer des enregistrements de ressources sur chacune des adresses IP de notre infrastructure. Bien évidemment, pour que ce soit fonctionnel, il faut également déclarer une délégation DNS dans la zone supérieure vers les DNS AWS, ce qui sort du cadre de cet article.

resource "aws_route53_zone" "publicdns" {

  name         = "aws.domaine.fr"

}

resource "aws_route53_record" "www-a" {

  zone_id = "${aws_route53_zone.publicdns.zone_id}"

  name    = "www-a.aws.domaine.fr"

  type    = "A"

  ttl = "60"

  records = ["${aws_instance.www-a.public_ip}"]

}

resource "aws_route53_record" "www-b" {

  zone_id = "${aws_route53_zone.publicdns.zone_id}"

  name    = "www-b.aws.morot.fr"

  type    = "A"

  ttl = "60"

  records = ["${aws_instance.www-b.public_ip}"]

}

resource "aws_route53_record" "www" {

  zone_id = "${aws_route53_zone.publicdns.zone_id}"

  name = "www.aws.domaine.fr"

  type = "CNAME"

  ttl = "60"

  records = ["${aws_elb.http-lb.dns_name}"]

}

2.6 Et enfin notre base de données

L’application web déployée sur nos deux instances utilisera une base de données et par conséquent nous allons utiliser le service AWS Relational Database as a Service ou RDS.

L’utilisation du service RDS implique trois ressources, la déclaration des subnet groups dans lesquels seront rattachés vos instances RDS, par simplicité je réutilise les réseaux des instances, mais de manière optimale il faudrait dédier un subnet.

resource "aws_db_subnet_group" "rds_subnet" {

    name = "rds_subnet_grpp"

    subnet_ids = ["${aws_subnet.webservers-a.id}","${aws_subnet.webservers-b.id}"]

}

Nous  déclarons ensuite notre base de données à proprement parler avec les identifiants d’accès et son type. Une particularité est le final snapshot. C’est-à-dire qu’à la suppression de la base de données RDS, AWS réalisera un instantané de celle-ci pouvant être restauré. Ce snapshot n’est donc pas supprimé par Terraform.

resource "aws_db_instance" "myawsdb" {

  allocated_storage    = 20

  engine               = "mariadb"

  engine_version       = "10.1.26"

  instance_class       = "db.t2.micro"

  name                 = "myawsdb"

  username             = "user"

  password             = "password"

  db_subnet_group_name = "${aws_db_subnet_group.rds_subnet.id}"

  skip_final_snapshot = false

  multi_az = true

  final_snapshot_identifier = "myawsdbfinalsnap"

  vpc_security_group_ids = ["${aws_security_group.sg_rds.id}"]

}

Et enfin, nous avons notre security group pour autoriser le port TCP/3306 depuis l’ensemble des subnets de notre VPC.

resource "aws_security_group" "sg_rds" {

  name = "sg_rds"

  vpc_id = "${aws_vpc.vpc_main.id}"

  ingress {

    from_port = "${var.mariadb_port}"

    to_port   = "${var.mariadb_port}"

    protocol  = "tcp"

    cidr_blocks = ["172.16.0.0/16"]

  }

  egress {

    from_port = 0

    to_port   = 0

    protocol  = "-1"

    cidr_blocks = ["0.0.0.0/0"]

  }

  lifecycle {

    create_before_destroy = true

  }

}

2.7 Étape finale !

Voilà, nous avons progressivement construit notre infrastructure. Que vous ayez tout décrit dans un fichier dédié ou éclaté la configuration n’a pas d’importance, mais juste une bonne pratique pour améliorer la lisibilité sur des infrastructures importantes.

Il vous reste juste à lancer les commandes connues jusqu’ici :

$ terraform init

$ terraform plan -out=terraform.plan

$ terraform apply terraform.plan

Pensez à l’issue de l’expérimentation à faire un destroy pour ne pas être facturé au-delà de ce qui est permis dans l’utilisation du compte gratuit AWS.

Conclusion

J’espère que vous aurez apprécié la puissance d’un tel outil. Dans la continuité de cet article, je vous propose de poursuivre avec les auto scaling groups afin de permettre à votre infra d’évoluer automatiquement pour suivre les besoins de montée en charge, exploiter une supervision CloudWatch, un VPN site à site vers votre VPC et pousser une NAT Gateway pour supprimer les adresses IP publiques inutiles ou encore faire cohabiter votre outil de gestion de configuration à l’issue de la post-installation.

 



Article rédigé par

Par le(s) même(s) auteur(s)

Galera, la solution pour des bases de données hautement disponibles

Magazine
Marque
Linux Pratique
Numéro
137
Mois de parution
mai 2023
Spécialité(s)
Résumé

Lorsqu’une application ne peut tolérer d’indisponibilités ou quand il devient nécessaire de fournir de la redondance au service de bases de données, il convient de mettre en place une architecture limitant les risques d’interruption de service. De même, le besoin de performance peut se faire sentir avec la croissance du nombre d’utilisateurs. Galera est une extension pour MariaDB aidant à résoudre ces deux situations.

Gérez votre stockage avec Stratis

Magazine
Marque
Linux Pratique
Numéro
128
Mois de parution
novembre 2021
Spécialité(s)
Résumé

Quand on parle de gestion du stockage local à un administrateur système Linux, il est généralement question de LVM et de filesystem XFS ou ext4. À un niveau plus évolué, on trouvera ZFS qui n'est pas libre ou bien Btrfs qui tarde à tenir ses promesses. Stratis a pour vocation de proposer quelque chose de neuf avec l’existant !

Déployer des environnements de développement avec Vagrant

Magazine
Marque
Linux Pratique
Numéro
127
Mois de parution
septembre 2021
Spécialité(s)
Résumé

Vagrant est un logiciel libre permettant de déployer rapidement des machines virtuelles. C'est un logiciel développé par la société Hashicorp, déjà connue pour d'autres logiciels comme Terraform, Packer ou Vault. Historiquement lié à VirtualBox, Vagrant s'est désormais largement ouvert à d'autres solutions de virtualisation comme Libvirt ou de conteneurisation comme Docker.

Les derniers articles Premiums

Les derniers articles Premium

Bénéficiez de statistiques de fréquentations web légères et respectueuses avec Plausible Analytics

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Pour être visible sur le Web, un site est indispensable, cela va de soi. Mais il est impossible d’en évaluer le succès, ni celui de ses améliorations, sans établir de statistiques de fréquentation : combien de visiteurs ? Combien de pages consultées ? Quel temps passé ? Comment savoir si le nouveau design plaît réellement ? Autant de questions auxquelles Plausible se propose de répondre.

Quarkus : applications Java pour conteneurs

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Initié par Red Hat, il y a quelques années le projet Quarkus a pris son envol et en est désormais à sa troisième version majeure. Il propose un cadre d’exécution pour une application de Java radicalement différente, où son exécution ultra optimisée en fait un parfait candidat pour le déploiement sur des conteneurs tels que ceux de Docker ou Podman. Quarkus va même encore plus loin, en permettant de transformer l’application Java en un exécutable natif ! Voici une rapide introduction, par la pratique, à cet incroyable framework, qui nous offrira l’opportunité d’illustrer également sa facilité de prise en main.

Les listes de lecture

8 article(s) - ajoutée le 01/07/2020
Découvrez notre sélection d'articles pour faire vos premiers pas avec les conteneurs, apprendre à les configurer et les utiliser au quotidien.
11 article(s) - ajoutée le 02/07/2020
Si vous recherchez quels sont les outils du DevOps et comment les utiliser, cette liste est faite pour vous.
8 article(s) - ajoutée le 02/07/2020
Il est essentiel d'effectuer des sauvegardes régulières de son travail pour éviter de perdre toutes ses données bêtement. De nombreux outils sont disponibles pour nous assister dans cette tâche.
Voir les 59 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous