Aller au contenu

Step 1-2 : Les disques EBS

Félicitations, vous avez réussi à créer votre instance via Terraform et déployer votre application dessus.

On peut se poser une question. Notre application utilise une base de données. Sauf que cette base de données disparaît à chaque fois qu'on supprime notre EC2 et qu'on la recrée.

Comment pouvons-nous persister nos données ?

Une première réponse est grâce aux disques EBS d'AWS

Concepts

Amazon Elastic Block Store, EBS, est la brique principale du service EC2 permettant d'attacher des "disques" à nos instances. On parle de Volumes. Ce sont des disques réseaux dont les données que l'on y écrit sont sauvegardées et répliquées avec une haute persistance même après l'extinction des instances. On peut attacher et détacher ces volumes de stockage block de nos instances, un peu comme un disque dur.

On peut attacher plusieurs volumes à une instance, mais un volume EBS ne peut être monté que sur une instance à la fois. (exception mise à part)

Un volume est rattaché à une AZ, Availability Zone. Les volumes sont attachables et détachables à chaud, pendant que l'instance fonctionne. On peut détacher le disque d'une instance pour le rattacher à une autre pour du Failover par exemple.

Il est possible de chiffrer nos volumes EBS ainsi qu'en faire des sauvegardes appelées snapshots, de façon manuelle ou automatique. À partir de ces snapshots, nous pouvons créer de nouveau volumes ou images (AMI).

Note

Bien que EBS soit un service fournissant de la persistance de donnée vous ne le trouverez pas sous la catégorie Storage mais bien dans Compute puis EC2 car c'est une resource du service EC2.

Types

AWS propose différents types de disques à différents prix à choisir suivant le besoin.

Globalement, on retrouve deux grandes distinctions dans lesquelles on retrouvera ensuite les différents types :

  • Solid state drive (SSD) -> gp2, gp3, io1...
  • Hard disk drive (HDD) -> st1, sc1

Pour choisir il y aura plusieurs critères à prendre en compte :

  • Durabilité
  • Taille min/max
  • Performances
  • Prix
  • Cas d'usage/Type de charge client

Plus de détails ici

Performance

Quand on parle de performances pour les volumes EBS, on utilise 2 termes, IOPS et Throughput :

  • IOPS, input/output operations per second, un nombre d'opérations écriture/lecture par seconde.
  • Throughput, bande passante souvent exprimée en MiB/s

Warning

Il y a beaucoup de choses qui peuvent influencer la performance observée plus que le type lui même du volume :

  • le type de l'instance EC2
  • son paramétrage
  • ce qui est écrit/lu
  • le paramétrage de l'EBS
  • la taille des blocks
  • ...

Il y a plusieurs documentation sur le sujet ici

TP

Dans cette étape, pour ne pas perdre notre donnée à chaque terminate d'instance, nous allons lui ajouter un disque EBS. Créez un nouveau dossier nommé step1-2 avec le même contenu que votre step1-1.

  • Ajoutez une nouvelle resource de type aws_ebs_volume
    • Précisez la même availability_zone que votre instance
    • Une size de 10 GiB
    • Type gp3
    • Chiffrez le disque
  • Ajouter aussi une nouvelle ressource aws_volume_attachment
    • Précisez bien /dev/sdf come device_name
    • Référencez votre disk et votre instance
  • Dans votre user_data.sh, montez le disque que vous venez de créer avant de lancer l'application.
User-Data.sh

Voici un extrait de script pour les users data que l'on vous fournit pour la gestion du volume au démarrage de l'instance. Il faut l'insérer avant le démarrage des services

#! /bin/bash

# Install docker https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
apt-get update
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io

# Docker post install configuration
groupadd docker
usermod -aG docker ubuntu
newgrp docker

# Start docker service
systemctl start docker.service
systemctl start containerd.service

# Configure Docker to start on boot
systemctl enable docker.service
systemctl enable containerd.service

# Initialize disk
export DEVICE_NAME="xvdf"
export DEVICE_PATH="/dev/$DEVICE_NAME"
export FSTYPE="ext4"
export MOUNT_FOLDER="/data"

while ! ls $DEVICE_PATH > /dev/null
do
  sleep 5
done

if ! lsblk -o NAME,FSTYPE | grep $DEVICE_NAME | grep $FSTYPE; then
  mkfs -t $FSTYPE $DEVICE_PATH
fi

mkdir $MOUNT_FOLDER
mount $DEVICE_PATH $MOUNT_FOLDER
echo "$DEVICE_PATH $MOUNT_FOLDER $FSTYPE defaults,nofail 0 2" >> /etc/fstab

# Use a private registry (Secret management simplified here, not a best practice)
docker login registry.gitlab.com -p "5t9L4Z9BXvPopSAdysVs" -u "readregcred"

# Setup environment variables
export EC2_PUBLIC_IP=$(curl http://checkip.amazonaws.com)

export HOME_PATH="/home/ubuntu"
cat >$HOME_PATH/.env <<EOL
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
POSTGRES_DB=mydb
PGDATA=/var/lib/postgresql/data/pgdata
DB_ENDPOINT=cdb-db:5432
API_URL=http://${EC2_PUBLIC_IP}:8080
EOL

# Create and start the containers
docker network create cdb-net
docker run -d --name "cdb-db"    --restart always -p 5432:5432 --env-file /home/ubuntu/.env --network cdb-net -v $MOUNT_FOLDER:/var/lib/postgresql/data registry.takima.io/school/proxy/postgres:14
docker run -d --name "cdb-app"   --restart always -p 8080:8080 --env-file /home/ubuntu/.env --network cdb-net registry.gitlab.com/takima-school/images/cdb/api:latest
docker run -d --name "cdb-front" --restart always -p 80:8080   --env-file /home/ubuntu/.env --network cdb-net registry.gitlab.com/takima-school/images/cdb/www:latest

Plus de détails sur le script ici.

Le nom de disque, ici xvdf, ne correspond pas directement forcément au nom mis dans AWS, /dev/sdf, car AWS utilise une virtualisation de type HVM. Plus d'infomations ici et .

Tip

Vous pouvez faire référence aux champs d'autres resources en faisant usage de référence à des Named Values

C'est une best practice déjà pour rester DRY, Don't repeat yourself, et car cela aide terraform à construire son graph de dépendances pour gérer l'ordre de création des ressources.

Ici pour le aws_volume_attachment on peut utiliser aws_ebs_volume.ec2_disk.id et aws_instance.mon_instance.id pour récupérer les id de disk et d'instance.

Terraform se sert de cette déclaration pour contruire son graph de dépendances.

Warning

Vous aurez peut-être remarqué qu'il y a 2 façon de créer et attacher des disques via terraform à votre instance. L'autre façon est via le block ebs_block_device directement sur votre ressource aws_instance.

De façon générale, on préfère faire via aws_ebs_volume et aws_volume_attachment pour une meilleur gestion via Terraform. Plus de détails dans sur cette doc et sur cette réponse.