L'utilisation de Terraform avec Elastic Cloud

blog-thumb-cloud-blue.png

Résumé : Aujourd'hui, nous allons étudier les deux fournisseurs Terraform disponibles à partir d'Elastic. Avec Terraform, vous pouvez définir votre infrastructure en tant que code, que vous conservez ensuite dans des référentiels pour y apporter facilement des modifications.

Premiers pas

Dans le cadre d'une infrastructure en tant que code (IaC), vous gérez l'infrastructure informatique à l'aide de fichiers. Ainsi, les changements appliqués sont répercutés automatiquement sans que vous ayez à intervenir. Ils sont documentés à tout moment de manière adéquate. Quant à Terraform, c'est devenu un environnement de référence pour certains concurrents comment CloudFormation ou Pulumi. Aujourd'hui, nous allons nous intéresser à l'utilisation de Terraform en combinaison avec Elastic Cloud, afin que vous n'ayez pas besoin d'utiliser l'interface utilisateur Cloud pour lancer, modifier ou supprimer des clusters.

Création d'une clé d'API cloud

Pour utiliser Terraform, une clé d'API cloud est nécessaire. Attention : il ne s'agit pas d'une clé d'API pour une instance Elastic Cloud, mais bien d'une clé d'API pour votre compte Elastic Cloud. Le fournisseur Elastic Cloud détaille la configuration nécessaire dans la documentation qui le concerne, à la section relative à l'authentification.

Configuration Terraform initiale

Commençons avec le fichier de base main.tf file :

terraform {
  required_version = ">= 1.0.0"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.4.0"
    }
  }
}

provider "ec" {
}

resource "ec_deployment" "custom-deployment-id" {
  name                   = "My deployment identifier"

  region                 = "gcp-europe-west3"
  version                = "8.1.3"
  deployment_template_id = "gcp-memory-optimized-v2"

  elasticsearch {}

  kibana {}
}

After storing this you can run

terraform init
terraform validate
terraform apply auto-approve

Le dernier appel prendra 1 à 3 minutes, le temps que les nœuds Kibana et Elasticsearch apparaissent. Une fois cela fait, notre instance est opérationnelle. Toutefois, si nous voulons en tirer parti, il est très utile de définir des sorties dans le fichier main.tf :

output "elasticsearch_endpoint" {
  value = ec_deployment.custom-deployment-id.elasticsearch[0].https_endpoint
}

output "elasticsearch_username" {
  value = ec_deployment.custom-deployment-id.elasticsearch_username
}

output "elasticsearch_password" {
  value = ec_deployment.custom-deployment-id.elasticsearch_password
  sensitive = true
}

output "kibana_endpoint" {
  value = ec_deployment.custom-deployment-id.kibana[0].https_endpoint
}

Après avoir exécuté à nouveau terraform apply, vous pouvez voir les points de terminaison dans la sortie terraform output. Vous pouvez exécuter des scripts qui analysent cette sortie, puis effectuer différentes actions, comme créer un index ou un modèle.

À l'aide de l'outil jq, vous pouvez extraire des sections de la commande de sortie terraform output (voire même étudier le fichier d'état Terraform) :

output=$(terraform output -json)
endpoint=$(echo $output | jq -r ".elasticsearch_endpoint.value")
username=$(echo $output | jq -r ".elasticsearch_username.value")
password=$(echo $output | jq -r ".elasticsearch_password.value")
curl $endpoint -u $username:$password

Dans notre exemple, l'emplacement du fichier d'état Terraform importe peu. Une autre fonctionnalité du fournisseur Elastic Cloud consiste à configurer des clusters à distance. Voyons comment elle fonctionne.

Configuration de clusters à distance pour CCS/CCR

Les fonctionnalités de recherche inter-clusters (CCS) et de réplication inter-clusters (CCR) impliquent que les clusters dits "à distance" soient configurés, de sorte qu'un cluster puisse accéder à un autre cluster. L'extrait ci-dessous omet totalement la configuration ou les sections output inutiles pour n'afficher que les éléments requis.

resource "ec_deployment" "cluster_1" {
  name                   = "cluster_1"

  region                 = "gcp-europe-west3"
  version                = "8.1.3"
  deployment_template_id = "gcp-memory-optimized-v2"

  elasticsearch {}

  kibana {}
}

resource "ec_deployment" "cluster_2" {
  name                   = "cluster_2"

  region                 = "gcp-europe-west3"
  version                = "8.1.3"
  deployment_template_id = "gcp-memory-optimized-v2"

  elasticsearch {
    remote_cluster {
      deployment_id = ec_deployment.cluster_1.id
      alias         = ec_deployment.cluster_1.name
      ref_id        = ec_deployment.cluster_1.elasticsearch.0.ref_id
    }
  }

  kibana {}
}

Dans cette configuration, cluster_2 a une connexion à distance avec cluster_1.

L'heure est venue à présent de définir la réplication inter-clusters. Remarque : La ligne de commentaire au-dessus de la commande indique sur quel cluster cette opération doit être exécutée.

# Cluster 1
PUT my-leader-index

# Cluster 2
PUT my-follower-index/_ccr/follow?wait_for_active_shards=1
{"remote_cluster":"cluster_1","leader_index":"my-leader-index"}

# Cluster 1
PUT /my-leader-index/_doc/my-doc?refresh=true
{"key":"value"}

# Cluster 2, repeat until hit count > 0, should take less than a second usually
GET /my-follower-index/_search

Désormais, nous avons un index suiveur dans le cluster 2 basé sur la configuration du cluster à distance dans Terraform.

La recherche inter-clusters a un fonctionnement similaire. Il suffit de tirer parti de la connexion du cluster à distance :

# Cluster 1
PUT /cluster1-index/_doc/1?refresh=true
{"cluster":"cluster1","name":"my name"}

# Cluster 2
PUT /cluster2-index/_doc/1?refresh=true
{"cluster":"cluster2","name":"my name"}

# Cluster 2
GET /cluster2-index,cluster_1:cluster1-index/_search

En plus de gérer les instances par vous-même, vous souhaiterez peut-être changer la configuration d'un cluster en particulier. C'est là que le deuxième fournisseur Terraform intervient, à savoir le fournisseur Terraform elasticstack. Celui-ci permet de configurer un cluster, qu'il soit sur Elastic Cloud ou sur site.

Utilisation du fournisseur elasticstack

Le fournisseur elasticstack permet de gérer différents aspects de la Suite Elastic, comme les paramètres de cluster, les modèles d'index et de composant, les utilisateurs et les rôles, ou encore les pipelines d'ingestion et les processeurs. Dans cet exemple, nous allons créer un pipeline d'index avec deux processeurs :

terraform {
  required_version = ">= 1.0.0"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.4.0"
    }
    elasticstack = {
      source = "elastic/elasticstack",
      version = "0.3.3"
    }
  }
}

provider "ec" {
}

resource "ec_deployment" "custom-deployment-id" {
  name                   = "custom-deployment-id"

  region                 = "gcp-europe-west3"
  version                = "8.1.3"
  deployment_template_id = "gcp-memory-optimized-v2"

  elasticsearch {}

  kibana {}
}

provider "elasticstack" {
  elasticsearch {
    username  = ec_deployment.custom-deployment-id.elasticsearch_username
    password  = ec_deployment.custom-deployment-id.elasticsearch_password
    endpoints = [ec_deployment.custom-deployment-id.elasticsearch[0].https_endpoint]
  }
}

data "elasticstack_elasticsearch_ingest_processor_set" "set_field_terraform" {
  field = "pipeline-source"
  value = "terraform"
}

data "elasticstack_elasticsearch_ingest_processor_grok" "grok_the_log" {
  field    = "message"
  patterns = ["%%{TIMESTAMP_ISO8601:@timestamp} %%{LOGLEVEL:level} %%{GREEDYDATA:message}"]
}

resource "elasticstack_elasticsearch_ingest_pipeline" "ingest" {
  name = "my-ingest-pipeline"

  processors = [
    data.elasticstack_elasticsearch_ingest_processor_set.set_field_terraform.json,
    data.elasticstack_elasticsearch_ingest_processor_grok.grok_the_log.json
  ]
}

This creates a pipeline named my-ingest-pipeline after bringing up the cluster. You could now go to Management/Ingest Pipeline in Kibana and see that the pipeline has been created, or just run the following simulate pipeline call:

POST _ingest/pipeline/my-ingest-pipeline/_simulate
{
  "docs": [
    {
      "_source": {
        "message": "2022-03-03T12:34:56.789Z INFO ze message"
      }
    }
  ]
}

This will return the following document as part of the response:

"_source" : {
  "@timestamp" : "2022-03-03T12:34:56.789Z",
  "level" : "INFO",
  "pipeline-source" : "terraform",
  "message" : "ze message"
}

There is one final step, which is not yet as easy as it should be, but the following little trick does it at least for most of my PoCs.

Ajout d'un tableau de bord

Même si le fournisseur Terraform elasticstack ne permet actuellement que de changer des aspects de la configuration d'Elasticsearch, il existe d'autres éléments, comme Kibana.

Pour présenter la Suite Elastic, j'adore fournir l'exemple complet dans un référentiel GitHub et faire en sorte que le démarrage soit aussi simple que possible.

Une partie de la démonstration consiste à installer un tableau de bord qui présente les données utilisées dans l'exemple. Mais comment y parvenir sans modules d'aide Kibana dans le fournisseur Terraform elasticstack ? En utilisant une commande curl dans null_resource. Cela permet d'ajouter une certaine dépendance à la plateforme ainsi que l'utilisation obligatoire de curl, où que cette commande soit exécutée.

terraform {
  required_version = ">= 1.0.0"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.4.0"
    }
  }
}

provider "ec" {
}

data "local_file" "dashboard" {
    filename = "${path.module}/dashboard.ndjson"
}

resource "ec_deployment" "custom-deployment-id" {
  name                   = "custom-deployment-id"

  region                 = "gcp-europe-west3"
  version                = "8.1.2"
  deployment_template_id = "gcp-memory-optimized-v2"

  elasticsearch {}

  kibana {}
}

resource "null_resource" "store_local_dashboard" {
  provisioner "local-exec" {
    command = "curl -X POST -u ${ec_deployment.custom-deployment-id.elasticsearch_username}:${ec_deployment.custom-deployment-id.elasticsearch_password} ${ec_deployment.custom-deployment-id.kibana[0].https_endpoint}/api/saved_objects/_import?overwrite=true -H \"kbn-xsrf: true\" --form file=@dashboard.ndjson"
  }
  depends_on = [ec_deployment.custom-deployment-id]
  triggers = {
    dashboard_sha1 = "${sha1(file("dashboard.ndjson"))}"
  }
}

Vous remarquerez aussi la présence de la section triggers dans null_resource. Celle-ci prendra en compte les changements apportés au fichier de tableau de bord et appellera à nouveau curl si l'élément sha1sum du fichier JSON change.

Résumé

J'espère que vous avez apprécié cette présentation des fournisseurs Terraform ec et Terraform elasticstack. Tous deux sont en cours de développement. Vous pouvez suivre leur évolution sur les référentiels correspondants (ec, elasticstack).

Si vous rencontrez des difficultés, n'hésitez pas à créer une question dans le référentiel GitHub correspondant et à indiquer vos commentaires. Merci et bonne "terraformation" !