Terraform 으로 프로젝트 eks 인프라 구성하기.

안상운·2025년 6월 12일

OnTheTop - 프로젝트

목록 보기
8/12
post-thumbnail

onthetop 프로젝트: Terraform으로 EKS 클러스터 구축하기

왜 Terraform과 EKS인가?

현대 클라우드 환경에서 인프라를 코드로 관리(Infrastructure as Code, IaC)하는 것은 더 이상 선택이 아닌 필수입니다. IaC를 통해 우리는 인프라를 명시적이고, 재현 가능하며, 버전 관리가 가능한 방식으로 운영할 수 있습니다. 그중에서도 하시코프(HashiCorp)의 Terraform은 선언적 구문을 통해 클라우드 리소스를 안전하고 효율적으로 프로비저닝하는 대표적인 도구로 자리 잡았습니다.

한편, 컨테이너 오케스트레이션의 사실상 표준이 된 쿠버네티스(Kubernetes)를 클라우드에서 운영할 때, AWS의 EKS(Elastic Kubernetes Service)는 가장 강력하고 안정적인 선택지 중 하나입니다. EKS는 쿠버네티스 컨트롤 플레인(Control Plane)의 설치, 운영, 유지보수를 AWS가 관리해주므로, 우리는 애플리케이션 워크로드에만 집중할 수 있는 환경을 제공받습니다.

이 글에서는 실제 운영 환경을 방불케 하는 onthetop 프로젝트의 Terraform 코드를 통해, VPC 네트워크부터 IAM 역할, EKS 클러스터 및 노드 그룹 생성, 그리고 CI/CD 파이프라인을 통한 배포 자동화에 이르기까지, 프로덕션 레벨의 EKS 클러스터를 구축하는 전 과정을 심층적으로 분석합니다. 이 분석을 통해 단순히 "어떻게" 만드는지를 넘어, "왜" 이렇게 설계되었는지에 대한 깊은 이해를 얻는 것을 목표로 합니다.

1. 프로젝트 구조: 견고한 설계의 첫걸음

프로젝트의 전체적인 구조를 살펴보는 것은 매우 중요합니다. 잘 설계된 구조는 코드의 재사용성을 높이고 유지보수를 용이하게 합니다. onthetop 프로젝트는 Terraform의 모범 사례를 참고해서 구조를 짰습니다.

eks-terraform/
├── envs/
│   ├── prod/      # Production 환경 구성
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── backend.tf (가상)
│   └── shared/    # 여러 환경이 공유하는 리소스 (e.g., S3 backend)
│       └── ...
└── modules/
    ├── vpc/       # VPC 네트워크 모듈
    ├── iam/       # IAM 역할 및 정책 모듈
    └── eks/       # EKS 클러스터 및 노드 그룹 모듈
  • envs (Environments): prod, staging, dev 등 각 배포 환경별 구성을 관리하는 디렉터리입니다. 환경별로 다른 변수 값(예: 인스턴스 타입, VPC CIDR)을 적용하여 동일한 모듈 코드로 여러 환경을 효율적으로 관리할 수 있습니다. 이를 통해 환경 간의 일관성을 유지하면서도 유연성을 확보합니다.
  • modules (Modules): VPC, IAM, EKS 등 관련된 리소스들의 집합을 재사용 가능한 단위로 묶어놓은 디렉터리입니다. 모듈화를 통해 코드의 중복을 제거하고, 각 인프라 구성 요소를 추상화하여 복잡도를 낮춥니다. 예를 들어, 잘 만들어진 vpc 모듈은 어떤 프로젝트에서든 가져다 쓸 수 있습니다.

이러한 구조는 "Don't Repeat Yourself" (DRY) 원칙을 인프라 코드에 적용한 훌륭한 예시이며, 대규모 인프라를 관리할 때 필수적인 접근 방식입니다.

2. 1단계: 인프라의 뼈대, VPC 네트워크 구축 (vpc 모듈)

모든 클라우드 서비스의 기반은 견고한 네트워크입니다. eks-terraform/modules/vpc/main.tf 코드는 EKS 클러스터가 동작할 격리된 네트워크 환경, 즉 VPC(Virtual Private Cloud)를 정의합니다.

핵심 리소스 분석:

  1. aws_vpc: 10.0.0.0/16과 같은 사설 IP 대역을 갖는 독립적인 가상 네트워크를 생성합니다. 이 공간 안에 EKS 클러스터의 모든 구성 요소가 배치됩니다.

  2. aws_subnet (Public & Private):

    • Public Subnet: 인터넷 게이트웨이(IGW)로의 라우팅 경로가 있어 외부 인터넷과 직접 통신이 가능한 서브넷입니다. 주로 외부 트래픽을 받아야 하는 Application Load Balancer(ALB)나 Bastion Host 등이 위치합니다.
    • Private Subnet: 외부에서 직접 접근할 수 없으며, NAT 게이트웨이를 통해서만 외부로 나가는(Outbound) 통신이 가능한 서브넷입니다. 보안을 위해 EKS 워커 노드와 같은 핵심 리소스들은 반드시 Private Subnet에 배치해야 합니다.
    • onthetop 프로젝트는 countcidrsubnet 함수를 사용하여 여러 가용 영역(Availability Zone, AZ)에 걸쳐 서브넷을 동적으로 생성함으로써 고가용성(High Availability)을 확보합니다.
  3. aws_internet_gateway (IGW): VPC와 외부 인터넷을 연결하는 관문입니다. Public Subnet의 라우팅 테이블에 IGW를 향하는 경로를 추가하여 인터넷 통신을 가능하게 합니다.

  4. aws_nat_gateway & aws_eip:

    • Private Subnet에 있는 리소스(예: 워커 노드)가 외부의 컨테이너 레지스트리에서 이미지를 가져오거나 OS 업데이트를 수행해야 할 때, 아웃바운드 인터넷 통신을 위해 필요합니다.
    • NAT 게이트웨이는 Public Subnet에 위치하며, 고정 IP(Elastic IP)를 할당받습니다. Private Subnet의 라우팅 테이블은 모든 아웃바운드 트래픽(0.0.0.0/0)을 NAT 게이트웨이로 보내도록 설정됩니다. 이를 통해 내부 리소스의 IP를 외부에 노출하지 않으면서도 안전하게 외부와 통신할 수 있습니다.
  5. aws_route_table & aws_route_table_association:

    • 서브넷 내에서 발생한 네트워크 트래픽이 어디로 가야 할지를 결정하는 라우팅 규칙의 집합입니다.
    • Public 라우팅 테이블은 IGW로, Private 라우팅 테이블은 NAT 게이트웨이로 향하는 경로를 각각 정의하고, 이를 각 서브넷과 연결(association)합니다.

"왜 Public과 Private 서브넷을 모두 사용하셨나요?"
"보안 모범 사례에 따라, 외부 접근이 불필요한 EKS 워커 노드와 같은 핵심 컴퓨팅 리소스는 Private Subnet에 배치하여 외부 공격 표면을 최소화했습니다. 동시에 외부 트래픽을 처리하는 로드 밸런서는 Public Subnet에 두어 서비스 접근성을 확보하고, Private Subnet의 리소스들은 NAT 게이트웨이를 통해 안전하게 외부 리소스(예: ECR, 외부 API)에 접근할 수 있도록 네트워크 아키텍처를 설계했습니다. 이는 보안성, 확장성, 고가용성을 모두 고려한 구성입니다."


3. 2단계: 권한 관리의 핵심, IAM 역할 생성 (iam 모듈)

AWS에서 리소스 간의 상호작용은 모두 IAM(Identity and Access Management)을 통해 제어됩니다. EKS는 정상적인 작동을 위해 여러 AWS 서비스(EC2, ELB, VPC 등)에 접근해야 하므로, 정확한 권한을 가진 IAM 역할을 생성하는 것이 매우 중요합니다. eks-terraform/modules/iam/main.tf는 이 역할을 담당합니다.

핵심 리소스 분석:

  1. EKS Cluster Role (aws_iam_role):

    • EKS 컨트롤 플레인이 사용자를 대신하여 VPC, ELB 등 다른 AWS 리소스를 관리하는 데 필요한 권한을 부여하는 역할입니다.
    • assume_role_policy를 통해 eks.amazonaws.com 서비스가 이 역할을 위임받을 수 있도록 신뢰 관계를 설정합니다.
    • AWS에서 관리하는 AmazonEKSClusterPolicy를 연결하여 필요한 기본 권한을 부여합니다.
  2. EKS Node Group Role (aws_iam_role):

    • EKS 클러스터의 워커 노드(EC2 인스턴스)가 사용하는 역할입니다.
    • assume_role_policy를 통해 ec2.amazonaws.com 서비스가 이 역할을 위임받을 수 있도록 설정합니다.
    • 이 역할을 통해 워커 노드는 컨트롤 플레인과 통신하고, ECR에서 컨테이너 이미지를 가져오며, CloudWatch에 로그를 전송하는 등의 작업을 수행합니다.
    • 필수적으로 연결되는 관리형 정책은 다음과 같습니다.
      • AmazonEKSWorkerNodePolicy: 워커 노드가 클러스터에 조인하고 통신하는 데 필요한 최소한의 권한.
      • AmazonEKS_CNI_Policy: AWS VPC CNI 플러그인이 파드(Pod)에 IP 주소를 할당하고 네트워크를 구성하는 데 필요한 권한.
      • AmazonEC2ContainerRegistryReadOnly: ECR에서 컨테이너 이미지를 pull 할 수 있는 권한.
  3. aws_iam_instance_profile:

    • 생성된 Node Group Role을 EC2 인스턴스(워커 노드)에 적용할 수 있도록 감싸주는 컨테이너입니다. EKS 노드 그룹을 생성할 때 이 인스턴스 프로필을 지정하게 됩니다.

면접관 Point 💡: "IAM 역할을 왜 클러스터와 노드 그룹으로 나누어 생성해야 하나요?"
답변 예시: "최소 권한 원칙(Principle of Least Privilege)을 따르기 위함입니다. EKS 컨트롤 플레인과 워커 노드는 요구하는 권한의 범위와 주체가 다릅니다. 컨트롤 플레인은 클러스터 전체의 네트워킹(ELB 생성 등)을 관리하는 넓은 권한이 필요한 반면, 워커 노드는 컨테이너 실행, 이미지 PULL, 로그 전송 등 자신의 역할에 국한된 권한만 필요합니다. 역할을 분리함으로써 각 구성 요소에 필요한 최소한의 권한만 부여하여, 하나의 역할이 탈취되더라도 피해 범위를 제한하고 전체 시스템의 보안을 강화할 수 있습니다."


4. 3단계: EKS 클러스터와 워커 노드 프로비저닝 (eks 모듈)

이제 준비된 네트워크와 IAM 역할을 바탕으로 EKS 클러스터의 핵심부를 생성할 차례입니다. eks-terraform/modules/eks/main.tf 파일이 이 과정을 정의합니다.

핵심 리소스 분석:

  1. aws_eks_cluster:

    • 쿠버네티스 컨트롤 플레인을 생성하는 리소스입니다.
    • name: EKS 클러스터의 고유한 이름입니다.
    • role_arn: 이전 단계에서 생성한 EKS Cluster Role의 ARN을 연결합니다.
    • vpc_config: EKS 클러스터를 어느 VPC에 위치시킬지 정의하는 중요한 블록입니다.
      • subnet_ids: 컨트롤 플레인이 로드 밸런서나 ENI(Elastic Network Interface)를 생성할 서브넷 목록을 지정합니다. vpc 모듈에서 출력한 Public 및 Private 서브넷 ID를 모두 전달하여 유연성을 확보합니다.
      • endpoint_public_access / endpoint_private_access: API 서버 엔드포인트의 접근 제어 설정입니다. 보안 강화가 필요하다면 Public 접근을 비활성화(false)하고, VPC 내부(또는 VPN/Direct Connect로 연결된 환경)에서만 API 서버에 접근하도록 구성할 수 있습니다.
  2. aws_eks_node_group:

    • 컨테이너 워크로드가 실제로 실행될 워커 노드(EC2 인스턴스 그룹)를 정의합니다.
    • cluster_name: 이 노드 그룹이 속할 EKS 클러스터의 이름을 지정합니다.
    • node_group_name: 노드 그룹의 이름입니다.
    • node_role_arn: 이전 단계에서 생성한 EKS Node Group Role의 ARN을 연결합니다.
    • subnet_ids: 워커 노드가 생성될 서브넷 목록입니다. 반드시 Private Subnet을 지정하여 외부 노출을 막아야 합니다.
    • scaling_config:
      • desired_size: 그룹이 유지해야 할 노드의 수.
      • max_size / min_size: 오토스케일링 시 노드 수가 확장/축소될 수 있는 최대/최소 한계. 이는 트래픽 변화에 따른 탄력적인 리소스 운영의 핵심입니다.
    • instance_types: 워커 노드로 사용할 EC2 인스턴스의 타입을 지정합니다. (예: t3.medium)
    • depends_on: 명시적으로 aws_eks_cluster에 대한 의존성을 선언하여, 컨트롤 플레인이 완전히 준비된 후에 노드 그룹 생성이 시작되도록 보장합니다.
  3. local_filekubeconfig 생성:

    • Terraform 실행 후 kubectl 명령어를 사용하기 위해 필요한 kubeconfig 파일을 생성하는 로직입니다.
    • aws_eks_cluster 리소스에서 제공하는 endpoint, certificate_authority 등의 정보를 조합하여 kubeconfig 파일을 로컬에 저장합니다. 이는 인프라 생성과 동시에 클러스터 접근 설정을 자동화하는 매우 실용적인 기법입니다.
  4. aws-auth ConfigMap 설정:

    • EKS 클러스터가 생성된 직후에는 클러스터를 생성한 IAM 사용자/역할만 접근 권한을 가집니다. 다른 IAM 사용자나 역할(예: CI/CD 파이프라인이 사용하는 역할)에게 클러스터 접근 권한을 부여하려면 aws-auth라는 특별한 ConfigMap을 수정해야 합니다.
    • onthetop 프로젝트에서는 aws-auth-patch.json 파일을 정의하고, kubectl patch 명령을 local-exec 프로비저너를 통해 실행하여 이 과정을 자동화합니다. 이를 통해 클러스터 생성 직후 필요한 사용자 권한을 코드 기반으로 일관되게 적용할 수 있습니다.

면접관 Point 💡: "EKS 노드 그룹의 오토스케일링은 어떻게 동작하며, 파드(Pod) 레벨의 스케일링과는 어떻게 다른가요?"
답변 예시: "EKS 노드 그룹의 오토스케일링은 Cluster Autoscaler(CA) 라는 컴포넌트에 의해 관리됩니다. CA는 파드 스케줄링 상태를 감시하다가, 리소스(CPU/Memory) 부족으로 인해 더 이상 파드를 스케줄링할 수 없는 상태가 되면 aws_eks_node_groupdesired_sizemax_size 한도 내에서 증가시켜 새로운 노드를 프로비저닝합니다. 반대로, 특정 시간 동안 사용률이 낮은 노드가 발견되면 파드를 다른 노드로 재배치한 후 해당 노드를 종료하여 min_size까지 축소합니다.
이는 Horizontal Pod Autoscaler(HPA) 와는 다릅니다. HPA는 CPU 사용량과 같은 메트릭을 기반으로 파드의 복제본(replica) 수를 조절하는, 즉 애플리케이션 레벨의 스케일링입니다. CA는 HPA에 의해 늘어난 파드들을 수용할 노드가 부족할 때 동작하는 인프라 레벨의 스케일링입니다. 이 둘은 상호 보완적으로 작동하여 완벽한 탄력성을 구현합니다."


5. 최종 단계: GitHub Actions를 이용한 배포 자동화 (CI/CD)

인프라를 코드로 작성하는 것의 진정한 가치는 자동화를 통해 발현됩니다. onthetop 프로젝트의 .github/workflows 디렉터리는 GitHub Actions를 사용하여 Terraform 코드의 변경사항을 자동으로 계획(plan)하고 적용(apply)하는 CI/CD 파이프라인을 정의합니다.

deploy-prod.yml 워크플로우 분석:

  • Trigger (on: workflow_dispatch): GitHub UI에서 수동으로 워크플로우를 실행할 수 있도록 설정합니다. 운영 환경 배포는 자동보다는 수동 확인 단계를 거치는 것이 안전할 때가 많습니다.
  • Permissions: id-token: write, contents: read는 GitHub Actions가 AWS와 OIDC(OpenID Connect)를 통해 연동하여 IAM 역할을 획득하는 데 필요합니다. 이를 통해 Access Key와 같은 장기 자격증명을 코드에 저장하지 않고도 안전하게 AWS에 인증할 수 있습니다. (매우 중요한 보안 베스트 프랙티스)
  • Jobs:
    1. configure-aws-credentials: AWS OIDC Provider 설정을 통해 임시 자격증명을 얻습니다.
    2. terraform-setup: hashicorp/setup-terraform 액션을 사용하여 특정 버전의 Terraform CLI를 설치합니다.
    3. terraform-plan: terraform init으로 백엔드와 프로바이더를 초기화하고, terraform plan을 실행하여 변경될 내용을 미리 확인합니다. 생성되는 플랜 파일은 아티팩트로 저장되어 다음 단계에서 사용됩니다.
    4. terraform-apply: plan 단계에서 생성된 플랜 파일을 기반으로 terraform apply를 실행하여 실제 인프라 변경을 수행합니다. auto-approve 옵션을 사용하여 상호작용 없이 적용을 완료합니다.

이러한 파이프라인은 Git을 Single Source of Truth로 삼아 인프라 변경 이력을 투명하게 관리하고, 사람의 실수를 줄이며, 빠르고 일관된 배포를 가능하게 합니다.


결론: 잘 만든 IaC는 살아있는 설계 문서다

onthetop 프로젝트의 EKS 구축 코드를 통해 우리는 단순한 리소스 생성을 넘어, 프로덕션 환경에서 요구되는 여러 핵심적인 DevOps 원칙들을 엿볼 수 있었습니다.

  • 모듈화와 환경 분리를 통한 코드의 재사용성 및 유지보수성 향상.
  • 보안을 최우선으로 고려한 네트워크 아키텍처 (Public/Private Subnet, NAT Gateway).
  • 최소 권한 원칙에 입각한 세분화된 IAM 역할 설계.
  • 고가용성과 탄력성을 위한 Multi-AZ 구성 및 Cluster Autoscaler 활용.
  • kubeconfigaws-auth 설정 자동화를 통한 프로비저닝 효율성 극대화.
  • OIDC를 활용한 안전한 CI/CD 파이프라인 구축.

eks terraform 코드
https://github.com/luckyPrice/onthetop-eks-terraform

0개의 댓글