본문 바로가기

개발하자

테라폼을 생성하기 전에 리소스가 있는지 확인

반응형

테라폼을 생성하기 전에 리소스가 있는지 확인

테라폼에 구글 클라우드에 리소스가 있는지 확인한 후 생성할 수 있는 방법이 있나요?

작업 중에 CircleCI/CD 파이프라인에 아래 리소스가 있는지 확인하고 싶습니다. 터미널 명령, bash 및 gcloud 명령에 액세스할 수 있습니다. 만약 자원이 존재한다면, 나는 그것들을 사용하고 싶다. 만약 그것들이 존재하지 않는다면, 나는 그것들을 만들고 싶다. 나는 터미널 명령과 bash에 액세스할 수 있는 단계로 CircleCI의 config.yml에서 이 로직을 수행하고 있다. 필요할 때 GCP에 필요한 인프라(리소스)를 만들고, 그렇지 않으면 CI/CD 빌드에서 Terraform 오류가 발생하지 않고 GCP를 사용하는 것이 목표입니다.

이미 존재하는 리소스를 생성하려고 하면 Terape apply에서 "이 리소스를 이미 소유하고 있습니다."와 같은 오류가 발생하고 CI/CD 작업이 실패합니다.

아래는 내가 얻으려는 자원을 설명하는 의사 코드입니다.

resource "google_artifact_registry_repository" "main" {
  # this is the repo for hosting my Docker images
  # it does not have a data source afaik because it is beta
}

내 자원을 위해서. 내가 가진 한 가지 접근법은 데이터 소스 블록을 사용하여 테라포름 적용을 하고 값이 반환되는지 확인하는 것이다. 이와 관련된 문제는 Google_artifact_registry_repository에 데이터 소스 블록이 없다는 것입니다. 따라서 리소스 블록을 사용하여 이 리소스를 한 번만 생성해야 하며 이후의 모든 CI/CD 빌드는 리소스 블록에 의존할 수 있습니다. 존재한다는 것을 읽을 수 있는 해결책이 있나요?

resource "google_storage_bucket" "bucket" {
  # bucket containing the folder below
}

resource "google_storage_bucket_object" "content_folder" {
  # folder containing Terraform default.tfstate for my Cloud Run Service
}

나와 자원을 위해. 데이터 소스 블록을 사용하여 Terraform을 적용하면 리소스를 찾을 수 없을 때 Terraform이 해당 상태를 반환하는 데 시간이 오래 걸립니다. 약 10-15초 내에 리소스가 존재하는지 여부를 확인할 수 있고, 그렇지 않다면 이러한 리소스가 존재하지 않는다고 가정할 수 있다면 좋을 것입니다.

data "google_storage_bucket" "bucket" {
  # bucket containing the folder below
}

output bucket {
  value = data.google_storage_bucket.bucket
}

리소스가 있으면 Terraform 출력 버킷을 사용하여 해당 값을 가져올 수 있습니다. 존재하지 않는 경우 Terraform은 응답을 반환하는 데 너무 오랜 시간이 걸립니다. 이것에 대한 아이디어가 있나요?




TF는 TF가 할 일이 아니기 때문에 기존 리소스가 있는지 확인하기 위한 기본 제공 도구를 많이 사용합니다. 그러나 직접 생성할 수 있습니다.

사용자 지정 데이터 소스를 사용하여 기존 리소스 확인을 포함하여 원하는 모든 논리를 프로그래밍하고 나중에 사용할 수 있도록 해당 정보를 TF에 반환할 수 있습니다.




Marcin의 조언 덕분에 Terraform's를 사용하여 GCP에 리소스가 있는지 확인하는 문제를 어떻게 해결할 수 있는지에 대한 실무적인 예를 가지고 있습니다. 이것이 효과적인 한 가지 방법입니다. 나는 다른 접근법들이 있다고 확신한다.

나는 CircleCI config.yml을 가지고 있는데, 여기서 나는 run 명령과 bash를 사용하는 일을 한다. bash부터 아래와 같이 나의 자원이 존재하는지 확인하는 Terraform 스크립트를 초기화/적용할 것이다.

data "external" "get_bucket" {
  program = ["bash","gcp.sh"]
  query = {
    bucket_name = var.bucket_name
  }
}

output "bucket" {
  value = data.external.get_bucket.result.name
}

그런 다음 gcp.sh에서 버킷이 있으면 gsutil을 사용하여 버킷을 가져옵니다.

#!/bin/bash

eval "$(jq -r '@sh "BUCKET_NAME=\(.bucket_name)"')"
bucket=$(gsutil ls gs://$BUCKET_NAME)

if [[ ${#bucket} -gt 0 ]]; then
  jq -n --arg name "" '{name:"'$BUCKET_NAME'"}'
else
  jq -n --arg name "" '{name:""}'
fi

그런 다음 내 CircleCI config.yml에 모두 정리했습니다.

terraform init
terraform apply -auto-approve -var bucket_name=my-bucket
bucket=$(terraform output bucket)

이 시점에서 버킷 이름이 반환되었는지 확인하고 이를 기반으로 진행 방법을 결정합니다.




이 기능은 다음과 같습니다:

  1. 데이터 생성
data "gitlab_user" "user" {
  for_each = local.users
  username = each.value.user_name 
}
  1. 리소스 생성
resource "gitlab_user" "user" {
  for_each       = local.users
  name           = each.key
  username       = data.gitlab_user.user[each.key].username != null ? data.gitlab_user.user[each.key].username : split("@", each.value.user_email)[0]
  email          = each.value.user_email
  reset_password = data.gitlab_user.user[each.key].username != null ? false : true
}

추신.

변수

variable "users_info" {
  type = list(
    object(
      {
        name         = string
        user_name    = string
        user_email   = string
        access_level = string
        expires_at   = string
        group_name   = string
      }
    )
  )
  description = "List of users and their access to team's groups for newcommers"
}

현지인

locals {
  users  = { for user in var.users_info : user.name => user }
}



리소스를 생성하기 전에 리소스가 이미 있는지 확인할 수 있는 방법이 있습니다. 하지만 당신은 그것이 존재하는지 알고 있어야 한다. 이 방법을 사용하여 리소스가 있는지 확인해야 합니다. 리소스가 없으면 오류가 발생합니다.

나는 Azure Resource Group에서 데이터를 생성/읽기하여 그것을 시연할 것이다. 먼저 부울 변수를 만듭니다. 리소스를 생성해야 하는 경우 이 값을 로 설정할 수 있습니다. 그렇지 않은 경우 기존 리소스에서 데이터를 읽으려는 경우 로 설정할 수 있습니다.

variable "azurerm_create_resource_group" {
    type = bool
}

다음으로 리소스를 제공하는 3차 연산자를 사용하여 리소스에 대한 데이터를 가져오고, 다음으로 리소스 생성에 대해 동일한 작업을 수행합니다:

data "azurerm_resource_group" "rg" {
    count = var.azurerm_create_resource_group == false ? 1 : 0
    name = var.azurerm_resource_group
}

resource "azurerm_resource_group" "rg" {
    count         = var.azurerm_create_resource_group ? 1 : 0
    name          = var.azurerm_resource_group
    location      = var.azurerm_location
}

이 코드는 의 값을 기반으로 리소스 그룹에서 데이터를 만들거나 읽습니다. 그런 다음 및 섹션의 데이터를 모두 에 결합합니다.

locals {
        resource_group_name = element(coalescelist(data.azurerm_resource_group.rg.*.name, azurerm_resource_group.rg.*.name, [""]), 0) 
        location            = element(coalescelist(data.azurerm_resource_group.rg.*.location, azurerm_resource_group.rg.*.location, [""]), 0)
    }

이를 위한 또 다른 방법은 테라포머를 사용하여 인프라 코드를 가져오는 것일 수 있습니다.

이게 도움이 됐으면 좋겠어요.


반응형