将 Terraform 与 Elastic Cloud 搭配使用

blog-thumb-cloud-blue.png

总结;今天,我们将深入了解 Elastic 提供的两个可用的 Terraform 提供程序。通过 Terraform,您可以将基础架构定义为代码,并将其保存在存储库中,以便轻松地进行更改。

开始使用

基础架构即代码 (IaC) 意味着通过文件管理您的 IT 基础架构,以便可以在无需人工干预的情况下自动应用更改,并始终正确记录更改。Terraform 已经成为 CloudFormation 或 Pulumi 等竞争对手的标准。今天我们重点介绍 Terraform 与 Elastic Cloud 的结合使用,因此您不需要使用 Cloud UI 来快速启动、更改或移除集群。

创建云 API 密钥

为了使用 Terraform,您需要一个云 API 密钥。确保该密钥不是 Elastic Cloud 实例的 API 密钥,而是您的 Elastic Cloud 帐户的 API 密钥。Elastic Cloud 提供程序在其文档的“身份验证”部分中更详细地显示了相关配置。

初始 Terraform 配置

我们先从一个几乎最小的 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

最后一次调用需要 1-3 分钟才能启动 Kibana 和 Elasticsearch 节点。这样,我们的实例就启动并运行了。然而,如果我们想要利用这个实例,在 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
}

现在,再次运行 terraform apply 之后,您可以在 terraform output 中看到终端。有了这个输出,就可以运行用于解析输出的脚本,然后执行创建索引或模板之类的操作。

您可以使用 jq 从 terraform output 命令中提取部分内容(甚至可以检查 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

这样一来,Terraform 状态的位置也就无关紧要了。Elastic Cloud 提供程序的另一项功能是设置远程集群。我们来看看它的运作方式。

设置远程集群以进行 CCS/CCR

跨集群搜索 (CCS) 和跨集群复制 (CCR) 功能需要设置所谓的远程集群,让一个集群可以访问另一个集群。下面的示例代码片段将完全省略创建过程或不必要的 output 部分,而只显示必需的内容。

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

在设置过程中,cluster_2 将与 cluster_1 建立远程连接。

是时候设置跨集群复制了。注意:命令上方的注释行指明了需要在哪个集群上执行此操作!

# 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

现在,我们在集群 2 中有了一个基于 Terraform 中远程集群设置的 follower 索引。

跨集群搜索的用法与跨集群复制类似,也要利用远程集群连接:

# 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

除了自己管理实例之外,您还可能希望更改特定集群的配置或设置。这就要用到第二个 Terraform 提供程序,即 elasticstack Terraform;通过该提供程序,无论在 Elastic Cloud 上还是在本地部署中,您都可以配置集群。

使用 Elasticstack 提供程序

Elasticstack 提供程序允许管理 Elastic Stack 的部分设置,例如集群设置、索引和组件模板、用户和角色或采集管道和处理器。在本例中,我们将创建一个具有两个处理器的索引管道:

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.

添加仪表板

虽然 elasticstack Terraform 提供程序目前仅用于更改部分 Elasticsearch 设置,但堆栈中还有其他部分,如 Kibana。

在演示 Elastic Stack 时,我最喜欢的一种方式要属在 GitHub 存储库中提供整个示例,并使其尽可能容易地启动和运行。

其中包括安装一个用于显示演示数据的仪表板。那么,在 Terraform elasticstack 提供程序中没有任何 Kibana 帮助工具的情况下,如何完成此任务呢?在 null_resource 中使用 curl 命令。这样就增加了一些平台依赖关系,而且每当执行 curl 时还要满足相关要求。

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

您可能还会注意到 null_resource 中的 triggers 部分;这将考虑到对仪表板文件的更改,并在 JSON 文件的 sha1sum 更改时再次执行 curl 调用。

总结

希望您享受这段将 ec Terraform 提供程序elasticstack Terraform 提供程序搭配使用的旅程。这两个提供程序尚在开发中,您可以访问相应的 GitHub 存储库(ecelasticstack)。

此外,如果您遇到任何问题,请在相应的 GitHub 存储库中创建问题并提供反馈。感谢您的反馈!希望 Terraform 带给您愉快的使用体验!