ksc0204 님의 블로그

AEWS 4기 6주차(1) - EKS CI/CD(flux cd, tofu-controller) 본문

AWS 4기

AEWS 4기 6주차(1) - EKS CI/CD(flux cd, tofu-controller)

ksc0204 2026. 4. 22. 16:45

Before Start..

본 글은 공식 문서 및 서종호(가시다)님의 AWS EKS 워크샵 내용을 기반으로 참고하여 학습 목적으로 작성하였습니다.
주관적인 해석이 포함되어 있어 사실과 다르거나 오류가 있을 수 있으니 참고용으로만 읽어주시기 바랍니다.
본 글은 Amazon EKS 기반 확장 가능한 멀티 테넌틑 SaaS 플랫폼 구축에 대한 AWS Workshop 실습을 통해 작성한 내용입니다.

 

Workshop - 사전 구축된 서비스 확인

EKS 클러스터 및 워커 노드 확인(Kubernetes Cluster)

EKS 클러스터
EKS 워커 노드

Loadbalancer

ECR(Container Repository)

 

SQS(Simple Queue Service)

 

DynamoDB(NoSQL)

 

Gitea 저장소(source code Repository)

 


EKS 클러스터 - 네임스페이스 정보 확인

 

EKS 클러스터 - flux 리소스 확인

현재 클러스터는 Flux CD를 통해 Git 저장소를 바라보면서 Helm으로 필요한 서비스(Karpenter,ALB 등)를 배포하고, Image Automation을 통해 ECR의 새 이미지를 자동으로 클러스터에 반영하여 GitOps 파이프라인이 구축되어 있습니다.

(Control Plane, Data Plane(워커 노드), 이미지 자동 업데이트까지 설정되어 있으며, 용도는 아래와 같습니다.)

Flux 리소스 용도 확인

리소스 역할
gitrepository Flux가 변경 사항을 감시하는 Git 저장소
- flux-system : flux 시스템 설정 및 Kustomize/Helm 설정이 정의된 저장소
- terraform : Terraform 코드 저장소
helmrepository  Helm 차트가 저장된 저장소 위치(ECR 포함)
helmchart 각 Helm 저장소에서 EKS 클러스터로 가져온 차트
helmrelease 실제 배포 단위. 하나의 차트를 여러 테넌트에 배포
kustomization GitRepository를 가리키는 포인터, Kubernetes 구성 관리
imagerepository / imagepolicy 신규 컨테이너 이미지 태그 자동 감지 및 정책 적용
- imageRepository : 컨테이너 이미지가 변경되었는지 주기적으로 감시
- imagePolicy : 최신 이미지 파일 기준점 결정
imageupdateautomation 신규 이미지 감지 시 Git에 자동 Commit(Image Automation)
즉, git 저장소의 Kustomize 혹은 Helm 설정 매니페스트 내의 이미지 태그 값을 찾아 자동으로 Commit 및 Push
Kustomize란 ? 원본 YAML 파일을 건드리지 않고, 환경에 맞게 설정을 덮어쓰는 도구입니다.(Kubernetes 1.14 이상 버전부터 내장)

 

Gitea Repository 설정

접속 확인

 

Gitea 저장소 - Clone

# Clone the microservice repositories
git clone http://admin:${GITEA_TOKEN}@${GITEA_PRIVATE_IP}:${GITEA_PORT}/admin/producer.git
git clone http://admin:${GITEA_TOKEN}@${GITEA_PRIVATE_IP}:${GITEA_PORT}/admin/consumer.git
git clone http://admin:${GITEA_TOKEN}@${GITEA_PRIVATE_IP}:${GITEA_PORT}/admin/payments.git

git clone으로 다운로드된 파일 확인

 

flux-system.gitrepository 확인

kubectl -n flux-system get gitrepository -o yaml

spec 확인 설명
spec.interval: 1m0s 1분 주기
spec.ref.name:refs/heads/main main 브랜치의 최신 커밋을 지속적으로 감시
spec.secretRef.name: flux-system flux-system이 저장된 Git 저장소 자격 증명 Key 참조 
spec.url: http://~.git Git 저장소 URL
  • 즉, http://~admin/eks-saas-gitops..git 저장소 URL에서 main 브랜치를 1분 주기를 통해 감지하는 역할을 하며, git repository에 접근 시 flux-system secret에 저장된 key를 참조합니다.
status 확인 설명
artifact.digest 파일 변경 감지 확인
artifact.path Soure Controller 내부 저장소에서 압축 파일 로컬 경로(Pod 내 저장 경로)
artifact.url Kustomize Controller, Helm Controller 등에서 해당 아티팩트를 다운로드할 수 있는 내클러스터 내부 URL(클러스터 내 다른 Pod 다운로드 경로)

 


Terraform(tenant-apps)

해당 Workshop에서는 Terraform 모듈을 사용하여 AWS 리소스가 관리되고 있습니다.

terraform으로 정의된 리소스(codebuild,codepipeline,flux_cd,gitea,gitops-saas-infra,tenant-apps)

Terraform 디렉터리 구조 설명
flux_cd EKS 클러스터에 Flux 설치 리소스 구성
gitea Gitea 저장소에 필요한 리소스 구성
gitops-saas-infra Workshop 전체 인프라 구성
tenant-apps Tenant 애플리케이션 전용 인프라 구성
(2번째 실습에서 해당 모듈을 통해 온보딩 시 필요한 SQS와 DynamoDB 테이블, IRSA등 모든 인프라 프로비저닝 가능)

 

tenant-apps 모듈 테스트

해당 코드에서는 producer와 consumer를 생성하도록 설정하였습니다.(enable_producer, enable_consumer는 스위치 역할)

cd /home/ec2-user/environment/gitops-gitea-repo/

cat << EOF > terraform_test.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.100.0"
    }
  }
}

provider "aws" {}

module "test_tenant_apps" {
  source          = "./terraform/modules/tenant-apps"
  tenant_id       = "test"
  enable_producer = true
  enable_consumer = true
}
EOF

위 내용에서 source로 지정된 경로를 tenant-apps로 지정하여 실행합니다.

 

init & plan 확인

terraform init
terraform plan | tee -a tfplan-1.txt

 

plan 상세 내역 확인

DynamoDB - compumer_ddb 테이블 생성
IAM - consumer,producer 정책 생성
SQS - Consumer 생성
SSM(System Manager) Parameter 생성 - Consumer, Producer
무작위 문자열 생성
IRSA 생성 및 IAM 정책 매핑(consumer)
IRSA 생성 및 IAM 정책 매핑(producer)

 

enable_producer를 false로 변경 후 비교(변경된 부분 캡처)

cat << EOF > terraform_test.tf
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "5.100.0"
    }
  }
}

provider "aws" {}

module "test_tenant_apps" {
  source          = "./terraform/modules/tenant-apps"
  tenant_id       = "test"
  enable_producer = false
  enable_consumer = true
}
EOF

아래 로그를 통해서만 확인해보았을 때는 producer에 대한 IRSA는 생성되지 않았지만, sto-readonly-role-policy-attach로 policy가 생성되는 것을 확인할 수 있다.

 

아래 출력된 내용만으로는 sto-readonly-role-policy-attach에 어떠한 정책이 확인되는지는 알 수 없지만, IRSA를 생성하는 것보다 더 적은 권한을 가지도록 설정하는게 좋을것으로 판단됩니다.

실제 tenant-apps에 선언된 sto-readonly-role-policy-attach에 대한 조건문 확인 시 aws_iam_role_policy_attachment가 false이거나 var.enable_consumer가 '0'인 상태일 경우 count 값이 '0'으로 설정되며, producer-role-pool-1 정책이 매핑된 sto-readonly-role-policy-attach 역할을 생성합니다.

 

Tofu 컨트롤러란?

Tofu 컨트롤러는 쿠버네티스 환경에서 OpenTofu(HashiCorp Terraform의 오픈소스 포크 버전)를 사용하여 Infrastructure as Code(IaC)를 GitOps 방식으로 관리하기 위한 컨트롤러입니다.

 

Tofu - 주요 용도

  1. 인프라 GitOps 구현: Git 저장소를 인프라 상태의 유일한 Single Source of Truth으로 하여금 Git 커밋만으로 인프라를 프로비저닝, 수정, 삭제할 수 있습니다.
  2. 자동화된 조정 및 Drift 감지: 컨트롤러가 주기적으로 Git의 원하는(Desired) 상태와 실제(Real) 상태를 비교합니다. 만약 Git 저장소에서 Terraform 코드에 대한 변경 사항이 발생하면 Tofu 컨트롤러는 이를 감지하고 AWS 리소스에 대한 변경 사항이 있을 경우 실제 리소스에 반영하는 역할을 수행합니다.
  3. 쿠버네티스 통합 관리: 외부 인프라까지 쿠버네티스 리소스(Tofu Custom Resource)로 정의하여 관리할 수 있으므로, 애플리케이션과 그에 필요한 인프라를 하나의 일관된 방식으로 운영할 수 있습니다.
flux CD는 Git 저장소의 쿠버네티스의 manifest를 감시하여 클러스터 내부 리소스 상태를 Git과 동기화하는 역할 뿐만 아니라 Terraform 코드를 실행하기 위한 manifest 파일을 불러와 클러스터에 적용하는 역할도 수행합니다.

Tofu Controller는 외부 AWS 서비스를 관리하기 위한 Terraform 코드를 실행하는 역할 수행

flux CD와 Tofu 동작 방식(실습 환경 기준)

1. Gitea - git 저장소에 Terraform CRD 파일 추가

2. flux cd - Git 저장소 변경 감지

3. Tofu Controller - Terraform CRD 감지

4. Tofu Runner - Pod 실행(Git 저장소에서 Terraform 모듈(.tf) pull)

5. Terraform apply - AWS 서비스 생성(SQS, DynamoDB, IRSA)

6. 실행 상태/플랜을 Kubernetes Secret으로 저장

 

tf-conroller 상태 확인

kubectl get pod -n flux-system -l app.kubernetes.io/instance=tf-controller

 

Terraform CRD 생성 및 배포

cat << EOF > /home/ec2-user/environment/gitops-gitea-repo/application-plane/production/tenants/example-tenant-terraform-crd.yaml
---
apiVersion: infra.contrib.fluxcd.io/v1alpha2
kind: Terraform
metadata:
  name: example-tenant
  namespace: flux-system
spec:
  path: ./terraform/modules/tenant-apps
  interval: 1m
  approvePlan: auto
  destroyResourcesOnDeletion: true
  sourceRef:
    kind: GitRepository
    name: terraform-v0-0-1
  vars:
    - name: tenant_id
      value: example-tenant
    - name: "enable_producer"
      value: true
    - name: "enable_consumer"
      value: true
  writeOutputsToSecret:
    name: example-tenant-infra-output
EOF
코드 분석 설명
spec.path: ./terraform/modules/tenant-apps 실제 실행할 Terraform 모듈 파일들(.tf 파일들)이 깃(Git) 저장소 내의 어느 폴더에 위치해 있는지 지정
spec.approvePlan: auto Terraform의 실행 계획(terraform plan)이 생성되었을 때, 수동 승인 과정 없이 자동으로 적용(terraform apply) 하도록 설정
spec.destroyResourcesOnDeletion 중요한 보안/관리 설정입니다. 해당 CRD가 클러스터에서 삭제될 경우 Terraform을 통해 생성되었던 실제 AWS 자원들도 함께 삭제(terraform destroy)하도록 설정
spec.sourceRef.kind: GitRepository
spec.sourceRef.name: terraform-v0-0-1
kind: GitRepository, name: terraform-v0-0-1
위에서 지정한 path를 찾기 위해 참조할 소스 코드 저장소입니다. 클러스터 내에 미리 정의된 terraform-v0-0-1이라는 이름의 GitRepository 리소스(Git 연결 정보)를 사용합니다.
spec.vars Terraform 코드에 입력값으로 전달할 변수 목록
tenant_id: "example-tenant"
enable_producer: true (producer module 활성화)
enable_consumer: true (consumer module 활성화)
spec.writeOutputsToSecret name: example-tenant-infra-output: terraform apply가 성공적으로 끝난 후 생성되는 Terraform Output 값들을 Kubernetes의 Secret 객체로 저장합니다.

 

fluxcd에 GitRepository 객체로 등록된 terraform 확인 시 tag 값과 URL을 통해 확인할 수 있습니다. 해당 태그 값은 git tag값과 동일합니다.

tenant-app kustomize 등록

작성한 Terraform CRD는 그 자체로는 Git 저장소에 존재하는 단순한 텍스트 파일이며, 쿠버네티스 클러스터는 이 파일의 존재를 혼자서 자각할 수 없습니다.

Flux의 Kustomization 리소스가 생성된 경로(Path)를 바라보고 있다가, 새로운 파일(terraform)을 발견하면 이를 쿠버네티스 클러스터에 kubectl apply 합니다.

cat << EOF > /home/ec2-user/environment/gitops-gitea-repo/application-plane/production/tenants/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - basic
  - advanced
  - premium
  - example-tenant-terraform-crd.yaml
EOF

 

Git Commit - 변경 사항 Git 저장소 반영

cd /home/ec2-user/environment/gitops-gitea-repo/
git pull origin main
git status
git add .
git commit -am "Added example terraform CRD for testing"
git push origin main

# flux cd 강제 반영
flux reconcile source git flux-system

이후 example-tenant-tf-runner와 pool-1-tf-runner Pod가 생성되었고, pool-1-tf-runner에 파드가 계속해서 지워지고 생성되기를 반복하여 AWS 서비스를 계속해서 프로비저닝 됩니다.

AWS 리소스 생성 확인(DynamoDB, SQS)

 

example-tenant-terraform-crd.yaml 파일 삭제

기존 Terraform CRD를 정의할 때 destroyResourceOnDeletion: true로 설정하였고, 이번에는 Git 저장소에서 해당 파일이 삭제되었을 경우 AWS 서비스(DynamoDB, SQS)도 같이 삭제가 되는지 확인하였습니다.

# terraform yaml 파일 삭제
rm /home/ec2-user/environment/gitops-gitea-repo/application-plane/production/tenants/example-tenant-terraform-crd.yaml

# kustomize 파일 수정
cat << EOF > /home/ec2-user/environment//gitops-gitea-repo/application-plane/production/tenants/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
    - basic
    - advanced
    - premium
EOF

# Git 업데이트 및 Commit
cd /home/ec2-user/environment/gitops-gitea-repo/
git pull origin main
git add .
git commit -m "Removed Terraform CRD and reference from kustomization.yaml"
git push origin main

# flux 강제 반영
flux reconcile source git flux-system

# 로그 확인
kubectl logs example-tenant-tf-runner -n flux-system -f

로그 확인

리소스 삭제 확인

dynamodb 및 sqs 삭제 확인
terraform plan 및 apply 결과값 secret에 저장됨