Como usar o Terraform com o Elastic Cloud

blog-thumb-cloud-blue.png

Resumo: hoje vamos ver detalhes sobre os dois provedores do Terraform disponíveis da Elastic. O Terraform permite que você defina sua infraestrutura como um código e a mantenha em repositórios para fazer alterações facilmente.

Para começar

Na infraestrutura como código (IaC), você gerencia sua infraestrutura de TI por meio de arquivos para que as alterações possam ser aplicadas automaticamente sem intervenção e sejam documentadas adequadamente o tempo todo. O Terraform tornou-se uma espécie de padrão com alguns concorrentes como CloudFormation ou Pulumi. Hoje vamos nos concentrar no Terraform em combinação com o Elastic Cloud, para que você não precise usar a UI do Elastic Cloud para ativar, alterar ou remover clusters.

Como criar uma chave de API do Elastic Cloud

Para usar o Terraform, você precisa de uma chave de API do Elastic Cloud. Certifique-se de que não seja uma chave de API para uma instância do Elastic Cloud, mas sim para sua conta do Elastic Cloud. O provedor do Elastic Cloud mostra a configuração com mais detalhes na parte da documentação que trata da autenticação (Authentication).

Configuração inicial do Terraform

Vamos começar com um arquivo main.tf quase mínimo:

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

A última chamada levará de um a três minutos para abrir os nós do Kibana e do Elasticsearch. Com isso, temos nossa instância em funcionamento. No entanto, se quisermos fazer uso disso, será muito útil definir saídas no arquivo 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
}

Agora, depois de executar terraform apply novamente, você pode ver os endpoints em terraform output. Você pode executar scripts que analisam essa saída e executam ações como criação de índice ou modelo.

Você pode usar jq para extrair partes do comando de saída do terraform (ou até mesmo inspecionar o arquivo de estado do 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

Dessa forma, a localização do estado do Terraform também é irrelevante. Outro recurso para o provedor do Elastic Cloud é configurar clusters remotos. Vejamos como isso funciona.

Como configurar clusters remotos para CCS/CCR

As funcionalidades de busca entre clusters (CCS) e replicação entre clusters (CCR) exigem que os chamados clusters remotos sejam configurados, onde um cluster pode acessar outro cluster. O snippet de amostra a seguir omitirá totalmente as partes de output desnecessárias ou de configuração, mostrando apenas o que é necessário.

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

Nesta configuração, cluster_2 terá uma conexão remota com cluster_1.

É hora de configurar a replicação entre clusters. Observação: a linha de comentário acima do comando indica em qual cluster isso precisa ser executado!

# 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

Agora temos um índice seguidor no cluster 2 com base na configuração do cluster remoto no Terraform.

A busca entre clusters é de uso semelhante, aproveitando a conexão do cluster remoto:

# 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

Além de gerenciar as instâncias por conta própria, você também pode alterar a configuração de um cluster específico. É aqui que o segundo provedor do Terraform, ou seja, o elasticstack, permite configurar um cluster, independentemente de estar no Elastic Cloud ou no local.

Uso do provedor elasticstack

O provedor elasticstack permite gerenciar partes do Elastic Stack, por exemplo, configurações de cluster, modelos de índice e componentes, usuários e funções ou processadores e pipelines de ingestão. Neste exemplo, criaremos um pipeline de índice com dois processadores:

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.

Inclusão de um dashboard

Embora o provedor do Terraform elasticstack agora funcione apenas para alterar partes da configuração do Elasticsearch, há outras partes da stack como o Kibana.

Uma das minhas formas favoritas de demonstrar o Elastic Stack é fornecer o exemplo completo em um repositório do GitHub e facilitar ao máximo o início das operações.

Parte disso é instalar um dashboard que mostra os dados que faziam parte da demonstração. Então, como isso pode ser feito sem helpers do Kibana no provedor do Terraform elasticstack? Usando um comando curl como parte de um null_resource. Isso adiciona alguma dependência da plataforma e a exigência do curl onde quer que seja executado.

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

Você também pode notar a parte triggers no null_resource — isso levará em consideração as alterações do arquivo do dashboard e executará a chamada curl novamente se o sha1sum do arquivo JSON for alterado.

Resumo

Espero que você tenha gostado de conhecer o provedor do Terraform ec e o provedor do Terraform elasticstack. Ambos estão em desenvolvimento e você pode seguir os repositórios do GitHub correspondentes (ec, elasticstack ).

Além disso, se você encontrar algum problema, crie uma ocorrência no repositório do GitHub correspondente e dê seu feedback. Obrigado e feliz terraformação!