[IaC] Terraform으로 Kubernetes 다루기 - 번외 Helm Chart
안녕하세요, Cloudraw입니다!
이번 글은 Terraform으로 Kubernetes 다루기 시리즈의 번외편으로, Kubernetes 환경에서 자주 사용되는 패키지 매니저인 Helm Chart를 Terraform과 함께 어떻게 활용할 수 있는지를 설명합니다.
앞서 작성한 시리즈에서는 아래와 같은 구성 요소들을 다뤘습니다.
- Kubernetes Provider 사용 방법, 기본 오브젝트 생성하기(Namespace, Pod, Service, Secret)
- 볼륨 리소스 다루기(CSP별 Blob 및 configmap mount)
- 네트워크 리소스 다루기(Ingress, Nginx-Ingress(Helm Chart))
- DNS 연동 및 인증서 발급(Let's Encrypt 및 Cert Manager(Helm))
- CloudStudio로 위 1~4 구성하기
이번 번외편에서는 Helm이 무엇인지, 그리고 Terraform으로 Helm Chart를 어떻게 선언하고 관리할 수 있는지를 실습 예제와 함께 소개합니다.
Helm Chart란?
Helm은 Kubernetes의 패키지 매니저입니다.
YAML로 작성된 복잡한 리소스를 Chart라는 패키지 단위로 묶어, 쉽고 일관성 있게 설치하고 업데이트할 수 있게 해줍니다.
Chart는 다음 구성 요소로 이루어집니다:
Helm Chart 구성 요소
구성 | 파일설명 |
Chart.yaml | Chart에 대한 메타 정보 |
values.yaml | 기본 설정값들을 정의한 파일 |
templates/ | 실제 Kubernetes 리소스 템플릿(YAML)들이 위치하는 디렉토리 |
✅ 즉, Helm Chart는 kubectl apply로 일일이 배포하지 않아도 되는 재사용 가능한 패키지화된 Kubernetes 앱이라고 볼 수 있습니다.
💡Terraform에서 Helm Chart 사용하는 이유
Terraform은 helm_release 리소스를 통해 Helm Chart를 선언적으로 배포할 수 있습니다.
즉, Terraform 코드로 Kubernetes 인프라 구성과 동시에 Helm Chart를 활용한 앱 배포도 자동화할 수 있습니다.
장점
- 코드 기반으로 Helm Chart 구성 및 배포
- 환경 재현 및 GitOps에 유리
- 다른 Terraform 리소스와 통합 관리 가능
마치 apt나 brew처럼, Helm은 복잡한 배포를 쉽게 만들어주는 역할을 하며, 특히 재사용 가능하고, 선언적인 배포가 필요한 환경에서 큰 강점을 가집니다.
Terraform의 helm_release 공식 문서는 아래에서 확인할 수 있습니다.
👉 https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release
실습: Terraform으로 Grafana Chart 설치하기
이번 실습에서는 모니터링 도구인 Grafana를 Helm Chart를 통해 설치해보겠습니다.
1️⃣ Helm Provider 설정
terraform {
required_providers {
helm = {
source = "hashicorp/helm"
version = "~> 2.11.0"
}
}
}
provider "helm" {
kubernetes {
config_path = "~/.kube/config"
config_context = "<context 이름>" # kubectl config get-contexts
}
}
✅ ~/.kube/config는 로컬 클러스터의 kubeconfig 경로로 정의된 기본 컨텍스트의 클러스터에 Helm Chart가 배포됩니다.
💡로컬 환경에 저장되어 있는 config를 불러와서 설정하는 방법이 아닌 CSP별 구성되어 있는 Cluster를 불러오는 방법으로 설정하려면 첫 번째 게시글인 Terraform으로 Kubernetes 다루기 - 1/5 를 참고하여 진행하시면 됩니다.
2️⃣ Helm Chart 배포: Grafana 설치
Helm Chart의 버전이나 repository 주소는 공식 Grafana Helm repository 기준으로 설정하면 됩니다.
resource "helm_release" "grafana" {
name = "grafana"
repository = "https://grafana.github.io/helm-charts"
chart = "grafana"
version = "6.60.1"
namespace = "monitoring"
create_namespace = true
values = [
file("${path.module}/grafana-values.yaml")
]
}
이제 중요한 설정 파일인 grafana-values.yaml을 작성해 보겠습니다.
3️⃣ Grafana 설정 예시 (grafana-values.yaml)
A. 도메인을 사용하는 환경 (Ingress + DNS)
adminUser: admin
adminPassword: admin1234
service:
type: ClusterIP
port: 80
ingress:
enabled: true
ingressClassName: cloudraw
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
hosts:
- host: grafana.cloudraw.kr
paths:
- path: /
pathType: Prefix
✅ 위 설정은 grafana.cloudraw.kr 도메인으로 접근 가능한 Ingress를 구성합니다. 실제로 도메인을 연결하려면 DNS A 레코드 설정도 함께 필요합니다.
B. 로컬 테스트 환경 (NodePort 사용)
테스트나 로컬 환경에서는 도메인이 필요하지 않을 수 있습니다. 이럴 땐 Ingress 없이 NodePort 서비스로 구성해 Node의 IP와 포트를 통해 접근할 수 있습니다.
NodePort 방식 설정 예시
adminUser: admin
adminPassword: admin1234
service:
type: NodePort
port: 80
nodePort: 30030 # 원하는 포트 지정
ingress:
enabled: false
브라우저 접속 테스트 할 경우 (EXTERNAL-IP 없이)
- kubectl port-forward 사용
- Minikube 전용 명령어 사용
kubectl port-forward svc/grafana 30030:80 -n monitoring
또는
minikube service grafana -n monitoring
이런 방식으로 외부 노출 없이도 브라우저로 접근이 가능합니다.
⚠️ 복잡한 키 설정 시 주의할 점
예시 1. annotation 키에 점(.)이 포함된 경우
grafana:
ingress:
annotations:
alb.ingress.kubernetes.io/group.name: shared-ingress
Terraform에서는 다음처럼 작성해야 합니다.
set = [
{
name = "grafana.ingress.annotations.alb\\.ingress\\.kubernetes\\.io/group\\.name"
value = "shared-ingress"
}
]
예시 2. 값이 JSON 객체인 경우
controller:
pod:
annotations:
status.kubernetes.io/restart-on-failure: {"timeout": "30s"}
Terraform에서는 다음처럼 표현합니다.
set = [
{
name = "controller.pod.annotations.status\\.kubernetes\\.io/restart-on-failure"
value = "{\"timeout\": \"30s\"}"
}
]
점(.)은 \\.로 escape 처리 값은 문자열 내 JSON → \" 형태로 이중 escape 필요
💡이처럼 복잡한 설정은 .tf 파일에서 직접 다루는 것보다 values.yaml에 따로 정의하고 불러오는 방식이 유지보수에 더 유리합니다.
💡Terraform에서 Helm values 설정 방법
Terraform에서는 Helm Chart의 설정값(values.yaml)을 아래 3가지 방식으로 정의할 수 있습니다.
방법 1. values 블록으로 파일 참조
values = [
file("grafana-values.yaml")
]
전체 설정이 많거나 복잡할 경우 values.yaml로 분리하는 방식이 유지보수에 유리합니다.
방법 2. set 블록으로 key/value 직접 설정
set {
name = "adminUser"
value = "admin"
}
set {
name = "ingress.enabled"
value = "true"
}
간단한 설정이나 파라미터 변경 시 유용합니다.
방법 3. set_sensitive로 비밀번호 등 민감한 값 처리
set_sensitive {
name = "adminPassword"
value = var.grafana_admin_password
}
이 방식은 비밀번호를 Terraform 변수로 관리하며, terraform.tfvars 또는 Secret Manager와 연동해 민감 정보 보호에 효과적입니다.
Terraform에서 Helm values 설정 방식 정리
방법 | 설명 | 예시 |
values 블록 | 파일로 전체 설정을 분리 | file("grafana-values.yaml") |
set 블록 | 단일 Key/Value 설정 시 | set { name = "...", value = "..." } |
set_list 블록 | 값이 리스트일 경우 | value = ["a", "b"] |
배포 및 확인
terraform init
terraform plan
terraform apply
kubectl get pods -n monitoring # grafana pod 생성 확인
kubectl get svc -n monitoring # grafana service 생성 확인
접속 URL:
- 도메인 환경: https://{설정한 도메인 주소} 예시) https://grafana.cloudraw.kr
- 로컬 환경: http://localhost:{포트포워딩 포트} 예시) http://localhost:30030
이번 글에서는 Terraform으로 Helm Chart를 선언하고, Grafana를 설치하는 예제를 다뤘습니다.
- Helm은 Kubernetes 리소스를 패키지로 관리하는 도구입니다.
- Terraform은 Helm Chart를 helm_release로 코드 기반으로 설치할 수 있게 해줍니다.
- 단순한 값은 set, 복잡한 설정은 values.yaml로 분리하는 것이 좋습니다.
Helm은 Kubernetes 앱을 쉽게 배포할 수 있는 도구이며, Terraform과 결합하면 IaC 형태로 완벽한 재현 가능성과 관리성을 제공합니다.
Cloudraw는 쉽게 클라우드 인프라를 그리고 사용할 수 있는 서비스를 제공하기 위해 노력하고 있습니다.
클라우드가 있는 곳 어디든 Cloudraw가 함께합니다.
📨 help@cloudraw.kr