> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Terraform으로 AWS 인프라 프로비저닝하기

> Terraform 또는 OpenTofu를 사용하여 관리형 모드용 Amazon EKS 클러스터를 생성하거나, 기존 VPC 또는 클러스터에 필요한 구성 요소를 추가합니다

비공개 프리뷰

관리형 모드(Managed mode)는 사용자가 소유한 Amazon EKS 클러스터에서 실행됩니다. 각 릴리스에는 4개의 Terraform 루트 모듈(이하 루트)이 포함되며, 이 모듈은 요구 사항을 충족하는 클러스터를 새로 생성하거나 기존 VPC 또는 클러스터에 필요한 요소를 추가합니다. 루트는 시스템 노드 그룹과 관리형 애드온(`vpc-cni`, `kube-proxy`, `coredns`, `aws-ebs-csi-driver`)을 포함한 클러스터를 생성하고, IAM role, KMS 키, 태그도 함께 생성합니다. 반면 `existing-eks`는 `install_addons`에 지정한 애드온만 설치합니다. Helm 대상 환경에서는 이어서 `clicklink clctl init`가 출력값과 플랫폼 bundle을 바탕으로 플랫폼 계층을 설치합니다. 플랫폼 계층에는 Karpenter, AWS Load Balancer 컨트롤러, StorageClass, 버전이 고정된 구성 요소가 포함됩니다([Terraform 출력값으로 커넥터 초기화하기](#hand-off) 참조). 루트를 사용하려면 Terraform 1.10 이상 또는 OpenTofu 1.12 이상과 AWS provider `~> 6.0`이 필요합니다. 이 페이지의 모든 명령에서 `terraform` 대신 `tofu`를 사용할 수 있습니다.

![AWS에서 ClickHouse Connector를 위한 Terraform 프로비저닝 흐름](https://mintcdn.com/private-7c7dfe99/rJQNifKkddKyB_KW/images/cloud/reference/byoc-connector-terraform-flow.svg?fit=max\&auto=format\&n=rJQNifKkddKyB_KW\&q=85\&s=8b0e95133f61d6b4278f29df9631e44e)

## 시작하기 전에

다음 항목이 필요합니다.

* Terraform 1.10 이상 또는 OpenTofu 1.12 이상과 AWS provider `~> 6.0`
* 선택한 루트에 필요한 리소스를 생성하고 수정할 권한이 있는 AWS 아이덴티티
* 릴리스 아카이브를 다운로드하고 검증하는 데 사용할 `curl`, SHA-256 도구(`sha256sum` 또는 `shasum`), `cosign`
* [등록](/docs/ko/products/bring-your-own-cloud/connector/onboarding#registration) 단계에서 받은 항목: 모든 루트에 필요한 `chart_repository_arn`, 그리고 마지막 `init` 인계 단계에서 사용할 커넥터 엔드포인트, 등록 토큰, 플랫폼 bundle

`production` 및 `existing-vpc`를 사용하는 경우, `clicklink clctl init`과 `kubectl`을 실행할 머신이 비공개 EKS API에 접근할 방법을 미리 계획하십시오. VPN, 배스천 호스트, 피어링된 네트워크, SSM 포트 포워딩 등을 사용할 수 있습니다.

## 1. 환경에 맞는 Terraform 루트를 선택하십시오

네 가지 루트 모두 동일한 `clicklink` 출력을 생성합니다. 어느 루트를 적용하든 `clicklink clctl init`으로 넘어가는 과정은 동일합니다.

| 루트 | 시작 환경 | 생성 항목 |
| - | - | - |
| `minimal` | 개발 및 개념 검증(PoC)용 클러스터 | 동일한 구성, 단일 가용 영역, 공개 엔드포인트, 별도 엔드포인트나 CMK 없음 |
| `production` | 리소스가 없는 계정 및 리전 | VPC, EKS 클러스터, 노드 그룹, IAM, KMS |
| `existing-vpc` | 기존 VPC | EKS 클러스터, 노드 그룹, IAM, KMS, 서브넷 태그 |
| `existing-eks` | 현재 운영 중인 클러스터 | IAM, 이름이 지정된 애드온, 키 권한 부여, 디스커버리 태그 |

### `minimal`

`minimal`은 퍼블릭 엔드포인트, 인터페이스 엔드포인트, 플로 로그, 로그 보존 기간, 시스템 풀 크기에 대한 요구 사항을 완화합니다. 완화된 변수는 모두 두 루트에 동일한 이름으로 존재합니다. 따라서 이 중 하나를 프로덕션 값으로 바꾸려면 `terraform.tfvars`를 수정한 후 다시 적용하기만 하면 됩니다. 반면 단일 워크로드 가용 영역과 KMS 키 부재는 나중에 변경할 수 없습니다. 서브넷의 가용 영역은 변경할 수 없고, 루트에 EKS 시크릿 암호화를 위한 변수가 없기 때문입니다. 이러한 차이를 해소하려면 `production`을 새 클러스터로 적용해야 합니다.

### `production`

VPC는 3개의 가용 영역(`availability_zone_count`, 2~~4개)에 걸쳐 있으며, 영역마다 비공개 `/19` 서브넷과 공개 `/21` 서브넷, 영역당 NAT gateway 1개, S3 gateway 엔드포인트, ECR, STS, EKS, EC2, CloudWatch Logs, SSM, SQS, KMS, ELB용 인터페이스 엔드포인트, 그리고 VPC 흐름 로그로 구성됩니다. EKS 클러스터는 비공개 API 엔드포인트와 액세스 엔트리 인증을 사용하고, 모든 컨트롤 플레인 로그 유형을 루트가 소유한 로그 그룹에 저장하며, 시크릿은 고객 관리형 KMS 키로 암호화합니다. 클러스터에는 관리형 애드온 `vpc-cni`, `kube-proxy`, `coredns`, `aws-ebs-csi-driver`와 `clickhouseGroup=system` 레이블이 지정된 taint 없는 시스템 노드 그룹 1개(기본값은 `m7g.large` 노드 2~~4개)가 구성됩니다. 또한 루트는 중단 큐와 `karpenter.sh/discovery` 태그를 포함한 Karpenter IAM, AWS Load Balancer 컨트롤러 및 커넥터 실행기용 IRSA 역할, 그리고 EBS 볼륨과 객체 스토리지 버킷용 KMS 키를 생성합니다.

### `existing-vpc` 및 `existing-eks`

두 루트 모두 직접 생성하지 않은 리소스는 변경하지 않습니다. 이러한 리소스에는 라우트 테이블, NAT 게이트웨이, 엔드포인트, 보안 그룹 규칙, 노드 그룹, 시작 템플릿, 클러스터 구성, KMS 키가 있습니다. 두 루트 모두 프라이빗 서브넷에 `karpenter.sh/discovery=<cluster_name>` 및 `kubernetes.io/role/internal-elb=1` 태그를 추가합니다. 또한 `existing-vpc`는 퍼블릭 서브넷에 `kubernetes.io/role/elb=1` 태그를 추가하고, `existing-eks`는 클러스터 보안 그룹에 태그를 추가합니다.

`existing-vpc`를 사용하는 경우 VPC에 다음 항목이 미리 구성되어 있어야 합니다:

* DNS 지원과 DNS 호스트명이 활성화되어 있어야 합니다.
* 최소 2개의 가용 영역(Availability Zone)에 걸쳐 2\~4개의 프라이빗 서브넷이 있어야 합니다. 각 서브넷은 `map_public_ip_on_launch`가 비활성화되어 있어야 하며, NAT 게이트웨이 또는 ECR, STS, EKS, EC2, CloudWatch Logs, SSM, SQS, KMS, ELB용 인터페이스 엔드포인트로 라우팅되어야 합니다. S3 게이트웨이 엔드포인트도 추가하십시오. 이 엔드포인트가 없으면 객체 스토리지 트래픽이 NAT 게이트웨이를 경유합니다.
* 퍼블릭 서브넷은 인터넷에 노출되는 로드 밸런서가 필요한 경우에만 구성합니다. VPC에 퍼블릭 계층이 없으면 `public_subnet_ids`를 비워 두십시오.

`existing-eks`를 사용하는 경우 클러스터에 다음 항목이 미리 구성되어 있어야 합니다:

* Kubernetes 1.34 이상이 필요합니다.
* 인증 모드는 `API` 또는 `API_AND_CONFIG_MAP`이어야 합니다. `CONFIG_MAP` 클러스터인 경우 plan 출력에 모드 전환 명령이 표시됩니다.
* 클러스터 발급자(issuer)에 대한 IAM OIDC 공급자가 필요합니다.
* 최소 2개의 가용 영역(availability zone)에 프라이빗 서브넷이 있어야 하며, 이 서브넷에서 NAT 또는 인터페이스 엔드포인트를 통해 AWS API로 egress 트래픽을 보낼 수 있어야 합니다. 기본적으로 루트 모듈은 클러스터 서브넷 중 라우트 테이블이 인터넷 gateway로 연결되는 서브넷을 제외하여 프라이빗 서브넷을 결정합니다. 클러스터 서브넷이 컨트롤 플레인 전용 `/28` 서브넷이거나 노드를 다른 서브넷에 배치해야 하는 경우에는 `private_subnet_ids`를 설정하십시오.
* Karpenter가 설치되어 있지 않아야 합니다. Karpenter IAM과 중단(interruption) 큐는 이 루트 모듈이 생성합니다. 큐 이름이 `<cluster_name>-clicklink`이므로 이전에 제거한 Karpenter 설치에서 남은 큐와 충돌하지 않습니다.
* `system_node_selector`에 지정된 레이블(기본값 `clickhouseGroup=system`)이 있고 테인트(taint)가 없는 시스템 노드가 필요합니다. 이 루트 모듈은 노드 그룹을 생성하지 않습니다.

이 중 하나라도 누락되면 `terraform plan`이 실패합니다.

`install_addons`에 포함된 애드온이 이미 자가 관리형으로 설치되어 실행 중이면 EKS는 `Conflicts found when trying to apply` 오류를 반환합니다. 관리형 애드온이 기존 설치를 대체하도록 하려면 `addon_resolve_conflicts_on_create = "OVERWRITE"`를 설정하고, 그렇지 않으면 해당 애드온을 `install_addons`에서 제거하세요.

## 2. Terraform 릴리스 압축 파일을 다운로드하고 검증하십시오

루트는 릴리스마다 하나의 아카이브로 제공되며, `clicklink` 바이너리와 동일한 버전이 지정됩니다. 현재 릴리스의 아카이브를 체크섬 및 cosign bundle과 함께 내려받으십시오.

```bash theme={null}
CLICKLINK_VERSION="$(curl -fsSL https://releases.clicklink.clickhouse.com/latest-version.txt)"
# Or pin a specific release: CLICKLINK_VERSION='vX.Y.Z'
TERRAFORM_TARBALL="clicklink-terraform-${CLICKLINK_VERSION}.tar.gz"
for suffix in '' .sha256 .bundle; do
  curl -fsSLO "https://releases.clicklink.clickhouse.com/${TERRAFORM_TARBALL}${suffix}"
done
if command -v sha256sum >/dev/null; then
  sha256sum -c "${TERRAFORM_TARBALL}.sha256"
else
  shasum -a 256 -c "${TERRAFORM_TARBALL}.sha256"
fi
```

압축을 해제하기 전에 cosign으로 서명을 검증하십시오.

```bash theme={null}
cosign verify-blob \
  --bundle "${TERRAFORM_TARBALL}.bundle" \
  --certificate-identity-regexp '^https://github\.com/ClickHouse/data-plane-clicklink/\.github/workflows/release\.yaml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  "${TERRAFORM_TARBALL}"
```

그런 다음 압축을 해제하십시오:

```bash theme={null}
tar -xzf "${TERRAFORM_TARBALL}"
cd "clicklink-terraform-${CLICKLINK_VERSION}"
```

아카이브의 압축을 풀면 `aws/production`, `aws/minimal`, `aws/existing-vpc`, `aws/existing-eks`, `aws/modules`가 들어 있는 하나의 디렉터리가 생성됩니다. 각 루트는 모듈을 `../modules`로 참조합니다. 루트 하나만 따로 복사하지 말고 압축을 푼 트리 전체를 그대로 유지하십시오. 아카이브에 포함된 루트 README에는 `--platform-bundle` 없이 `init`으로 인계하는 방식이 안내되어 있을 수 있으나, 지원되는 명령은 [Terraform 출력값으로 커넥터 초기화](#hand-off)에 나와 있는 명령입니다.

## 3. 선택한 루트를 구성하고 적용하십시오

루트 디렉터리에서 예시 변수 파일을 복사한 후 내용을 입력하세요:

```bash theme={null}
cp terraform.tfvars.example terraform.tfvars
```

모든 루트에는 `region`, `cluster_name`, `chart_repository_arn`이 필요합니다. `cluster_name`은 클러스터 이름으로 쓰이며, 모든 리소스의 접두사이자 디스커버리 태그 값으로도 사용됩니다. `production`, `minimal`, `existing-vpc`에서는 소문자, 숫자, 하이픈으로 이루어진 3\~32자여야 하며, 문자로 시작하고 하이픈으로 끝나지 않아야 합니다. `existing-eks`에서는 이미 운영 중인 클러스터의 이름을 사용하며, 최대 32자까지 허용됩니다. `chart_repository_arn`은 ClickHouse 클러스터 차트가 저장된 ECR 리포지토리로, [등록](/docs/ko/products/bring-your-own-cloud/connector/onboarding#registration) 시 계정 담당 팀이 제공합니다. 클러스터를 생성하는 루트에는 `cluster_admin_principal_arns`도 필요합니다. 이는 EKS 액세스 엔트리를 통해 클러스터 관리자 권한을 받는 주체 목록입니다. 루트를 실행하는 아이덴티티가 이 목록에 포함되어 있지 않으면 이후 클러스터에 접근할 수 없습니다. 클러스터 생성자에게 액세스 권한이 암묵적으로 부여되지 않기 때문입니다. 루트별 요구 사항은 다음과 같습니다.

* `minimal`에는 퍼블릭 API 엔드포인트의 IPv4 허용 목록인 `endpoint_public_access_cidrs`가 필요합니다. `init`과 `kubectl`을 실행하는 네트워크가 이 목록에 포함되어 있어야 합니다. `allow_public_endpoint_from_anywhere = true`로 설정하지 않으면 `/0`은 허용되지 않습니다. `endpoint_public_access = false`로 설정하면 목록을 비워 둘 수 있으며, 이 경우 `production`과 마찬가지로 엔드포인트는 프라이빗으로만 접근할 수 있습니다.
* `existing-vpc`에는 `vpc_id`와 `private_subnet_ids`가 필요합니다. `public_subnet_ids`는 선택 사항으로, 인터넷에 노출되는 로드 밸런서가 필요할 때 지정합니다.
* `existing-eks`에는 추가 필수 변수가 없습니다. `install_addons`로 클러스터에 설치되지 않은 관리형 애드온을 지정하고, `ebs_kms_key_arn`으로 서비스 볼륨에 사용할 키를 지정합니다.

그런 다음 init, plan, apply를 차례로 실행하십시오.

```bash theme={null}
terraform init
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64
terraform plan
terraform apply
```

이 아카이브에는 프로바이더 잠금 파일(lock file)이 포함되어 있지 않습니다. `terraform providers lock`을 실행하면 잠금 파일이 생성되므로, 이를 사용자의 사본에 커밋하십시오. 상태(state)는 기본적으로 로컬에 저장됩니다. `versions.tf`에는 공유 상태 구성 방식을 보여 주는 `backend "s3"` 블록이 주석 처리되어 포함되어 있습니다.

> [!NOTE]
>
> `production` 및 `existing-vpc`의 API 엔드포인트는 프라이빗입니다. `init`과 `kubectl`은 VPC 내부(시스템 노드로의 SSM 포트 포워딩, 배스천, VPN 또는 피어링된 네트워크)에서 실행하십시오. 또는 `endpoint_public_access = true`로 설정하고 `endpoint_public_access_cidrs`에 허용 목록을 지정하여 퍼블릭 액세스를 명시적으로 활성화할 수 있습니다.

## 4. Terraform 출력값을 사용하여 커넥터를 초기화하십시오

출력값을 내보낸 후, kube context가 새 클러스터를 가리키는 머신에서 해당 출력값을 플랫폼 bundle과 함께 `init`에 전달하십시오:

```bash theme={null}
terraform output -json > outputs.json
clicklink clctl init --enroll https://<subdomain>.<connector-domain> --target helm --managed \
  --from-terraform outputs.json --platform-bundle bundle.yaml
```

이 루트는 Helm 대상만 지원합니다. VM(`--target systemd`)에서는 `init`가 `--platform-bundle`을 거부하며, `clicklink clctl platform approve --bundle`은 고정된 구성 요소만 설치하므로 클러스터에 노드 프로비저너가 없습니다. `--target systemd`는 직접 운영하는 ClickHouse를 등록하는 커넥터에만 사용하십시오. 이 루트에서는 지원되지 않습니다.

`--platform-bundle`은 루트에 포함되지 않은 항목을 설치합니다. 여기에는 `EC2NodeClass`와 `clickhouse-server` 및 `clickhouse-keeper` NodePool을 포함한 Karpenter, AWS Load Balancer 컨트롤러, `gp3-encrypted` StorageClass(출력값에 EBS 키가 있으면 해당 키로 암호화됨), 그리고 bundle에 고정된 플랫폼 구성 요소인 스냅샷 컨트롤러, ClickHouse operator, 모니터링 collector가 포함됩니다. bundle은 ClickHouse Cloud가 사용자 환경에 맞게 생성하는 플랫폼 매니페스트로, 온보딩 과정에서 계정 담당 팀이 전달합니다. bundle의 `cluster:` 섹션에는 Karpenter와 로드 밸런서 컨트롤러 버전이 고정되어 있습니다. 이 플래그를 사용하려면 `--target helm`, `--managed`, `--from-terraform`이 함께 지정되어야 합니다. 이미 설치된 구성 요소는 그대로 유지되므로 명령을 다시 실행해도 안전하며, `init`는 설치한 항목과 건너뛴 항목, 그리고 건너뛴 이유를 보고서로 출력합니다. 이 플래그 없이 실행하면 `init`는 커넥터를 등록하기만 하고 위 구성 요소는 전혀 설치하지 않으므로, 이들이 갖춰지기 전까지는 클러스터에서 서비스를 실행할 수 없습니다. 이후 [플랫폼 업데이트](/docs/ko/products/bring-your-own-cloud/connector/platform-updates)를 통해 스냅샷 컨트롤러, operator, collector는 변경되지만, Karpenter, 로드 밸런서 컨트롤러, StorageClass는 `init`가 설치한 상태 그대로 유지됩니다.

`--from-terraform`에는 `terraform output -json`이 출력하는 전체 문서나 `terraform output -json clicklink`가 출력하는 단일 객체 중 하나를 지정할 수 있습니다. `clicklink` 출력에는 클러스터 아이덴티티(`account_id`, `region`, `cluster_name`, `cluster_endpoint`, `cluster_ca`), OIDC 공급자, 커넥터 네임스페이스, 실행기의 IAM 역할(`executor_role_arn`), EBS 키, Karpenter 노드 역할과 큐, 로드 밸런서 컨트롤러 역할, `system_node_selector`가 포함됩니다. `init`는 이 파일에서 클러스터 아이덴티티와 커넥터 네임스페이스를 읽어 옵니다. 또한 `executor_role_arn`을 커넥터의 `pcm-executor` ServiceAccount에 IRSA 어노테이션으로 설정하고, 커넥터 파드에 노드 셀렉터를 적용합니다. 관리형 서비스는 이 역할을 공유하지 않습니다. `clicklink clctl executor prepare`는 서비스마다 역할을 하나씩(기본값 `CH-S3-<service>-<region>-00-Role`) 생성하며, 이 역할은 서비스가 생성될 때 해당 서비스에 바인딩됩니다. 자세한 내용은 [권한 모델](/docs/ko/products/bring-your-own-cloud/connector/reference/privilege-model#identities)을 참조하십시오.

`--cluster-name`이나 `--target-namespace` 같은 플래그 값이 파일과 일치하지 않으면 `init`는 두 값을 모두 표시하며 실행을 거부합니다. 이 경우 해당 플래그를 제거하거나 출력값을 수정하십시오. 또한 kube 컨텍스트의 API 서버가 `cluster_endpoint`와 다르거나 EKS ARN이 다른 클러스터를 가리키는 경우에도 실행을 거부합니다. 출력에는 `schema` 필드가 있으며, 현재 값은 `1`입니다. `clctl`은 지원하지 않는 `schema` 값을 가진 파일을 거부합니다.

나머지 등록 절차는 [온보딩](/docs/ko/products/bring-your-own-cloud/connector/onboarding#install-and-enroll)의 표준 절차와 동일합니다.

## KMS 키와 필요한 권한 부여

`production`과 `existing-vpc`는 `kms`에 ARN을 전달하지 않으면 EKS 시크릿, EBS 볼륨, 객체 스토리지 버킷용으로 교체(rotation)가 활성화된 고객 관리형 KMS 키 3개를 생성합니다. `existing-eks`는 `storage_kms_key_arn`을 설정하지 않으면 저장소 키를 생성하며, 서비스 볼륨용 키는 생성하지 않고 `ebs_kms_key_arn`으로 전달받습니다. `minimal`은 키를 생성하지 않으며, `storage_kms_key_arn`을 지정하지 않으면 버킷은 SSE-S3를 그대로 사용합니다. 생성된 키에는 IAM에 액세스를 위임하는 계정 루트 정책 문(statement) 1개가 포함됩니다. 직접 제공하는 키에도 동일한 위임이 필요하며, 그렇지 않으면 키 정책에 다음 권한 부여가 포함되어야 합니다.

| 키 | 주체 | 작업 |
| - | - | - |
| EKS 시크릿 | `<cluster_name>-cluster` | `kms:Encrypt`, `kms:Decrypt`, `kms:DescribeKey` |
| EBS | `<cluster_name>-ebs-csi-driver`, `<cluster_name>-karpenter-controller` | `kms:Encrypt`, `kms:Decrypt`, `kms:ReEncrypt*`, `kms:GenerateDataKey*`, `kms:DescribeKey`, `kms:GrantIsForAWSResource = true` 조건이 포함된 `kms:CreateGrant` |
| 저장소 | `clicklink clctl executor prepare --storage-kms-key-arn`이 생성하는 각 `CH-S3-<service>-<region>-00-Role` | `kms:Decrypt`, `kms:GenerateDataKey`, `kms:DescribeKey` |
| 저장소 | 서비스 백업과 함께 저장되는 `_tde/` 키 레코드용 `<cluster_name>-clicklink-executor` | `kms:GenerateDataKey`, `kms:Decrypt` |

루트는 어느 경우든 EKS 시크릿 키와 EBS 키에 대한 IAM role 정책을 연결하며, 루트에 저장소 키가 있으면 실행기의 저장소 키 정책도 연결합니다. 각 서비스 역할의 정책은 `executor prepare`가 연결합니다. 시스템 노드 루트 볼륨에는 서비스 데이터가 아닌 이미지와 큐블릿 로그가 저장되며, 계정의 기본 EBS 키를 사용합니다.

## Terraform으로 관리되는 인프라 삭제

`terraform destroy`는 루트 모듈이 생성한 리소스를 제거합니다. 생성된 KMS 키는 30일간의 삭제 대기 기간에 들어갑니다. 로그 그룹은 보관된 로그와 함께 삭제되므로 필요한 로그는 미리 내보내십시오. Karpenter가 시작한 인스턴스와 ClickHouse Operator가 생성한 볼륨은 Terraform 상태(state)에 포함되지 않습니다. 따라서 먼저 서비스를 삭제하고 Karpenter를 제거하십시오. 그렇지 않으면 VPC 및 노드 역할 삭제가 실패합니다.

`existing-eks`는 클러스터를 그대로 유지합니다. 이 루트는 자신이 추가한 역할, 인터럽션 큐와 규칙, 액세스 엔트리, 태그를 제거합니다. 이 루트가 설치한 `vpc-cni`, `kube-proxy`, `coredns` 애드온은 EKS 관리 대상에서 해제되지만, 해당 파드는 계속 실행됩니다. 반면 이 루트가 설치한 EBS CSI 드라이버 애드온은 IRSA 역할까지 함께 삭제되므로 루트와 함께 제거됩니다. 드라이버를 유지하려면 삭제하기 전에 별도의 역할을 사용하여 애드온을 다시 생성하십시오.

`aws_ec2_tag`는 기존 태그의 소유권을 가져오므로, 삭제 시 이 루트들이 추가한 모든 태그가 제거되며 여기에는 루트 생성 이전부터 존재하던 `kubernetes.io/role/internal-elb` 태그도 포함됩니다. 태그를 유지하려면 삭제하기 전에 `manage_subnet_tags = false`(`existing-vpc`) 또는 `manage_discovery_tags = false`(`existing-eks`)를 설정한 뒤 apply를 실행하거나, `terraform state rm`으로 `aws_ec2_tag` 리소스를 상태에서 제거하십시오.
