Dans la pratique
Des exemples variés d’infrastructure
Ce chapitre, un peu spécial, a pour but d’illustrer quelques cas d’usage intéressants de Terraform avec des exemples de code concrets.
Ces exemples de code (comme d’autres de cet ouvrage) sont disponibles sur le repository GitHub disponible à cette adresse : https://github.com/eni-terraform-samples, ainsi que sur GitLab : https://gitlab.com/eni-terraform-samples/.
Les exemples sont entièrement fonctionnels. Ils contiennent chacun un fichier README.md, qui décrit quelles sont les variables Terraform demandées, les outputs en sortie et les variables d’environnement nécessaires à la configuration du provider (clés d’API, tokens, etc.). Ils peuvent servir de point de départ à l’écriture de code pour une infrastructure de production, ou à l’écriture d’un module (cf. chapitre Utiliser et développer des modules).
N’hésitez pas à les télécharger, les tester et les modifier !
Un cluster k8s sur Scaleway
La création d’un cluster Kubernetes sur Scaleway consiste à créer deux ressources : le cluster en lui-même, ainsi qu’un node pool, qui contiendra les machines virtuelles du cluster.
Pour être créé, un cluster a également besoin d’un réseau privé.
Voici un exemple de code simple, mais complet, qui crée un cluster Kubernetes sur le cloud Scaleway :
# scaleway cluster needs a private network
resource "scaleway_vpc_private_network" "network" {}
# getting lastest supported k8s version
data "scaleway_k8s_version" "latest" {
name = "latest"
region = "fr-par"
}
resource "scaleway_k8s_cluster" "cluster" {
name = "cluster"
# versions have the form region/version
version = split( "/",
data.scaleway_k8s_version.latest.id)[1]
cni = "cilium"
region = "fr-par"
# referencing the created network
private_network_id = scaleway_vpc_private_network.network.id
# delete all that wes created when destroying the cluster
delete_additional_resources = true
}
resource "scaleway_k8s_pool" "pool" {
# referencing the created cluster id
cluster_id = scaleway_k8s_cluster.cluster.id
name...
Une zone DNS chez OVH
La gestion d’une zone DNS chez OVH peut se faire avec leur provider Terraform.
La data ovh_domain_zone permet de récupérer des informations sur un nom de domaine et sa zone existante chez OVH. La ressource ovh_domain_zone_record permet de créer de nouveaux enregistrements dans une zone DNS existante.
data "ovh_domain_zone" "zone" {
name = "star-wars.ovh"
}
resource "ovh_domain_zone_record" "dagobah" {
zone = data.ovh_domain_zone.zone.name
subdomain = "dagobah"
fieldtype = "A"
ttl = 60
target = "47.41.108.60"
}
resource "ovh_domain_zone_record" "tatooine" {
zone = data.ovh_domain_zone.zone.name
subdomain = "tatooine"
fieldtype = "A"
ttl = 60
target = "242.105.108.11"
}
Dans cet exemple de code, la zone DNS star-wars.ovh est accédée à l’aide d’un bloc data.
Deux records DNS sont ajoutés à cette zone : dagobah.star-wars.ovh et tatooine.star-wars.ovh, avec leurs adresses IP respectives.
L’exécution de ce code avec terraform apply donne les logs suivants :...
Un groupe GitLab avec des repositories
Il est possible d’initialiser des repositories GitLab avec Terraform.
Le code suivant initialise les repositories de cet ouvrage en utilisant le provider GitLab :
resource "gitlab_group" "terraform_code_examples" {
name = "ENI Terraform Book Samples"
path = "eni-terraform-samples"
description = "A GitLab group for Terraform code samples"
avatar = "logo-eni.png"
}
resource "gitlab_project" "ovh_dns_zone" {
name = "ovh-dns-zone"
description = "sample Terraform project which manages an OVH DNS zone"
namespace_id = gitlab_group.terraform_code_examples.id
avatar = "logo-ovhcloud.png"
}
resource "gitlab_project" "scaleway_k8s_cluster" {
name = "scaleway-k8s-cluster"
description = "sample Terraform project which creates a k8s cluster
on Scaleway Cloud"
namespace_id = gitlab_group.terraform_code_examples.id
avatar = "logo-scaleway.png"
}
resource "gitlab_project" "aws_intances" {
name = "aws-instances" ...
Des repositories sur GitHub
Comme c’est le cas pour GitLab, il est possible d’utiliser Terraform pour créer des repositories GitHub.
Le code suivant initialise les repositories de cet ouvrage en utilisant le provider GitHub :
locals {
projects = {
"ovh-dns-zone" : "sample Terraform project which manages
an OVH DNS zone"
"scaleway-k8s-cluster" : "sample Terraform project which
creates a k8s cluster on Scaleway Cloud"
"aws-instances" : "sample Terraform project which manages
EC2 instances exposed by a load-balancer"
}
}
resource "github_repository" "repository" {
for_each = local.projects
name = each.key
description = each.value
visibility = "public"
}
La ressource github_repository permet de créer un repository GitHub.
Un for_each est utilisé pour créer plusieurs repositories à partir du même bloc ressource. La syntaxe et le fonctionnement de l’argument for_each sont expliqués dans le chapitre Concepts avancés de Terraform.
Les repositories sont créés dans l’organisation définie au niveau du provider :...
Une base de données PostgreSQL sur Google Cloud
Cet exemple est un peu plus compliqué que les exemples précédents. Ici, une base de données PostgreSQL est créée sur Google Cloud, ainsi qu’un utilisateur pour s’y connecter. Les informations d’accès à l’utilisateur sont alors stockées à deux endroits : dans un secret sur Google Secret Manager, ainsi que dans un secret dans un Vault.
Le code suivant, présent dans le fichier main.tf crée un serveur de base de données PostgreSQL sur Google Cloud, avec une base de données star-wars :
# create a database server instance
resource "google_sql_database_instance" "this" {
name = "star-wars-database"
database_version = "POSTGRES_15"
# use "Paris" region
region = "europe-west9"
settings {
tier = "db-f1-micro"
disk_size = 20
disk_autoresize = true
backup_configuration {
enabled = true
}
}
}
# create a database inside the instance
resource "google_sql_database" "this"...
Des serveurs EC2 et un load-balancer sur AWS
Cette infrastructure est plus compliquée que les infrastructures précédentes :
Cette infrastructure contient la déclaration de trois sous-réseaux publics dans un VPC (Virtual Private Cloud, un réseau privé virtuel). Une Internet Gateway permet d’ouvrir l’accès à Internet (sortant) et rend possible l’association d’adresses IP publiques. Chaque sous-réseau contient une machine virtuelle. Les machines virtuelles sont exposées par un load-balancer HTTP qui répartit les requêtes entrantes sur les trois machines.
Les réseaux sont déclarés par le fichier networks.tf :
locals {
vpc_cidr_block = "10.200.0.0/16"
networks = {
"eu-west-3a" = "10.200.1.0/24"
"eu-west-3b" = "10.200.2.0/24"
"eu-west-3c" = "10.200.3.0/24"
}
}
# Définition du VPC et des sous-réseaux
resource "aws_vpc" "main" {
cidr_block = local.vpc_cidr_block
tags = {
Name = "vpc-eu-west-3"
}
}
resource "aws_subnet" "public_subnet" {
for_each = local.networks
availability_zone = each.key
cidr_block = each.value
vpc_id = aws_vpc.main.id
tags = {
Name = "subnet-${each.key}"
}
}
resource "aws_internet_gateway" "internet" {
vpc_id = aws_vpc.main.id
}
Une variable locale contient le bloc réseau à associer au VPC, ainsi que le nom des trois zones à utiliser associées aux plages réseau souhaitées.
Le réseau est créé avec un bloc aws_vpc. Les sous-réseaux...
Une base de données MongoDB sur Atlas
Le code de cet exemple utilise quatre variables en entrée :
variable "organization_id" {
type = string
description = "the organization in which to create the cluster"
}
variable "environment" {
type = string
description = "the name of the environment for the cluster"
}
variable "cluster_name" {
type = string
description = "the name of the cluster"
}
variable "database_user" {
type = object({
username = string
database_name = string
})
}
La variable organization_id permet de saisir l’identifiant de l’organisation dans laquelle déployer le cluster.
La variable environment est utilisée pour créer un projet dans l’organisation MongoDB Atlas. La notion de projet dans MongoDB Atlas permet d’isoler différents clusters.
La variable cluster_name permet de nommer le cluster.
La variable database_user permet de déclarer un utilisateur dans le cluster, qui aura des droits d’écriture sur une base de données.
Le fichier cluster.tf définit la création du projet MongoDB Atlas, ainsi que le cluster :
resource "mongodbatlas_project" "this" {
org_id = var.organization_id
name = var.environment
}
resource "mongodbatlas_cluster" "this" {
project_id = mongodbatlas_project.this.id
name = var.cluster_name ...
Conclusion
Ce chapitre a présenté des cas d’usages les plus variés possible de Terraform.
Les cas les plus simples sont les utilisations des services GitHub et GitLab, pour créer des repositories. Ces cas sont simplistes, mais montrent un usage relativement original de Terraform. Il est possible d’aller plus loin sur ces deux exemples : création de variables de CI/CD ou secrets, ajout de membres d’équipes en contributeur sur les repositories, etc.
Les cas plus compliqués sont la base de données avec l’intégration de Vault, ou l’infrastructure EC2 sur AWS. Le cas de la base de données montre un usage intéressant d’intégration de plusieurs providers dans le même code. Il n’est pas rare d’utiliser le provider Vault pour écrire des secrets lorsque des ressources sont créées sur un service cloud (utilisateur ou service account, par exemple).
Les cas de l’infrastructure EC2 sur AWS montrent un usage des fonctions avancées de Terraform, en particulier le for_each en teasing, qui est expliqué en détail dans le chapitre Concepts avancés de Terraform.
Vous arrivez à l’issue du premier tiers de ce livre ! Les chapitres suivants introduisent les notions plus avancées : modules, constructions de code avancées, gestion du state, écriture de tests...