Terraform mit Elastic Cloud verwenden

blog-thumb-cloud-blue.png

ZUSAMMENFASSUNG; Heute werden wir uns näher mit den beiden verfügbaren Terraform-Anbietern von Elastic befassen. Mit Terraform können Sie Ihre Infrastruktur als Code definieren und in Repositorys aufbewahren, um Änderungen zu vereinfachen.

Erste Schritte

Infrastructure-as-Code (IaC) bedeutet, dass Sie Ihre IT-Infrastruktur in Dateien verwalten, damit Änderungen automatisch und ohne Eingriffe vorgenommen werden können und stets korrekt dokumentiert werden. Terraform ist bei einigen Konkurrenten wie CloudFormation oder Pulumi bereits eine Art von Standard. Heute befassen wir uns mit Terraform in Kombination mit Elastic Cloud, damit Sie nicht die Cloud-GUI verwenden müssen, wenn Sie Cluster hochfahren, ändern oder entfernen möchten.

Cloud API-Schlüssel erstellen

Um Terraform nutzen zu können, brauchen Sie einen Cloud API-Schlüssel. Stellen Sie sicher, dass Sie keinen API-Schlüssel für eine Elastic Cloud-Instanz verwenden, sondern für Ihr Elastic Cloud-Konto. Der Elastic Cloud Provider zeigt die Konfiguration noch ausführlicher in der Dokumentation zur Authentifizierung.

Terraform-Ausgangskonfiguration

Wir beginnen mit einer Minimalkonfiguration in einer main.tf-Datei:

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

Der letzte Aufruf dauert etwa 1-3 Minuten, da die Kibana- und Elasticsearch-Knoten hochgefahren werden. Anschließend ist unsere Instanz einsatzbereit. Um sie jedoch nutzen zu können, sollten wir Ausgaben in der Datei main.tf definieren:

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
}

Wenn wir terraform apply erneut ausführen, sehen Sie die Endpoints in der terraform-Ausgabe. Sie können diese Ausgabe mit Skripts analysieren und Aktionen wie Index- oder Vorlagenerstellung ausführen.

Mit jq können Sie Teile der Terraform-Ausgabe extrahieren (oder sogar die Terraform-Zustandsdatei untersuchen):

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

Auf diese Weise ist es auch unwichtig, wo sich der Terraform-Zustand befindet. Mit dem Elastic Cloud Provider können Sie außerdem Remote-Cluster einrichten. Sehen wir uns an, wie das funktioniert.

Remote-Cluster für CCS/CCR einrichten

Um Funktionen für clusterübergreifende Suche (Cross Cluster Search, CCS) und clusterübergreifende Replikation (Cross Cluster Replication, CCR) nutzen zu können, benötigen wir sogenannte Remote-Cluster, um mit einem Cluster auf einen anderen Cluster zuzugreifen. Das folgende Codebeispiel enthält keinerlei Einrichtung oder nicht benötigte Ausgabekomponenten, sondern zeigt nur den hierfür benötigten Teil.

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 {}
}

In dieser Konfiguration stellt cluster_2 eine Remoteverbindung zu cluster_1 her.

Jetzt können wir die clusterübergreifende Replikation einrichten. Hinweis: Die Kommentarzeile über dem Befehl gibt an, in welchem Cluster der Befehl ausgeführt werden muss!

# 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

Jetzt haben wir einen Follower-Index in Cluster 2 auf Basis der Remote-Clustereinrichtung in Terraform.

Für die clusterübergreifende Suche nutzen wir ebenfalls die Remote-Clusterverbindung:

# 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

Möglicherweise möchten Sie nicht nur die Instanzen selbst verwalten, sondern auch die Konfiguration oder Einrichtung bestimmter Cluster ändern. Dazu können Sie mit dem zweiten Terraform-Anbieter (elasticstack) einen Cluster entweder in Elastic Cloud oder lokal definieren.

Elasticstack-Anbieter verwenden

Mit dem elasticstack-Anbieter können wir Teile des Elastic Stack verwalten, wie etwa Clustereinstellungen, Index- und Komponentenvorlagen, Benutzer und Rollen oder Ingestionspipelines und Prozessoren. In diesem Beispiel erstellen wir eine Index-Pipeline mit zwei Prozessoren:

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.

Dashboard hinzufügen

Mit dem elasticstack-Terraform-Anbieter können wir zwar momentan nur Teile der Elasticsearch-Einrichtung anpassen, aber dafür haben wir noch andere Teile des Stacks zur Verfügung, wie etwa Kibana.

Ich führe den Elastic Stack gerne vor, indem ich das gesamte Beispiel in einem GitHub-Repository bereitstelle, um die Einrichtung möglichst einfach zu gestalten.

Dazu gehört auch die Installation eines Dashboards, das die Daten aus der Vorführung zeigt. Wie kann ich das ohne Kibana-Helfer im Terraform-elasticstack-Anbieter erreichen? Mit einem curl-Befehl als Teil einer null_resource. Dadurch ergibt sich eine gewisse Plattformabhängigkeit, und der Befehl curl muss in der Ausführungsumgebung vorhanden sein.

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"))}"
  }
}

Möglicherweise ist Ihnen auch der triggers-Abschnitt in der null_resource aufgefallen. Dieser Teil überprüft die Dashboard-Datei auf Änderungen und ruft curl erneut auf, wenn sich die SHA1-Prüfsumme der JSON-Datei geändert hat.

Zusammenfassung

Hoffentlich hat Ihnen diese Demonstration des ec Terraform-Anbieters und des elasticstack Terraform-Anbieters gefallen. Beide Komponenten werden aktiv entwickelt, und Sie können den entsprechenden GitHub-Repositorys folgen (ec, elasticstack).

Falls Ihnen irgendwelche Probleme auffallen, können Sie diese im jeweiligen GitHub-Repository melden und Ihr Feedback abgeben. Vielen Dank und viel Spaß beim Terraforming!