CloudNet@ Team Study/EKS Workshop 4th Cohort

Introducing CI/CD configuration in the EKS environment.

"Everything about infra" 2026. 4. 23. 03:55
포스팅은 CloudNet@팀 서종호(Gasida)님이 진행하시는
AWS EKS Workshop Study 내용을 참고하여 작성합니다.

 

AWS Container Specialist Ian Y. Choi 님이 열강해주셨는데요,

앞으로 GitOps를 활용하여 EKS 기반 SaaS 애플리케이션 아키텍처를

소개하는 챕터가 될 것 같습니다.

 

복잡한 SaaS DevOps 요구사항을 충족하기 위해 Flux v2 기반 환경 아키텍처 입니다.

 

 

01. 실습 워크숍 아키텍처 개요

이번 실습은 GitOps 기반 멀티테넌트 SaaS 플랫폼을 EKS 위에서 구현하는 환경입니다.

다이어그램 flow를 기준으로 실습 아키텍처를 소개드리겠습니다.

 

Flow 1. 앱 소스코드 → ECR (CI 흐름)

Gitea Microservice Repository
  (Producer / Consumer 소스코드)
        ↓
   Gitea Actions
   (GitHub Actions와 문법 동일한 내장 CI)
        ↓
  Amazon ECR
  ├─ Producer Service Image
  └─ Consumer Service Image

Gitea는 GitHub처럼 생긴 Git 서버인데, 내 서버(여기서는 EKS)에 직접 설치해서 쓰는 오픈소스 입니다.

(이번 실습에서는 GitHub 대신 Gitea를 사용합니다)

 

Gitea Actions는 GitHub Actions랑 문법이 거의 동일한 CI 기능이 내장되어 있어서,

소스코드가 Push되면 자동으로 컨테이너 이미지를 빌드해서 ECR에 올려줍니다.

 

Flow 2. Gitea GitOps Repository 구성

Gitea GitOps Repository
  ├─ Application Template  (Helm 차트 + Terraform 정의)
  └─ Pool Environment Release Config  (테넌트별 설정값)

소스코드 저장소와 별도의 GitOps 전용 저장소가 있습니다.

여기엔 앱 배포 방법(Helm 차트)과 AWS 리소스 정의(Terraform)가 들어있어요.
이게 이 아키텍처에서 "유일한 진실의 원천(Source of Truth)" 역할을 합니다.
클러스터 상태를 바꾸고 싶으면 반드시 이 저장소를 통해야 해요.

 

Flow 3. Flux가 GitOps Repository를 Watch

Gitea GitOps Repository
        ↓  Watches (30초~1분 주기로 폴링)
  flux-system namespace (EKS 내부)
  ├─ Flux v2 (Git 감시 + Reconcile 실행)
  └─ Tofu Controller (Terraform 실행기)

Flux v2는 EKS 안에 Pod으로 떠 있는 컨트롤러입니다. Gitea GitOps 저장소를 계속 감시하다가

변경이 감지되면 클러스터에 자동으로 반영(Reconcile)해줘요.

 

원래 Terraform은 개발자가 로컬에서 직접 terraform apply를 치지만,

Tofu Controller를 쓰면 EKS Pod 안에서 Terraform이 실행되는게 장점입니다 !

(그래서 Git에 Terraform 코드를 올리는 것만으로 AWS 리소스 생성까지 자동화됩니다.)

 

Flow 4. Reconcile → Pool Namespace 구성

Flux Reconcile
        ↓
  Pool namespace (basic tier)
  ├─ HPA
  ├─ Deployment  (Producer / Consumer 앱)
  ├─ Ingress
  └─ Terraform CR  (Tofu Controller가 실행)
        ↓
  AWS Tenant Application Resources
  ├─ Amazon DynamoDB  (테넌트별 데이터 저장소)
  └─ Amazon SQS       (Producer → Consumer 메시지 큐)

테넌트별 격리 단위는 Namespace 입니다. Flux가 Reconcile을 실행하면 해당 테넌트의 Namespace에

앱이 배포되고, Tofu Controller가 Terraform을 실행해서 DynamoDB와 SQS까지 함께 프로비저닝해줘요.

( 이 모든 게 Git Push 하나로 자동으로 일어나는 것입니다 )

 

Flow 5. Helm Chart Image 참조 (ECR OCI)

Gitea GitOps Repository의 HelmRelease
        ↓  References
  Amazon ECR (Helm Chart Image 저장소)
  └─ Application Helm Chart Image (OCI 형식)

Helm 차트 자체도 OCI 이미지 형태로 ECR에 저장되어 있습니다. Flux의 HelmRelease가

ECR을 참조해서 차트를 가져오는 구조에요. 즉 ECR은 앱 컨테이너 이미지Helm 차트 이미지

두 가지를 모두 저장하는 역할을 합니다.

 

📌 전체 흐름 요약

[CI 흐름 - 앱 빌드]
Gitea Microservice Repo → Gitea Actions → ECR (앱 이미지)

[GitOps 흐름 - 배포/인프라]
Gitea GitOps Repo → Flux Watch → Reconcile
                                    ├─ Helm → Pool Namespace에 앱 배포
                                    └─ Tofu Controller → DynamoDB / SQS 생성

[테넌트 관리]
Argo Workflows → Onboarding/Offboarding 자동화
               → Gitea GitOps Repo에 테넌트 설정 파일 추가/삭제

여기서 핵심 포인트는 운영자가 새 테넌트를 추가할 때 AWS 콘솔, kubectl & terraform apply 등

명령어를 칠 필요가 없습니다.

 

Argo Workflows로 온보딩을 트리거하면 Gitea에 설정 파일이 생성되고, Flux가 감지해서

앱 배포와 AWS 리소스 생성을 전부 자동으로 처리해줘요. 이게 플랫폼 엔지니어링 입니다!

 

Why is a platform Engineering structure necessary?

실습 환경 아키텍처에 대해서 설명드렸는데, 저도 처음에 감이 안잡혀서 부연 설명을 드리고자 합니다.

이런 플랫폼 엔지니어링 구조가 명확하게 왜 필요할까?

 

먼저, 일반적인 스타트업이 SaaS를 운영한다고 가정해봅시다.

  • 고객(테넌트)이 100명이면 → 100개의 환경을 만들어야 합니다.
  • 각 테넌트마다 DB, 큐, 앱 배포를 수동으로 하면 저희 운영팀이 힘들어요 ..
  • 그래서 "테넌트 추가 = Git에 설정 파일 하나 올리면 끝" 이 되도록 자동화하는 게 이번 주차 핵심 !

위에서 설명드린 플랫폼 엔지니어링 아키텍처를 구현하기 위한 도구들을 설명드리겠습니다.

 

Gitea란? GitHub를 내 서버에 직접 설치해서 쓰는 것

GitHub, GitLab을 써봤나요? 이것들은 SaaS입니다. 즉 남의 서버에 올리는 거에요.

Gitea는 그걸 내 서버(여기서는 EKS)에 직접 설치해서 쓰는 오픈소스 Git 서버 입니다.

 

그렇다면 이번 실습에서 Gitea를 쓰는 이유는 추측해보기에는 ..

  • AWS Workshop 환경이라 인터넷의 GitHub에 접근하기 어려운 구조
  • 실제 기업 환경도 보안상 내부망에 Git 서버를 두는 경우가 많음
  • Gitea Actions = GitHub Actions랑 문법이 거의 동일한 CI 기능도 내장

 

Flux v2란? 변경이 생기면 클러스터에 자동으로 반영해주는 쿠버네티스 컨트롤러

기존 방식이랑 비교해볼까요?

[기존 Push 방식]
운영자 → kubectl apply 또는 helm install → 클러스터 반영
문제: 누군가 kubectl로 직접 클러스터를 수동 변경하면 Git이랑 상태가 어긋남

[Flux GitOps 방식]
운영자 → Git에 Push → Flux가 감지 → 클러스터 자동 반영
장점: 클러스터 상태는 항상 Git 내용과 일치가 보장됨

Flux는 EKS 안에 Pod으로 떠 있고, Gitea 저장소를 30초~1분 간격으로 polling 합니다.

즉, 변경이 감지되면 알아서 helm upgrade 또는 kubectl apply를 실행합니다.

 

Tofu Controller란? Terraform 코드를 EKS Pod 안에서 실행시켜주는 컨트롤러

원래 Terraform은 운영자 로컬 PC에서 'terraform apply'를 통해 Provider 리소스를 생성합니다.

그러면 Tofu를 사용하면 뭐가 다를까요?

Git에 Terraform 코드 Push
    ↓
Flux가 감지
    ↓
Tofu Controller Pod이 terraform apply 실행
    ↓
AWS 리소스(DynamoDB, SQS 등) 생성

즉, Terraform을 실행하는 주체가 운영자 로컬PC / CI 서버 → EKS Pod으로 바뀌는 거에요.

이게 왜 좋냐면 테넌트가 추가될 때마다 Git에 설정 파일 하나만 올리면 Flux → Tofu Controller가 알아서

AWS 리소스까지 만들어줍니다. 사람이 'terraform apply'를 칠 필요가 없겠죠 ?

참고로 OpenTofu는 Terraform의 오픈소스 포크입니다.
HashiCorp가 Terraform 라이선스를 변경한 이후에 커뮤니티가 만든 대안이고, 문법은 거의 동일합니다.

 

Argo Workflows란? 쿠버네티스 위에서 실행되는 작업 자동화 도구

Argo CD(배포 도구)랑 헷갈릴 수 있는데 다른 도구이고, Jenkins 같은 파이프라인과 유사합니다.

Argo CD        = GitOps 배포 도구 (Flux랑 경쟁 관계)
Argo Workflows = 순서가 있는 작업(Job)을 실행하는 워크플로우 엔진

이번 실습에서 Argo Workflows의 역할은 아래와 같습니다.

새 테넌트 추가 요청 발생
    ↓
Argo Workflows "Onboarding" 워크플로우 실행
    ↓
Step 1: Gitea에 테넌트 설정 파일 생성 (Git Push)
Step 2: Flux가 변경 감지
Step 3: Tofu Controller가 DynamoDB/SQS 생성
Step 4: Helm이 앱 배포
    ↓
테넌트 환경 완성

반대로 테넌트 해지 시엔 "Offboarding" 워크플로우가 이 과정을 역순으로 실행해서 리소스를 정리합니다.

 

📌 이번 SaaS 실습에서 실행하는 마이크로 서비스

현재 소스코드는 Gitea Microservice Repository에서 관리 되고 있는 'Producer' , 'Consumer' 라는 앱이

실행중이고 코드가 Push되면 Gitea Actions가 자동으로 빌드해서 ECR에 이미지 업로드 합니다.

이때 그 이미지를 Flux + Helm이 가져다가 EKS에 배포하는 실습을 구현해볼 예정입니다.

Producer / Consumer 소스코드
        ↓  (Gitea에서 관리)
Gitea Actions가 빌드 → ECR에 이미지 Push
        ↓  (GitOps 흐름)
Flux가 감지 → EKS Pool Namespace에 Deployment로 배포

 

Guide to building a practice environment

실습 환경을 AWS 워크숍이 아닌, 본인이 직접 구축을 하시겠다는 분만 참고하시면 될 것 같습니다.

정말 감사하게도 " Ian Y. Choi" 님이 소스 코드를 공유주셨습니다.

 

1) 워크숍 환경 Git Repository

(https://github.com/ianychoi/eks-saas-gitops)

 

GitHub - ianychoi/eks-saas-gitops: Source repo of Building SaaS applications on Amazon EKS using GitOps workshop

Source repo of Building SaaS applications on Amazon EKS using GitOps workshop - ianychoi/eks-saas-gitops

github.com

 

2) 구현 가이드

(https://aws-solutions-library-samples.github.io/compute/building-saas-applications-on-amazon-eks-using-gitops.html#deploy-the-guidance)

 

Guidance for Building SaaS applications on Amazon EKS using GitOps

This Implementation Guide provides an overview of the Guidance for Building SaaS applications on Amazon EKS using GitOps, its reference architecture and components, considerations for planning the deployment, and configuration steps for deploying the guida

aws-solutions-library-samples.github.io

 

저는 워크숍 아키텍처로 진행을 할 예정이므로, 넘어가도록 하겠습니다.

 


 

02. GitOps 원칙

 

1) Declarative (선언형) : "어떻게 하는지 말고, 어떤 상태여야 하는지를 정의해라"

명령형 vs 선언형 차이

[명령형 - 기존 방식]
"nginx 컨테이너를 실행해"
"replicas를 3으로 늘려"
"80포트를 열어"

[선언형 - GitOps 방식]
"최종 상태는 이거야" → Helm values.yaml / Terraform .tf 파일
replicas: 3
port: 80

실습에서는 Helm 차트와 Terraform 코드가 선언형 정의 파일 역할을 합니다.

 

2) Versioned and Immutable (버전 관리 + 불변) : "원하는 상태는 Git에 저장되고, 히스토리가 남아야 한다"

Git commit = 모든 변경의 기록
  • 언제, 누가, 무엇을 바꿨는지 전부 추적 가능
  • 문제 생기면 git revert 한 방으로 이전 상태로 롤백
  • Git 외의 경로로 클러스터를 직접 변경하는 걸 차단

 

3) Pulled Automatically (자동 Pull) : "에이전트가 Git에서 상태를 알아서 가져와야 한다"

기존 CI/CD 방식(Push)과의 차이

[기존 Push 방식]
Jenkins/GitHub Actions → kubectl apply → 클러스터
(외부에서 클러스터로 밀어넣음)

[GitOps Pull 방식]
Flux (클러스터 내부 에이전트) → Gitea를 주기적으로 Pull
(클러스터 안에서 스스로 가져옴)

실습에서 Flux가 이 역할입니다.. Gitea를 30초~1분 간격으로 polling해서 변경을 스스로 감지해요.

 

4) Continuously Reconciled (지속적 조정)

"에이전트가 실제 상태를 계속 감시하다가, 원하는 상태와 다르면 자동으로 맞춰라"

Git 상태 (desired)  vs  실제 클러스터 상태 (actual)
        ↓
    차이 감지
        ↓
Flux가 자동으로 맞춤 (Reconcile)

예를 들어 누군가 실수로 kubectl delete deployment producer를 쳤을 때:

  • 기존 방식: 그냥 없어진 채로 유지됨
  • GitOps 방식: Flux가 감지 → 자동으로 다시 배포

GitOps는 인프라 및 애플리케이션 설정을 선언적으로 정의하고, 이를 형상 관리 도구(주로 Git)를 통해 관리하는 방식으로, 다음과 같은 4원칙을 https://opengitops.dev 에서 강조하고 있습니다.

 

📌 SaaS DevOps에서 GitOps가 필요한 이유

한편, 복잡한 비즈니스 요구 사항에 대응하기 위해 GitOps를 활용하는 것 또한 가능하며,

이것이 바로 SaaS DevOps 환경에서 GitOps가 필요한 이유에 해당합니다.

 

SaaS의 핵심은 민첩성으로, SaaS 모델에서는 고객을 위해 소프트웨어를 실행하고 관리하므로

지속적인 변화와 혁신을 지원하는 DevOps 프로세스가 필요해요.

  • 잦은 릴리스 : 신속한 피드백과 기능 제공을 가능하게 지원
  • 운영 효율성: 동일한 프로세스를 통해 모든 테넌트를 일관되게 관리
  • 자동화된 온보딩 : 신속하고 일관된 테넌트 생성을 보장하여 효율성을 극대화

 

03. SaaS 배포 모델

SaaS 애플리케이션의 경우 사일로, 하이브리드, 풀 등 다양한 배포 모델을 사용하는데, 이때 테넌트 온보딩 과정에서

리소스를 프로비저닝하는데 필요한 요구 사항이 다릅니다.

 

예: SaaS 모델에 따른 격리 수준, 비용 및 대표 티어 활용 예시

모델 설명 격리 수준 비용 대표 활용
사일로(Silo) 테넌트마다 전용 인프라 높음 높음 Premium tier
풀(Pool) 인프라 공유 낮음 낮음 Basic tier
Hybrid 티어별 혼합 운영 중간 중간 (실제 SaaS에서 혼합 형태로 대부분 활용)

 

한번 쉽게 와닿게 풀어서 설명드려보겠습니다.

 

1) 사일로를 사용하는 고객사

  • 보안이 빡센 금융회사라 "우리 데이터가 다른 회사 서버랑 절대 같이 있으면 안 됨" 이라고 계약서에 명시
  • 규제(금융, 의료, 공공기관)로 인해 물리적 격리가 필수
  • 그래서 고객사 전용 서버, 전용 DB를 따로 프로비저닝해줘야 함

따로 인프라를 구축해주게 된다면 당연하게도 비용이 비싸지겠죠?

A사 서버 + B사 서버 + C사 서버 = 서버 3대 비용
→ 내가 다 부담해야 함
→ 그 비용을 고객한테 청구하니까 월정액이 비쌈

 

2) 풀 티어를 사용하는 고객사

  • 10인 스타트업들이 "저렴하게 쓰고 싶어요" 하는 경우
  • 서버 1대를 여러 고객이 나눠씀
  • 데이터는 논리적으로 분리되어 있지만 (다른 테이블 or 다른 DB 스키마) 물리적으로는 같은 서버

인프라를 공유하기 때문에 사일로 보다 확연하게 비용이 저렴합니다.

서버 1대로 A사 + B사 + C사 + D사 + ... 수십 개 회사 처리
→ 서버 비용을 여러 회사가 나눠냄
→ 월정액이 저렴함

대신 아래와 같은 단점이 존재합니다.

  • B사가 갑자기 대용량 파일을 엄청 올리면 같은 서버 쓰는 A사도 느려질 수 있음 (노이지 네이버 문제)
  • 보안 사고 시 다른 테넌트 데이터에 영향 가능성

 

3) 하이브리드를 사용하는 고객사

  • "서버는 공유해도 되는데, 우리 DB만큼은 전용으로 써야 해요" 하는 중간 고객
  • 앱 서버는 공유 → 비용 절감
  • DB는 전용 → 데이터 격리 보장

회사마다 컴플라이언스 가이드라인이 다르므로, 각 환경에 맞게 구성하려고 하이브리드를 많이 선택합니다.

Slack, Notion, Datadog 같은 서비스들이 다 이런 구조에요.

 

📌 이번 실습과 연결을 한다면?

EKS
└─ Pool namespace (basic tier)
     ├─ Tenant A의 Producer/Consumer  ┐
     ├─ Tenant B의 Producer/Consumer  ├─ 같은 Namespace 공유
     └─ Tenant C의 Producer/Consumer  ┘

이번 실습은 Basic 티어(Pool 모델) 만 구현하는 거에요.

 

실제로 Premium(Silo) 티어까지 구현하려면 테넌트마다 별도 Namespace + 별도 AWS 리소스를

프로비저닝해야 하는데, 그게 앞서 설명한 Tofu Controller의 역할이 훨씬 더 복잡해집니다.

 


긴 글 읽어주셔서 감사합니다.

다음 챕터에서는 실제로 실습을 해보도록 하겠습니다.