| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- pv/pvc
- aws-node
- ipamd
- EKS Architecture
- gateway api
- eks upgrade
- ClusterIP
- 쿠버네티스 네트워크
- auto mode
- externaldns
- Fargate
- EmptyDir
- aws vpc cni
- soci
- k8s authentication
- cni binary
- kube-proxy
- EKS vLLM
- CoreDNS
- Instance Store
- EKS
- Terraform
- k8s scheduler
- serviceaccount
- HostPath
- kubernetes networking
- hashicorp
- eksctl
- nodeport
- Node group
- Today
- Total
ksc0204 님의 블로그
AEWS 4기 6주차(3) - EKS CI/CD(SaaS Tier 전략, ArgoCD Worflow) 본문
Before Start..
주관적인 해석이 포함되어 있어 사실과 다르거나 오류가 있을 수 있으니 참고용으로만 읽어주시기 바랍니다.
SaaS 티어 전략
1. Tier(티어) 전략
B2B SaaS(Software as a Service) 환경에서 '티어(Tier)'를 나눈다는 것은 단순히 마케팅 부서에서 요금제 표를 예쁘게 꾸미는 작업이 아닙니다. 엔지니어링 관점에서 티어 전략은 "고객이 지불하는 비용에 맞춰 인프라 자원의 격리 수준(Isolation Level)과 성능을 물리적/논리적으로 어떻게 분배할 것인가?"를 결정하는 핵심 생존 전략입니다.
초기 스타트업부터 엔터프라이즈 컴플라이언스를 요구하는 금융권 고객까지, 다양한 요구사항을 하나의 플랫폼에서 수용하기 위해 현대 SaaS 기업들이 채택하고 있는 'SaaS 인프라 티어 전략'의 개념과 실제 적용 사례를 살펴봅니다.
2. SaaS 티어 전략 - 실습 환경 기준
| 구성 요소 | Basic 티어 | Premium 티어 |
| 배포 모델 | Pool (공유) | Silo (전용) |
| Kubernetes 네임스페이스 | pool-1 (공유) | 테넌트 전용 |
| Producer | 공유 (pool-1) | 전용 배포 |
| Consumer | 공유 (pool-1) | 전용 배포 |
| SQS 큐 | 공유 | 전용 |
| DynamoDB 테이블 | 공유 | 전용 |
| Ingress | 테넌트별 라우팅만 | 전용 |
| 비용 | 낮음 | 높음 |
| 격리 수준 | 낮음 | 높음 |
아래 내용은 Gemini 3 Pro를 참고하여 작성하였습니다.
① Basic Tier (다중 임대 / Shared Pool 모델)
- 구조: 여러 테넌트(고객)가 소수의 동일한 애플리케이션 파드와 단일 데이터베이스 자원을 함께 공유합니다.
- 특징: 유휴 자원을 극한으로 활용하여 테넌트 당 인프라 단가를 극소화합니다. 대규모 무료 사용자나 초기 진입 고객을 유치하는 데 필수적입니다.
- 한계: 한 테넌트의 과도한 트래픽이 다른 테넌트의 성능 저하를 유발하는 '시끄러운 이웃(Noisy Neighbor)' 문제가 발생할 수 있습니다.
② Premium Tier (완전 격리 / Silo 모델)
- 구조: 전용 파드는 물론 데이터베이스, 메시지 큐, 캐시 서버까지 모든 구성 요소를 단독으로 프로비저닝합니다.
- 특징: 비용은 가장 높지만 다른 회사와 데이터가 섞이는 것을 엄격히 금지하는 엔터프라이즈 보안 및 망 분리 규제(컴플라이언스)를 완벽하게 충족합니다.
3. 티어 전략 도입의 비즈니스 및 기술적 이점
- 비용 효율성의 극대화: 모든 고객에게 전용 자원을 할당할 때 발생하는 기하급수적인 적자 구조를 막고, 수익성을 보장합니다.
- 안정성과 SLA 보장: 고수익 VIP 고객의 인프라를 논리적/물리적으로 분리하여, 공용 풀에서 발생하는 장애로부터 완벽하게 보호합니다.
- 보안 규제 대응력 확보: 금융, 공공기관 등 까다로운 보안 요건을 요구하는 대규모 B2B 계약을 수주할 수 있는 기술적 토대가 됩니다.
4. 글로벌 SaaS 기업의 적용 사례
- 개발자 플랫폼 (GitHub): 무료/일반 사용자는 공용 웹 서버와 Shared Runner를 사용하지만, Enterprise 고객에게는 격리된 Dedicated Runner를 제공하거나 아예 고객사 환경에 독립된 클러스터를 구축(GitHub Enterprise Server)합니다.
- 데이터 웨어하우스 (Snowflake): 기본 티어에서는 컨트롤 플레인과 컴퓨팅 자원을 공유하지만, 최상위 티어(Business Critical)에서는 전용 컴퓨팅 클러스터(Virtual Warehouse)를 즉시 스핀업하고 AWS PrivateLink를 통해 인터넷을 거치지 않는 격리 네트워크를 제공합니다.
- 금융망 B2B 핀테크: 일반 고객은 논리적 스키마만 분리된 공용 RDS를 사용하지만, 금융권 고객이 유입될 경우 프로비저닝 도구를 통해 별도의 AWS 계정이나 전용 클러스터 기반의 완벽한 Silo 환경을 찍어냅니다.
5. GitOps를 활용한 인프라 구현
이러한 복잡한 티어링 전략을 수동으로 관리하는 것은 불가능에 가깝습니다.(관리 포인트 증가 문제)
최근에는 Flux CD, Terraform(TF-controller), HelmRelease를 결합하여 비즈니스 로직을 인프라 코드(IaC)로 완벽히 동기화합니다.
예를 들어, Basic 고객이 Premium으로 결제를 업그레이드할 경우 엔지니어는 Git 저장소의 테넌트 설정 파일(values.yaml)에서 변수 하나(producer.enabled: true)만 변경하여 커밋합니다. 그러면 GitOps 컨트롤러가 이를 감지하여 무중단으로 전용 파드와 DB를 생성하고, Ingress 라우팅 목적지를 공용 서버에서 전용 서버로 부드럽게 이전시킵니다.
Advanced 티어 정의
해당 실습 환경에서는 Basic, Premium에 대한 티어는 정의되어 있지만, Advanced에 대한 티어는 정의되어 있지 않아 직접 정의하는 실습을 진행하였습니다.
설계 목표
목표 : 기존 Helm Chart를 변경하지 않은 상태에서 Silo와 Pool 모델의 장점을 사용 패턴에 맞게 조합하여 Advanced 설계
- Producer: 공유
- pool-1 Pool 환경 활용(요청 패턴이 비교적 균일한 워크로드) - Consumer : 전용
- 테넌트 전용 네임스페이스(데이터 처리 격리 필요)
HelmRelease 생성 - Advanced 템플릿
cat << EOF > /home/ec2-user/environment/gitops-gitea-repo/application-plane/production/tier-templates/advanced_tenant_template.yaml
apiVersion: v1
kind: Namespace
metadata:
name: {TENANT_ID}
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: {TENANT_ID}-advanced
namespace: flux-system
spec:
releaseName: {TENANT_ID}-advanced
targetNamespace: {TENANT_ID} # Deploying into the tenant-specific namespace
interval: 1m0s
chart:
spec:
chart: helm-tenant-chart
version: "{RELEASE_VERSION}.x"
sourceRef:
kind: HelmRepository
name: helm-tenant-chart
values: # producer, consumer 부분 수정
tenantId: {TENANT_ID}
apps:
producer:
envId: pool-1
enabled: false # Pool deployment -- advanced tier shares resources with other tenants
ingress:
enabled: true
consumer:
enabled: true # Silo deployment -- advanced tier has a dedicated deployment for each tenant
ingress:
enabled: true
image:
tag: "0.1" # {"\$imagepolicy": "flux-system:consumer-image-policy:tag"}
EOF
Advanced 테넌트 - 프로비저닝(수동)
export TENANT_ID=tenant-t1d6c
export RELEASE_VERSION=0.0
cd /home/ec2-user/environment/gitops-gitea-repo/application-plane/production/
cp tier-templates/advanced_tenant_template.yaml tenants/advanced/$TENANT_ID.yaml
#TENANT_ID 값 치환
sed -i "s|{TENANT_ID}|$TENANT_ID|g" "tenants/advanced/$TENANT_ID.yaml"
sed -i "s|{RELEASE_VERSION}|$RELEASE_VERSION|g" "tenants/advanced/$TENANT_ID.yaml"
Kustomization 생성 및 Git Commit & Push
cat << EOF > tenants/advanced/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- $TENANT_ID.yaml
EOF
cd /home/ec2-user/environment/gitops-gitea-repo/
git pull origin main
git add .
git commit -am "Adding tenant-t1d6c with Advanced Tier"
git push origin main
Flux 강제 반영 및 확인
# flux 강제 반영
flux reconcile source git flux-system
# 배포 및 리소스 생성 확인
aws dynamodb list-tables | grep tenant-t1d6c
aws sqs list-queues | grep tenant-t1d6c


Curl 명령어를 통해 Consumer와 Producer 호출 시 환경 확인
APP_LB=http://$(kubectl get ingress -n tenant-t1d6c -o json | jq -r .items[0].status.loadBalancer.ingress[0].hostname)
echo $APP_LB # ALB 접속 도메인 확인
curl -s -H "tenantID: tenant-t1d6c" $APP_LB/producer | jq
curl -s -H "tenantID: tenant-t1d6c" $APP_LB/consumer | jq

위에서처럼 Producer는 공용환경을 가지며, Consumer는 전용 환경을 부여한 것을 확인할 수 있습니다. 즉, 아래 표와 같이 설계되었습니다.
| 구분 | Producer | Consumer | 인프라 | 비용 | 격리 수준 |
| Basic | 공유 (pool-1) | 공유 (pool-1) | 공유 | 낮음 | 낮음 |
| Advanced | 공유 (pool-1) | 전용 | Consumer만 전용 | 중간 | 중간 |
| Premium | 전용 | 전용 | 전용 | 높음 | 높음 |
ArgoCD Workflow
실습 환경

- workflowtemplates 확인
onbording 워크플로우 템플릿 역할 - 새 테넌트 환경 프로비저닝
offboarding 워크플로우 템플릿 역할 - 테넌트를 환경에서 제거
deployment 워크플로우 템플릿 역할 - 테넌트 HelmRelease 버전 업데이트
Onbording workflow yaml 분석
[ec2-user@ip-10-0-1-206 gitops-gitea-repo]$ kubectl get workflowtemplate tenant-onboarding-template -n argo-workflows -o yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
creationTimestamp: "2026-04-20T08:25:07Z"
generation: 1
labels:
kustomize.toolkit.fluxcd.io/name: controlplane
kustomize.toolkit.fluxcd.io/namespace: flux-system
name: tenant-onboarding-template
namespace: argo-workflows
resourceVersion: "5503"
uid: 508a01d6-f14e-4716-8e32-dff6063fd0b8
spec:
serviceAccountName: argoworkflows-sa
templates:
- container:
args:
- ./00-validate-tenant.sh {{workflow.parameters.TENANT_ID}}
command:
- /bin/sh
- -c
env:
- name: GIT_USERNAME
value: '{{workflow.parameters.GIT_USERNAME}}'
- name: GIT_TOKEN
value: '{{workflow.parameters.GIT_TOKEN}}'
image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/argoworkflow-container:0.1
volumeMounts:
- mountPath: /mnt/vol
name: workdir
name: validate-if-tenant-exists
- container:
args:
- ./01-tenant-clone-repo.sh {{workflow.parameters.REPO_URL}} {{workflow.parameters.GIT_BRANCH}}
{{workflow.parameters.GIT_USERNAME}} {{workflow.parameters.GIT_TOKEN}} &&
cp -r eks-saas-gitops /mnt/vol/eks-saas-gitops
command:
- /bin/sh
- -c
env:
- name: GIT_USERNAME
value: '{{workflow.parameters.GIT_USERNAME}}'
- name: GIT_TOKEN
value: '{{workflow.parameters.GIT_TOKEN}}'
image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/argoworkflow-container:0.1
volumeMounts:
- mountPath: /mnt/vol
name: workdir
name: clone-repository
- container:
args:
- ./02-tenant-onboarding.sh {{workflow.parameters.TENANT_ID}} {{workflow.parameters.RELEASE_VERSION}}
{{workflow.parameters.TENANT_TIER}} {{workflow.parameters.GIT_USER_EMAIL}}
{{workflow.parameters.GIT_USERNAME}} {{workflow.parameters.GIT_BRANCH}} {{workflow.parameters.GIT_TOKEN}}
command:
- /bin/sh
- -c
env:
- name: GIT_USERNAME
value: '{{workflow.parameters.GIT_USERNAME}}'
- name: GIT_TOKEN
value: '{{workflow.parameters.GIT_TOKEN}}'
image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/argoworkflow-container:0.1
volumeMounts:
- mountPath: /mnt/vol
name: workdir
name: create-tenant-helm-release
volumeClaimTemplates:
- metadata:
name: workdir
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: gp2
| 설정 | 역할 |
| sericeAccountName: argoworkflows-sa | 해당 Workflow를 실행할 때 부여 받는 권한 |
| spec.container.name: validate-if-tenant-exists | 신규 테넌트 = 기존 테넌트 중복 검사 스크립트 실행(인프라 충돌 방지) |
| spec.container.name: clone-repository | Git Repo → Workflow 내부로 git clone |
| spec.container.name: create-tenant-helm-release | HelmRelease 객체 생성 |
argoworkflows-sa SA 확인
현재는 실습환경으로 administrator 권한이 설정되어 있지만 추후 운영 환경시에는 최소권한으로만 설정하는 것을 권장합니다.


ArgoCD Workflow - Onboarding 동작 방식(실습 환경 기준)
1. SQS 이벤트 및 tenant ID 값 전달 → 2.테넌트 검증(중복 검사) → 3. 신규 테넌트 생성 및 Git Clone → 4. HelmRelease 생성 → Git Commit & Push (ArgoCD Workflow에서 실행) → flux cd 감지(flux-system에서 확인)
SQS 이벤트 전달
신규 테넌트를 생성하기 위해서는 필요한 메타데이터 값을 SQS로 전달하여 동작 과정을 확인하였습니다.
필요한 메타데이터 : tenant_id, tenant_tier, release_version
export ARGO_WORKFLOWS_ONBOARDING_QUEUE_SQS_URL=$(kubectl get configmap saas-infra-outputs -n flux-system -o jsonpath='{.data.argoworkflows_onboarding_queue_url}')
aws sqs send-message \
--queue-url $ARGO_WORKFLOWS_ONBOARDING_QUEUE_SQS_URL \
--message-body '{
"tenant_id": "tenant-1",
"tenant_tier": "premium",
"release_version": "0.0"
}'
Premium tenant Onboarding

Onboarding Workflow 실행 확인



Gitops 변경사항 검증
- 신규 테넌트가 추가되고 자동으로 이미지가 업데이트 된것을 확인할 수 있습니다.

Adding new tenant tenant-1 in tier premium으로 업데이트된 내역을 확인해보면 kustomization.yaml 파일이 수정되었고, tenant-1.yaml 파일이 신규 생성된 것을 확인할 수 있습니다.









offboarding 실행


'AWS 4기' 카테고리의 다른 글
| AEWS 4기 7주차(2) - EKS Upgrade(Workshop 실습) (0) | 2026.05.01 |
|---|---|
| AEWS 4기 7주차(1) - EKS Upgrade (0) | 2026.05.01 |
| AEWS 4기 6주차(2) - EKS CI/CD(Flux CD + Helm Chart) (0) | 2026.04.23 |
| AEWS 4기 6주차(1) - EKS CI/CD(flux cd, tofu-controller) (0) | 2026.04.22 |
| AEWS 4기 5주차(2) - 워커노드 kubelet,containerd 디버깅, Loadbalancer 트러블슈팅 (0) | 2026.04.18 |