Tutoriel localstack (partie 2) - Déployer des ressources avec Terraform

Logo localstack

Introduction

Cet article à été mis à jour début 2020 en utilisant la version 0.10.7 de Localstack et la version 0.12.20 de Terraform.

Dans le tutoriel précédent, j’expliquais les possibilités offertes par Localstack en finissant par les inconvéniences. Dans ce 2ème tuto je vais montrer comment Terraform peut être utilisé pour pallier à ces inconvéniences ainsi que faciliter et accélérer le déploiement des ressources AWS dans un environnement Localstack.

Je vais supposer que vous avez déjà sous la main les fichiers de configuration de la première partie car ce tutoriel en est la suite directe.

Tous les fichiers de l’installation complète et condensée sont disponibles sur ce repository github

Installation

Installer Terraform

Vous pouvez télécharger le paquet correspondant à votre système d’exploitation sur cette page.

Par exemple, pour installer Terraform 0.12.20 sur Ubuntu bionic, voici un script résumant les étapes à suivre :

wget https://releases.hashicorp.com/terraform/0.12.20/terraform_0.12.20_linux_amd64.zip
unzip terraform_0.12.20_linux_amd64.zip
sudo mv terraform /usr/local/bin/terraform
sudo chmod +x /usr/local/bin/terraform
rm terraform_0.12.20_linux_amd64.zip

Exécuter la commande terraform --version pour valider l’installation.

Configuration de Terraform

La première chose requise est un fichier de configuration Terraform. Créé le fichier localstack.tf :

touch localstack.tf

De la même manière que vous le feriez pour déployer des vraies resources AWS avec Terraform, nous utiliserons le provider AWS. Ajouter le contenu suivant au fichier :

provider "aws" {
  region                      = "ap-southeast-2"
  access_key                  = "fake"
  secret_key                  = "fake"

  endpoints {
    dynamodb = "http://localhost:4569"
    lambda   = "http://localhost:4574"
  }
}

Il y a certaines choses qui changent en comparaison avec une configuration Terraform “classique” du provider AWS : les endpoints et les secret key et access key. Le clés sont requises par le provider mais inutiles dans ce contexte localstack donc n’importe quelle chaîne de caractères fera l’affaire.

Maintenant exécuter terraform init pour télécharger le plugin du provider AWS.

DynamoDB

Il est temps de déployer une première ressource. Évidemment localstack doit être accessible. Démarrez le conteneur :

docker-compose up -d

Ajouter le contenu suivant au fichier localstack.tf.

resource "aws_dynamodb_table" "table_1" {
  name           = "table_1"
  read_capacity  = "20"
  write_capacity = "20"
  hash_key       = "id"

  attribute {
    name = "id"
    type = "S"
  }
}

La configuration suivante est strictement équivalente à la commande aws dynamodb create-table du tutoriel précédent.

Pour être sûr que la table DynamoDB est absente, exécutez la commande suivante :

aws dynamodb delete-table --endpoint-url http://localhost:4569 --table-name table_1

Maintenant exécutez terraform plan.

Cette erreur apparaît ?

Error: error validating provider credentials: error calling sts:GetCallerIdentity: InvalidClientTokenId: The security token included in the request is invalid.

Terraform essaie de validate les faux identifiants (access_key et secret_key) mais ceux-ci ne seront de toute façon pas utilisé par localstack. Il faut ajouter la ligne skip_credentials_validation = true à la configuration du provider pour empêcher cette erreur.

Exécuter terraform plan à nouveau.

Boum! Nouvelle erreur:

Error: AWS account ID not previously found and failed retrieving via all available methods.

Le “AWS account ID” est un autre concept propre à AWS mais qui n’est pas implémenté dans localstack. Cette fois-ci il faut ajouter la ligne skip_requesting_account_id = true à la configuration du provider pour empêcher l’erreur.

Allez, encore la commande terraform plan et vous devriez voir un retour correcte :

Terraform plan

Vous pouvez maintenant exécuter terraform apply, puis taper yes cela devrait être bon.

Vous pouvez utiliser le cli AWS pour vérifier que la table a bien été créé :

aws dynamodb list-tables --endpoint-url http://localhost:4569

Exécuter terraform plan une fois encore vous affichera un plan vide comme prévu.

Lambda

Voici la configuration à ajouter au fichier localstack.tf pour déployer la fonction lambda counter du tutoriel précédent.

resource "aws_lambda_function" "counter" {
  function_name = "counter"
  filename      = "lambda.zip"
  role          = "fake_role"
  handler       = "main.handler"
  runtime       = "nodejs8.10"
  timeout       = 30
}

Avant de déployer cette ressource, soyez sûr qu’elle n’existe pas (au cas où vous venez de la créer du tutoriel précédent).

aws lambda delete-function --function-name counter --endpoint-url http://localhost:4574

Exécuter la commande terraform plan suivi de terraform apply.

Voyons si tout se passe comme prévu. Étant donné que la fonction lambda n’a pas encore été appelé nous ne devrions pas trouver d’éléments dans la table DynamoDB.

aws dynamodb scan --endpoint-url http://localhost:4569 --table-name table_1

Invoquons la fonction lambda, puis scannons la table une fois de plus pour constater les changements.

aws lambda invoke --function-name counter --endpoint-url=http://localhost:4574 --payload '{"id": "test"}' output.txt
aws dynamodb scan --endpoint-url http://localhost:4569 --table-name table_1

J’espère que tout se passe comme prévu jusqu’ici! Exécuter terraform plan pour s’assurer que le plan est vide.

Ajouter plus de services

Ajouter des nouveaux services devrait être simple désormais. Essayons avec un topic SNS.

La première chose à faire est de mettre à jour le fichier docker-compose.yml pour démarrer le service SNS dans localstack.

  • Mappez le port 4575 du conteneur avec la même valeur sur la machine hôte.
  • Ajoutez sns à la variable d’environnement SERVICES (utiliser des virgules pour séparer les noms de services)

Puis exécuter docker-compose up -d pour appliquer les modifications.

Ajouter la nouvelle ressource au fichier localstack.tf :

resource "aws_sns_topic" "my_topic" {
  name = "TOPIC_NAME"
}

Mettez aussi à jour le bloc provider pour ajouter l’endpoint SNS sns = "http://localhost:4575".

Puis executez terraform apply.

Vous pouvez utiliser le cli aws cette fois ci aussi pour vérifier que le topic est présent :

aws sns list-topics --endpoint-url http://localhost:4575

Cas particuliers

Terraform n’est pas une solution miracle et il vous faudra peut être gérer quelques cas particuliers. Si certaines resources ne peuvent pas être créés en utilisant leur module Terraform, il est possible de contourner ce problème.

Au liey de créer la ressource avec un module comme ceci :

resource "aws_sns_topic" "my_topic" {
  name = "TOPIC_NAME"
}

Vous pouvez obtenir le même résultat en utilisant le module null_resource, avec le cli aws comme commande. Remplacez le bloc aws_sns_topic avec celui ci :

resource "null_resource" "my_sns_topic" {
  provisioner "local-exec" {
    command = "aws sns --endpoint-url=http://localhost:4575 create-topic --name TOPIC_NAME"
  }

  triggers = {
      # Toujours créer le topic
      version = uuid()
  }
}

Exécutez terraform init pour télécharger le plugin du provider “null”, puis terraform apply. De cette manière, vous n’avez pas besoin d’utiliser le cli AWS manuellement pour certaines ressources, et Terraform pour d’autres.

Le mot de la fin

Votre configuration Terraform est prête! Cela rend les déploiements locaux bien plus simples et rapides. Il suffit d’exécuter terraform apply --auto-approve dès que localstack est démarré.

Dans localstack certaines ressources sont sauvegardées sur le disque (via des volumes docker), mais pas toutes. Vous remarquerez qu’après un arrêt et redémarrage du conteneur localstack, les tables DynamoDB sont encore présentes, mais le topic SNS et les fonctions lambda nécessitent un re-déploiement.

Soyez vigilant quand vous arrêtez un conteneur car le fichier contenant l’état des ressources Terraform déployées (terraform.tfstate) reste inchangé même si en réalité elles sont détruites. Ce comportement pourrait causer du désordre dans vos déploiements futurs.

Le tutoriel suivant explique comment aller encore plus loin et automatiser le déploiement des ressources dès que localstack démarre! (La traduction française est en cours mais si vous êtes à l’aise avec l’anglais, vous pouvez d’ors et déjà le lire ici)

Si cet article vous a rendu service, n’hésitez pas à starrer ce repo en guise de remerciement ! ⭐