Pool namespace에 앱이 배포될 때 노드가 부족하면 Karpenter가 자동으로 노드 추가
5) 비용 모니터링 : kubecost
테넌트별 비용을 추적하는 도구
SaaS에서 테넌트마다 얼마나 리소스를 쓰는지 파악하는 게 중요하니까 함께 구성된 것입니다.
Flux 리소스 확인
Flux는 이 솔루션의 핵심 엔진으로, Git 및 ECR의 변경 사항을 감시하여 클러스터 상태를 선언된 상태와
일치시키는 역할을 담당합니다. 다음 명령으로 전체 Flux 리소스를 확인해볼까요 ?
[ec2-user@ip-10-0-1-79 environment]$ flux get all
NAME REVISION SUSPENDED READY MESSAGE
ocirepository/capacitor v0.4.8@sha256:1efcb443 False True stored artifact for digest 'v0.4.8@sha256:1efcb443'
NAME REVISION SUSPENDED READY MESSAGE
gitrepository/flux-system refs/heads/main@sha1:83debf83 False True stored artifact for revision 'refs/heads/main@sha1:83debf83'
gitrepository/terraform-v0-0-1 v0.0.1@sha1:2d19a84a False True stored artifact for revision 'v0.0.1@sha1:2d19a84a'
NAME REVISION SUSPENDED READY MESSAGE
helmrepository/argo sha256:77d58f2f False True stored artifact: revision 'sha256:77d58f2f'
helmrepository/eks-charts sha256:d5d7cd31 False True stored artifact: revision 'sha256:d5d7cd31'
helmrepository/helm-application-chart False True Helm repository is Ready
helmrepository/helm-tenant-chart False True Helm repository is Ready
helmrepository/karpenter False True Helm repository is Ready
helmrepository/kubecost False True Helm repository is Ready
helmrepository/metrics-server sha256:ba69c5bb False True stored artifact: revision 'sha256:ba69c5bb'
helmrepository/tf-controller sha256:1fcad0f6 False True stored artifact: revision 'sha256:1fcad0f6'
NAME REVISION SUSPENDED READY MESSAGE
helmchart/flux-system-argo-events 2.4.3 False True pulled 'argo-events' chart with version '2.4.3'
helmchart/flux-system-argo-workflows 0.40.11 False True pulled 'argo-workflows' chart with version '0.40.11'
helmchart/flux-system-aws-load-balancer-controller 1.6.2 False True pulled 'aws-load-balancer-controller' chart with version '1.6.2'
helmchart/flux-system-karpenter 1.4.0 False True pulled 'karpenter' chart with version '1.4.0'
helmchart/flux-system-kubecost 2.1.0 False True pulled 'cost-analyzer' chart with version '2.1.0'
helmchart/flux-system-metrics-server 3.11.0 False True pulled 'metrics-server' chart with version '3.11.0'
helmchart/flux-system-onboarding-service 0.0.1 False True pulled 'application-chart' chart with version '0.0.1'
helmchart/flux-system-pool-1 0.0.1 False True pulled 'helm-tenant-chart' chart with version '0.0.1'
helmchart/flux-system-tf-controller 0.16.0-rc.4 False True pulled 'tf-controller' chart with version '0.16.0-rc.4'
NAME LAST SCAN SUSPENDED READY MESSAGE
imagerepository/consumer-image-repository 2026-04-26T17:04:07Z False True successful scan: found 2 tags with checksum 1936459500
imagerepository/payments-image-repository 2026-04-26T17:04:07Z False True successful scan: found 2 tags with checksum 1936983789
imagerepository/producer-image-repository 2026-04-26T17:04:07Z False True successful scan: found 2 tags with checksum 1937901294
NAME IMAGE TAG READY MESSAGE
imagepolicy/consumer-image-policy 398879295738.dkr.ecr.us-west-2.amazonaws.com/consumer prd-20260424T054936Z True Latest image tag for 398879295738.dkr.ecr.us-west-2.amazonaws.com/consumer resolved to prd-20260424T054936Z
imagepolicy/payments-image-policy 398879295738.dkr.ecr.us-west-2.amazonaws.com/payments prd-20260424T054919Z True Latest image tag for 398879295738.dkr.ecr.us-west-2.amazonaws.com/payments resolved to prd-20260424T054919Z
imagepolicy/producer-image-policy 398879295738.dkr.ecr.us-west-2.amazonaws.com/producer prd-20260424T054956Z True Latest image tag for 398879295738.dkr.ecr.us-west-2.amazonaws.com/producer resolved to prd-20260424T054956Z
NAME LAST RUN SUSPENDED READY MESSAGE
imageupdateautomation/consumer-update-automation-pooled-envs 2026-04-26T17:02:20Z False True repository up-to-date
imageupdateautomation/consumer-update-automation-tenants 2026-04-26T17:04:06Z False True repository up-to-date
imageupdateautomation/payments-update-automation-pooled-envs 2026-04-26T17:02:20Z False True repository up-to-date
imageupdateautomation/payments-update-automation-tenants 2026-04-26T17:04:06Z False True repository up-to-date
imageupdateautomation/producer-update-automation-pooled-envs 2026-04-26T17:02:20Z False True repository up-to-date
imageupdateautomation/producer-update-automation-tenants 2026-04-26T17:04:07Z False True repository up-to-date
NAME REVISION SUSPENDED READY MESSAGE
helmrelease/argo-events 2.4.3 False True Helm install succeeded for release argo-events/argo-events.v1 with chart argo-events@2.4.3
helmrelease/argo-workflows 0.40.11 False True Helm install succeeded for release argo-workflows/argo-workflows.v1 with chart argo-workflows@0.40.11
helmrelease/aws-load-balancer-controller 1.6.2 False True Helm install succeeded for release aws-system/aws-load-balancer-controller.v1 with chart aws-load-balancer-controller@1.6.2
helmrelease/karpenter 1.4.0 False True Helm install succeeded for release karpenter/karpenter.v1 with chart karpenter@1.4.0
helmrelease/kubecost 2.1.0 False True Helm install succeeded for release kubecost/kubecost.v1 with chart cost-analyzer@2.1.0
helmrelease/metrics-server 3.11.0 False True Helm install succeeded for release kube-system/metrics-server.v1 with chart metrics-server@3.11.0
helmrelease/onboarding-service 0.0.1 False True Helm install succeeded for release onboarding-service/onboarding-service.v1 with chart application-chart@0.0.1
helmrelease/pool-1 0.0.1 False True Helm upgrade succeeded for release pool-1/pool-1.v2 with chart helm-tenant-chart@0.0.1
helmrelease/tf-controller 0.16.0-rc.4 False True Helm install succeeded for release flux-system/tf-controller.v1 with chart tf-controller@0.16.0-rc.4
NAME REVISION SUSPENDED READY MESSAGE
kustomization/capacitor v0.4.8@sha256:1efcb443 False True Applied revision: v0.4.8@sha256:1efcb443
kustomization/controlplane refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
kustomization/dataplane-pooled-envs refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
kustomization/dataplane-tenants refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
kustomization/dependencies refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
kustomization/flux-system refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
kustomization/infrastructure refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
kustomization/sources refs/heads/main@sha1:83debf83 False True Applied revision: refs/heads/main@sha1:83debf83
[ec2-user@ip-10-0-1-79 environment]$
위 리소스 들을 아래와 같이 한번 살펴봅시다.
1) Git/OCI Repository (소스 감시 대상)
gitrepository/flux-system : Gitea GitOps 저장소 (main 브랜치) 감시 중 gitrepository/terraform-v0-0-1 : Terraform 모듈 저장소 (v0.0.1 태그) 감시 중 ocirepository/capacitor : Flux UI 도구 (OCI 이미지) 감시 중
2) Helm Repository (차트 저장소)
helmrepository/argo : Argo Workflows/Events 차트 helmrepository/karpenter : Karpenter 차트 helmrepository/kubecost : 비용 모니터링 차트 helmrepository/tf-controller : Tofu Controller 차트 helmrepository/helm-application-chart : onboarding-service용 차트 (ECR OCI) helmrepository/helm-tenant-chart : pool-1 테넌트용 차트 (ECR OCI)
3) Image Repository + Policy (이미지 자동 업데이트)
imagerepository/producer-image-repository : ECR의 producer 이미지 태그 스캔 중 imagerepository/consumer-image-repository : ECR의 consumer 이미지 태그 스캔 중 imagerepository/payments-image-repository : ECR의 payments 이미지 태그 스캔 중
그리고 이미지 뒤에 태그가 붙어있는데요, Flux가 ECR을 주기적으로 스캔해서 새 이미지 태그가 올라오면
자동으로 감지합니다. 'prd-YYYYMMDDTHHmmssZ' 형식이 태그 네이밍 규칙이에요.
Gitea Actions가 빌드 후 이 형식으로 태그를 붙여서 ECR에 올리는 것입니다 !
4) Image Update Automation (자동 배포 트리거)
imageupdateautomation/producer-update-automation-pooled-envs : pool 환경용 imageupdateautomation/producer-update-automation-tenants : silo 환경용
(consumer, payments도 동일한 구조)
흐름으로 본다면 아래와 같습니다.
Gitea Actions → ECR에 새 이미지 Push (prd-새타임스탬프)
↓
Flux ImageRepository가 새 태그 감지
↓
ImagePolicy가 최신 태그 결정
↓
ImageUpdateAutomation이 Gitea GitOps Repo의
values.yaml 이미지 태그를 자동으로 수정 + commit
↓
Flux GitRepository가 변경 감지
↓
HelmRelease Reconcile → 새 이미지로 롤링 업데이트
즉 개발자가 코드만 Push하면 ECR → Gitea → EKS 배포까지 자동으로 배포됩니다.
6) Kustomization (GitOps 구조 계층)
kustomization/flux-system : Flux 자체 부트스트랩 kustomization/sources : Git/Helm 저장소 정의 kustomization/dependencies : 의존성 순서 관리 kustomization/infrastructure : Karpenter, LBC 등 인프라 kustomization/controlplane : onboarding-service 등 플랫폼 서비스 kustomization/dataplane-pooled-envs : pool-1 같은 공유 환경 kustomization/dataplane-tenants : silo 테넌트 환경 kustomization/capacitor : flux UI
Gitea 저장소 접근 설정
이번 워크숍에서는 Gitea 서버에 호스팅된 여러 저장소에 접근하여 클론해야 합니다.
먼저 이러한 저장소에 대한 접근 권한을 설정해 보겠습니다.
먼저 웹 인터페이스 접속을 위한 Gitea URL과 관리자 자격 증명을 가져오겠습니다.
# Get Gitea IPs from the configuration
export GITEA_PRIVATE_IP=$(kubectl get configmap saas-infra-outputs -n flux-system -o jsonpath='{.data.gitea_url}')
export GITEA_PUBLIC_IP=$(kubectl get configmap saas-infra-outputs -n flux-system -o jsonpath='{.data.gitea_public_url}')
export GITEA_PORT="3000"
# Get Gitea admin password from Systems Manager Parameter Store
export GITEA_ADMIN_PASSWORD=$(aws ssm get-parameter --name "/eks-saas-gitops/gitea-admin-password" --with-decryption --query 'Parameter.Value' --output text)
# Display access information for web browser login
echo "=== Gitea Web Interface Access ==="
echo "Public URL (for browser access): $GITEA_PUBLIC_IP"
echo "Username: admin"
echo "Password: $GITEA_ADMIN_PASSWORD"
echo "=================================="
echo ""
echo "Use the PUBLIC URL above to access Gitea from your web browser."
저장소 접근 변수 설정
ConfigMap에서 필요한 값을 추출하고 환경을 설정해봅시다.
# Extract Gitea configuration from ConfigMap
export GITEA_TOKEN=$(kubectl get configmap saas-infra-outputs -n flux-system -o jsonpath='{.data.gitea_token}')
# Set up the repository paths used throughout the workshop
export REPO_PATH="/home/ec2-user/environment/microservice-repos"
export GITOPS_REPO_PATH="/home/ec2-user/environment/gitops-gitea-repo"
mkdir -p $REPO_PATH
필요한 저장소 복제
워크숍 동안 사용할 저장소를 복제해볼까요 ?
cd $REPO_PATH
# 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
tree
├── consumer
│ ├── Dockerfile
│ ├── consumer.py
│ └── requirements.txt
├── payments
│ ├── Dockerfile
│ ├── payments.py
│ └── requirements.txt
└── producer
├── Dockerfile
├── producer.py
└── requirements.txt
# Verify the repositories were cloned successfully
echo "Microservice repositories:"
ls -la $REPO_PATH
echo ""
echo "GitOps repository:"
ls -la $GITOPS_REPO_PATH
Flux 저장소 구성 확인
Flux는 Gitea 저장소의 변경 사항을 감시하고 클러스터 상태와 일치시키도록 구성되어 있습니다.
Flux가 모니터링하는 gitops 저장소 위치를 확인하려면 다음 명령을 실행하세요.
Check : flux-system과 terraform-v0-0-1 두 레포지토리가 READY=TRUE 상태인지 확인.
Terraform 및 OpenTofu 컨트롤러
이번 Lab에서는 Terraform 모듈 구조를 이해하고, Tofu Controller를 통해 GitOps 방식으로
AWS 인프라를 자동 프로비저닝하는 흐름을 직접 실습합니다.
핵심 흐름은 아래와 같아요
Git에 Terraform CRD 파일 Push
↓
Flux가 변경 감지
↓
Tofu Controller가 tf-runner Pod 실행
↓
terraform apply → AWS 리소스 생성 (DynamoDB, SQS)
애플리케이션 인프라는 Terraform 모듈로 정의되어 있으며, GitOps 저장소의 다음 경로에 위치한다.
gitops-gitea-repo/terraform/modules/
모듈 구성은 아래와 같아요.
modules/
├── flux_cd # EKS에 Flux를 설치하는 데 필요한 리소스
├── gitea # Gitea 저장소에 필요한 리소스
├── gitops-saas-infra # 워크숍 전체 인프라 구성 리소스
└── tenant-apps # 테넌트 애플리케이션 인프라 구성 요소
├── data.tf
├── main.tf
├── outputs.tf
├── README.md
├── variables.tf
└── versions.tf
각 모듈 역할
모듈
역할
flux_cd
EKS 클러스터에 Flux v2 설치에 필요한 리소스 정의
gitea
내부 Git 서버(Gitea) 구성에 필요한 리소스 정의
gitops-saas-infra
워크숍 전체 기반 인프라 구성
tenant-apps
테넌트 온보딩 시 생성되는 AWS 리소스 정의 (SQS, DynamoDB, IRSA 등)
Terraform Aggregated Module 패턴
이 워크숍에서는 Aggregated Module 패턴을 사용합니다. 사용자는 최상위 모듈 하나만 호출하면,
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
4) Flux Reconcile 강제 실행 (선택)
폴링 주기를 기다리지 않고 즉시 반영하려면:
flux reconcile source git flux-system
5) tf-runner Pod 및 AWS 리소스 확인
잠시 후 tf-runner Pod가 생성되어 Terraform을 실행한다.
# tf-runner Pod 확인
kubectl get pod -n flux-system
# tf-runner 로그 실시간 확인
kubectl logs pod/example-tenant-tf-runner -n flux-system -f
# DynamoDB 테이블 생성 확인
# consumer-example-tenant- 접두사의 테이블이 생성되어 있어야 함
aws dynamodb list-tables
# SQS 큐 생성 확인
# consumer-example-tenant- 접두사의 SQS 큐가 생성되어 있어야 함
aws sqs list-queues
📌 Terraform CRD 삭제 (리소스 정리)
GitOps의 핵심 원칙대로, 리소스를 삭제할 때도 Git에서 CRD를 제거하기만 하면 됩니다.
destroyResourcesOnDeletion: true 설정 덕분에 CRD가 삭제되면 생성된 AWS 리소스도 자동으로 삭제된다.
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
Helm 차트는 Kubernetes 애플리케이션을 정의, 설치, 관리하는 패키징 도구입니다.
이 워크숍에서 사용하는 Helm 차트의 구조를 이해하고, helm template 명령어로 실제 배포 없이
렌더링 결과를 미리 확인하는 방법을 실습합니다.
📌 Helm Chart란?
Helm 차트는 서로 관련된 Kubernetes 리소스 세트를 하나의 패키지로 묶은 것입니다.
예를 들어 Producer 앱 하나를 배포하려면 Deployment, Service, Ingress, HPA, ServiceAccount 등
여러 YAML 파일이 필요한데, Helm은 이것들을 하나의 차트로 묶어서 관리한다.
차트 기본 구조:
Chart.yaml # 차트 이름, 버전, 설명 등 메타데이터
values.yaml # 템플릿에서 사용하는 기본값 정의
charts/ # 이 차트가 의존하는 하위 차트 디렉토리
templates/ # 실제 Kubernetes 매니페스트 템플릿 파일들
├── deployment.yaml
├── service.yaml
├── ingress.yaml
├── hpa.yaml
├── serviceaccount.yaml
├── terraform.yaml
└── ...
Chart.yaml : 차트 이름, 버전, 설명 등 메타데이터
values.yaml : 템플릿 변수의 기본값. 배포 시 재정의 가능
charts/ : 이 차트가 의존하는 서브 차트 모음
templates/ : values.yaml의 값과 결합되어 최종 Kubernetes YAML을 생성하는 템플릿
이렇게 하면 Flux의 HelmRepository가 ECR을 차트 저장소로 사용할 수 있습니다.
HelmRelease란?
HelmRelease는 Flux에서 제공하는 CRD로, Helm 릴리즈를 선언적으로 관리할 수 있게 해준다.
기존 방식과 비교해볼까요?
[기존 방식 - 직접 실행]
helm install example-tenant ./helm-tenant-chart --values values.yaml
→ 사람이 직접 실행, Git과 연동 안 됨
[HelmRelease GitOps 방식]
Git에 HelmRelease YAML 파일 추가
→ Flux가 감지 → 자동으로 helm install/upgrade 실행
→ 차트 버전 변경, values 변경도 Git Push만으로 반영
HelmRelease 예시 (example-tenant-premium)
apiVersion: v1
kind: Namespace
metadata:
name: example-tenant
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: example-tenant-premium
namespace: flux-system
spec:
releaseName: example-tenant-premium
targetNamespace: example-tenant # 실제 앱이 배포될 Namespace
storageNamespace: example-tenant # Helm 릴리즈 메타데이터 저장 위치
interval: 1m0s # 1분마다 Reconcile
chart:
spec:
chart: helm-tenant-chart # 사용할 차트 이름
version: "0.x" # 0.x 버전 중 최신 사용
sourceRef:
kind: HelmRepository
name: helm-tenant-chart # ECR을 가리키는 HelmRepository
values:
tenantId: example-tenant
apps:
producer:
enabled: true # Silo 배포 - Premium 티어는 테넌트별 전용 Deployment
consumer:
enabled: true # Silo 배포 - Premium 티어는 테넌트별 전용 Deployment
주요 필드를 아래 표와 같이 설명드리겠습니다.
filed
describtion
targetNamespace
실제 Kubernetes 리소스(Deployment, Service 등)가 배포될 Namespace
storageNamespace
Helm이 릴리즈 상태를 저장하는 Secret이 생성될 Namespace
interval: 1m0s
Flux가 1분마다 Git과 실제 클러스터 상태를 비교하고 동기화
chart.spec.version: "0.x"
0.x 범위의 최신 차트를 자동으로 사용 (예: 0.0.2가 올라오면 자동 업그레이드)
sourceRef
차트를 가져올 저장소 - ECR을 가리키는 HelmRepository CRD 참조
values
helm install --values와 동일. 테넌트별 설정값 주입
HelmRepository - ECR과의 연결
HelmRelease의 sourceRef가 가리키는 HelmRepository는
Flux가 Helm 차트를 가져오는 저장소 정보를 담고 있다.
kubectl get HelmRepository -n flux-system | grep -i helm-tenant-chart
cd /home/ec2-user/environment/gitops-gitea-repo/
git pull origin main
git add .
git commit -m "Added HelmRelease for example-tenant"
git push origin main
Step4. Flux Reconcile 강제 실행
flux reconcile source git flux-system
참고: Flux가 HelmRelease와 Terraform CRD를 통합하고 리소스를 생성하는 데 다소 시간이 걸립니다. tf-runner 로그로 진행 상황을 확인할 수 있다.
sed -i '/example-tenant-helmrelease.yaml/d' \
/home/ec2-user/environment/gitops-gitea-repo/application-plane/production/tenants/kustomization.yaml
3) Git Push
cd /home/ec2-user/environment/gitops-gitea-repo/
git pull origin main
git add .
git commit -m "Removed HelmRelease for example-tenant"
git push origin main
4) Flux Reconcile 및 삭제 확인
flux reconcile source git flux-system
# Kubernetes 리소스 삭제 확인
kubectl get namespaces
kubectl get all -n example-tenant
# AWS 리소스 삭제 확인
aws dynamodb list-tables
aws sqs list-queues
★ 중요 : 실제 테넌트 온보딩 시 이 두 가지가 동시에 동작합니다.
Git에 테넌트 설정 Push (HelmRelease + Terraform CRD)
↓
Flux Reconcile
├─ HelmRelease → Helm Controller → ECR에서 차트 Pull → helm install
│ └─ example-tenant ns: Deployment, Service, Ingress, HPA 생성
│
└─ Terraform CRD → Tofu Controller → tf-runner Pod → terraform apply
└─ AWS: DynamoDB 테이블, SQS 큐, IAM Role 생성