Elastic Cloud와 함께 Terraform 사용

blog-thumb-cloud-blue.png

요약: 오늘은 Elastic에서 이용할 수 있는 두 Terraform 서비스 제공자에 대해 살펴보겠습니다. Terraform을 사용하면 인프라를 코드로 정의하고 리포지토리에 보관하여 쉽게 변경할 수 있습니다.

시작하기

코드형 인프라(Infrastructure-as-code, IaC)는 파일을 통해 IT 인프라를 관리하여 변경 사항을 개입 없이 자동으로 적용하고 항상 적절하게 문서화할 수 있도록 하는 것을 의미합니다. Terraform은 CloudFormation이나 Pulumi와 같은 일부 경쟁사들과 함께 일종의 표준이 되었습니다. 클라우드 UI를 사용하여 클러스터를 스핀업, 변경 또는 제거할 필요가 없도록 오늘은 Elastic Cloud와 함께 Terraform에 초점을 맞추겠습니다.

클라우드 API 키 생성

Terraform을 사용하려면 클라우드 API 키가 필요합니다. Elastic Cloud 인스턴스의 API 키가 아니라 Elastic Cloud 계정의 API 키인지 확인하세요. Elastic Cloud 서비스 제공자는 설명서의 인증(Authentication) 부분에서 구성을 좀더 자세히 보여줍니다.

초기 Terraform 구성

다음과 같이 거의 최소한의 main.tf 파일로 시작하겠습니다.

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

마지막 호출은 Kibana 및 Elasticsearch 노드를 시작하는 데 1-3분이 걸립니다. 이것으로, 우리의 인스턴스가 가동되고 있습니다. 그러나 이를 활용하려면 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 출력 명령에서 일부분을 추출하거나 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_2cluster_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

이제 Terraform의 원격 클러스터 설정을 기반으로 클러스터 2에 팔로워 인덱스가 있습니다.

클러스터 간 검색은 원격 클러스터 연결 기능을 활용하는 것과 유사합니다.

# 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 도우미 없이 어떻게 이것이 가능할까요? curl 명령을 null_resource의 일부로 사용함으로써 가능합니다. 이것은 플랫폼 의존성과 그것이 실행되는 모든 곳에서 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_resourcetriggers 부분을 볼 수도 있습니다. 그러면 대시보드 파일의 변경 사항이 고려되고 JSON 파일의 sha1sum이 변경되면 curl 호출이 다시 실행됩니다.

요약

ec Terraform 서비스 제공자elasticstack Terraform 서비스 제공자에서 모두 즐거운 작업이 되셨기를 바랍니다. 둘 다 개발 중이며 해당 GitHub 리포지토리(ec, elasticstack)를 따르실 수 있습니다.

또한 문제가 발생할 경우, 해당 GitHub 리포지토리에서 문제를 생성하고 피드백을 제공하세요. 감사합니다. 즐거운 Terraform 작업 되세요!