IaC

[IaC] Terraform으로 Kubernetes 다루기 - 3/5

cloudraw 2025. 5. 22. 14:21

안녕하세요, Cloudraw입니다!

Terraform으로 Kubernetes 다루기 세 번째입니다.

  1. Kubernetes Provider 사용 방법, 기본 오브젝트 생성하기(Namespace, Pod, Service, Secret)
  2. 볼륨 리소스 다루기(CSP별 Blob 및 configmap mount)
  3. 네트워크 리소스 다루기(Ingress, Nginx-Ingress(Helm Chart))
  4. DNS 연동 및 인증서 발급(Let's Encrypt 및 Cert Manager(Helm))
  5. CloudStudio로 위 1~4 구성하기

 

세번째, 네트워크 리소스  다루기(Ingress, Nginx-Ingress(Helm Chart))

이전 글에서는 Pod 내부에 디스크 또는 Blob 스토리지를 마운트하여 애플리케이션이 데이터를 저장하거나 설정을 불러올 수 있도록 구성했습니다.

이제는 외부에서 해당 서비스에 접속할 수 있도록 네트워크 경로를 열어줄 차례입니다.

Kubernetes에서는 서비스에 외부 트래픽을 연결하기 위해 다음과 같은 방법을 사용할 수 있습니다.

방법 설명
NodePort 클러스터 노드의 고정 포트를 열어 접근
LoadBalancer 클라우드에서 외부 IP를 배정받아 노출
Ingress URL 경로, 도메인 기반으로 라우팅을 설정하고 외부 진입 지점 역할 수행

 

💡 Ingress란?
- Kubernetes 리소스 중 하나로, 외부 요청을 특정 Service로 라우팅하는 역할을 수행합니다.
- 도메인 기반(URL 경로 포함) 라우팅을 지원합니다.
- HTTP/HTTPS 설정, 인증서 관리, 리다이렉션 등 다양한 네트워크 기능을 구성할 수 있습니다.

 

단, Ingress 리소스만으로는 작동하지 않으며 Ingress Controller가 반드시 필요합니다. 이번 글에서는 가장 널리 쓰이는 Nginx-Ingress ControllerHelm을 통해 설치하고 사용합니다.

 

 

1. Nginx-Ingress Controller 설치하기 (Helm)

 

 

- Helm provider 설정 (Terraform)

Terraform으로 Helm Chart를 배포하려면 Helm Provider를 설정해야 합니다.

 

Helm Provider를 사용하기 위해서는 크게 다음 두 가지 방법이 있습니다.

 

  • 1. config_path를 사용해 kubeconfig 파일로 접근
  • 2. Kubernetes Cluster Credentials를 직접 설정



1. config_path를 사용해 kubeconfig 파일로 접근방법

provider "helm" {
  kubernetes {
    config_path = "~/.kube/config"  # 로컬 kubeconfig 경로
  }
}

⚠️ terraform 명령어를 실행하는 환경에서 ~/.kube/config 경로의 kubeconfig 파일이 정상적으로 kubernetes 클러스터에 접근할 수 있어야 합니다.

 

2. Kubernetes Cluster Credentials를 직접 설정  (이전 1단계 글에서 CSP별로 설정하는 방법을 참고할 수 있습니다.)

provider "helm" {
  kubernetes {
    host     = "https://cluster_endpoint:port"

    client_certificate     = base64decode("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0...생략...")
    client_key             = base64decode("LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVk...생략...")
    cluster_ca_certificate = base64decode("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0...생략...")
  }
}
⚠️ 주의
위 정보를 코드에 직접 하드코딩하면 보안적으로 취약할 수 있습니다. 실제 운영 환경에서는 Terraform 변수나 data 리소스, 외부 시크릿 저장소 등을 사용해 안전하게 주입하는 방식을 권장합니다.
kubectl config view --raw  명령어를 사용하면 client-certificate-data, client-key-data, cluster-ca-certificate-data 값을 확인할 수 있습니다.

 

 

- Helm Chart로 Nginx-Ingress 설치(https://artifacthub.io/packages/helm/ingress-nginx/ingress-nginx)

Terraform의 helm_release 리소스를 활용하여 Kubernetes 클러스터에 Nginx-Ingress Controller를 설치합니다. 이 Controller는 클러스터 외부에서 들어오는 HTTP/HTTPS 요청을 내부 서비스로 라우팅해주는 진입점 역할을 합니다.

resource "helm_release" "nginx_ingress" {
  name       = "nginx-ingress"
  namespace  = "ingress-nginx"
  repository = "https://kubernetes.github.io/ingress-nginx"
  chart      = "ingress-nginx"
  version    = "4.12.2"  # 템플릿 버전

  create_namespace = true  # 네임스페이스가 없으면 자동 생성

  set {
    name  = "controller.service.type"
    value = "LoadBalancer"  # 외부 IP 할당
  }

  set {
    name  = "controller.publishService.enabled"
    value = "true"  # Controller IP를 자동으로 Ingress에 등록
  }
  
  set {
    name = "controller.ingressClassResource.name"
    value = "cloudraw" # default 값은 "nginx"
  }
}
✅ Helm을 통해 Nginx-Ingress Controller가 LoadBalancer로 설치되며, 클러스터 외부로부터 트래픽을 받을 준비가 완료됩니다.
💡 controller.ingressClassResource.name 설정의 의미 (IngressClass에 대한 설명은 아래에서 설명)
Helm Chart를 통해 설치되는 Nginx-Ingress Controller는 기본적으로 nginx라는 이름의 IngressClass 리소스를 자동 생성합니다. 하지만 set 블록을 통해 controller.ingressClassResource.name 값을 직접 설정하면, Helm은 nginx 대신 해당 이름(예: cloudraw)으로 IngressClass를 생성합니다.

이 값은 Ingress 리소스에서 이 Controller를 사용하겠다고 명시할 때 매우 중요합니다.
즉, 기본으로 설정된 값인 nginx 외에 고유한 이름(cloudraw)을 부여함으로써 Ingress Controller를 여러 개 운영하는 환경에서도 명확하게 라우팅 대상을 지정할 수 있습니다.

 

2. Ingress 리소스 생성하기

Ingress Controller가 설치되었다면 이제 외부에서 특정 URL 요청이 들어올 때, 어떤 서비스(Service)로 라우팅할지를 정의하는 Ingress 리소스를 작성해야 합니다.

resource "kubernetes_ingress_v1" "cloudraw_ingress" {
  metadata {
    name      = "cloudraw-ingress"
    namespace = kubernetes_namespace_v1.cloudraw.metadata[0].name  # 생성한 Pod가 속한 네임스페이스

    annotations = {
      "kubernetes.io/ingress.class" = "cloudraw"  # 위에서 지정한 ing nginxNginx Ingress Controller 사용 명시
    }
  }

  spec {
    rule {
      http {
        path {
          path      = "/"          # 접속 경로: "/"는 루트 URL
          path_type = "Prefix"     # 하위 경로 포함 일치

          backend {
            service {
              name = kubernetes_service_v1.cloudraw.metadata[0].name  # 연결할 서비스 이름
              port {
                number = 80  # 서비스 포트 번호
              }
            }
          }
        }
      }
    }
  }
}

 

구성 요소 설명
annotations.ingress.class 사용할 Ingress Controller를 지정 (nginx)
path 접속 URL 경로 (/, /api, /admin 등 다양하게 설정 가능)
service.name 트래픽을 전달할 서비스의 이름
service.port.number 해당 서비스의 포트 번호 (Service 정의와 일치해야 함)
✅ 위 예시는http://EXTERNAL-IP/로 접속 시 cloudraw-service로 라우팅되도록 구성합니다.

 

💡 IngressClass란?
IngressClassIngress 리소스가 어떤 Ingress Controller의해 처리될지를 지정하는 Kubernetes 리소스입니다.
클러스터에 여러 종류의 Ingress Controller(Nginx, Istio 등)함께 존재하는 경우, IngressClass통해 Ingress 리소스가 어떤 Controller라우팅될지를 명확히 지정할 있습니다.

 

Ingress 리소스에서 IngressClass지정하는 방식은 보통 가지입니다.

  • spec.ingressClassName 필드를 사용하는 방식 (Kubernetes 1.18 이상 권장)
  • metadata.annotations"kubernetes.io/ingress.class"설정하는 방식 (이전부터 사용되던 방식)
💬 이번 구성에서는 어떻게 처리했을까?

이번 블로그 예제에서는 Helm Chart통해 Nginx Ingress Controller설치하고,

Helm Chart 설정 시 아래처럼 IngressClass 이름을 cloudraw로 지정했습니다.

set {
  name = "controller.ingressClassResource.name"
  value = "cloudraw"
}
 

따라서 Ingress 리소스에서도 다음 두 가지 방식 중 하나를 선택해 사용하면 됩니다.

# Ingress 리소스 내에서 IngressClass를 지정하는 두 가지 방식 중 하나 사용

# 1. 어노테이션 방식 (현재 예제에서 사용)
metadata {
  annotations = {
    "kubernetes.io/ingress.class" = "cloudraw"
  }
}

# 2. 필드 방식
spec {
  ingress_class_name = "cloudraw"
}

Ingress 리소스에서는 별도로 IngressClass 리소스를 생성하지 않고, 단순히 annotation 통해 사용할 Controller 명시하는 것만으로 충분합니다. 이러한 방식은 설정이 간단하고, Helm 설치와 바로 연동되기 때문에 실무에서도 자주 활용됩니다.

실무에서는 이렇게 Helm Chart 기본값(nginx) 외에 자신만의 IngressClass 이름을 지정하여 라우팅 경로를 분리하는 패턴이 자주 사용됩니다.

 

 

3. Nginx-Ingress 접근 확인

 

이번 단계에서는 Ingress가 정상적으로 외부 트래픽을 라우팅하는지 확인하기 위해, 기존에 구성한 cloudraw-pod와는 별도로, 테스트 목적의 간단한 'nginx-pod'를 새로 생성하여 접근 테스트를 진행하였습니다. 다음과 같이 'nginx' 이미지를 사용하는 테스트용 Pod를 생성하고, 이에 연결되는 'service'를 정의합니다.

 

테스트용 nginx-pod 및 service 정의

# 테스트용 Nginx Pod
resource "kubernetes_pod_v1" "nginx_test" {
  metadata {
    name      = "nginx-test-pod"
    namespace = kubernetes_namespace_v1.cloudraw.metadata[0].name
    labels = {
      app = "nginx-test"
    }
  }

  spec {
    container {
      name  = "nginx"
      image = "nginx:latest"

      port {
        container_port = 80
      }
    }
  }
}

# Nginx Pod에 연결될 Service
resource "kubernetes_service_v1" "nginx_test_svc" {
  metadata {
    name      = "nginx-test-service"
    namespace = kubernetes_namespace_v1.cloudraw.metadata[0].name
  }

  spec {
    selector = {
      app = "nginx-test"
    }

    port {
      port        = 80
      target_port = 80
    }
  }
}

 

 

해당 Ingress연결되도록 수정한 Ingress 예시

resource "kubernetes_ingress_v1" "nginx_test_ingress" {
  metadata {
    name      = "nginx-test-ingress"
    namespace = kubernetes_namespace_v1.cloudraw.metadata[0].name

    annotations = {
      "kubernetes.io/ingress.class" = "nginx"
    }
  }

  spec {
    rule {
      http {
        path {
          path      = "/"       
          path_type = "Prefix"

          backend {
            service {
              name = kubernetes_service_v1.nginx_test_svc.metadata[0].name
              port {
                number = 80
              }
            }
          }
        }
      }
    }
  }
}

Helm을 통해 Nginx-Ingress Controller가 설치되었으므로, 다음 명령어로 EXTERNAL-IP를 확인할 수 있습니다.

kubectl get svc -n ingress-nginx

 

결과

 

브라우저에서 접속
http://<EXTERNAL_IP>/

→ 생성한 nginx-pod의 응답이 출력되면 정상 작동합니다.

 

 

 

 

 

 

 

📌 흐름 정리

Ingress는 외부 트래픽이 Pod까지 도달하는 흐름에서 매우 중요한 역할을 수행합니다. 아래는 전체 트래픽 흐름입니다.

[ 사용자의 브라우저 요청 ]
        ↓
[ LoadBalancer EXTERNAL-IP ]
        ↓
[ Nginx Ingress Controller ]
        ↓
[ Ingress 리소스 설정 ]
        ↓
[ cloudraw-service ]
        ↓
[ cloudraw-pod ]
💡 참고
이전 글에서 작성한 cloudraw-pod, cloudraw-service 구성과 연계되며,각 요청은 URL 경로와 도메인 규칙에 따라 라우팅됩니다.

 

 

⚠️유의사항 및 Troubleshooting

문제 상황원인 및 해결 방법
EXTERNAL-IP가 <pending> 상태 CSP에서 LoadBalancer를 지원하지 않거나 클러스터 설정 미비. (예: Minikube 등에서는 사용 불가)
404 Not Found Ingress path 또는 연결된 Service name/port 확인 필요
Ingress Controller 미설치 Ingress 리소스는 Controller가 없으면 작동하지 않음
HTTPS 인증서 필요 다음 세션에서 Let's Encrypt + Cert Manager 구성으로 해결 가능 
특정 경로만 라우팅 Ingress rule의 path 설정을 추가하거나 수정

 

 

 

이번 글에서는 다음과 같은 작업을 완료했습니다.

  • Helm을 통해 Nginx-Ingress Controller를 설치
  • Ingress 리소스를 정의하여 cloudraw 애플리케이션에 외부에서 접근 가능하게 구성
  • 실제 EXTERNAL-IP를 통해 접속 확인

다음 단계에서는, 도메인 연결 및 HTTPS 인증서를 자동 발급받는 Cert Manager 구성 방법을 Terraform으로 이어서 다뤄보겠습니다.

 

 

 


 

    

 

Cloudraw는 쉽게 클라우드 인프라를 그리고 사용할 수 있는 서비스를 제공하기 위해 노력하고 있습니다.

 

클라우드가 있는 곳 어디든 Cloudraw가 함께합니다.

 

📨 help@cloudraw.kr