Kargo로 구현하는 GitOps 멀티 스테이지 프로모션 — Argo CD와 연동해 dev에서 prod까지 자동화하기
Argo CD를 잘 쓰고 있다고 생각했는데, 어느 날 팀장이 물어봅니다. "dev에 올라간 이미지, 지금 staging에는 언제 들어가요?" 순간 답이 막힙니다. Jenkins 잡이 있긴 한데 누군가가 손으로 트리거하는 거고, 지난번엔 깜빡해서 staging이 사흘 동안 낡은 버전을 들고 있었던 기억이 납니다. GitOps를 도입했는데도 환경 간 프로모션은 여전히 수작업이었던 거죠. 저도 똑같은 상황에서 Kargo를 처음 찾아봤고, 직접 써보면서 가장 먼저 이해해야 했던 것은 "Argo CD와 역할이 겹치지 않는가"라는 질문이었습니다.
이 글에서는 Kargo의 핵심 개념인 Warehouse·Freight·Stage·PromotionTask 모델을 이해하고, dev → staging → prod로 이어지는 자동 프로모션 파이프라인을 선언형으로 설계하는 방법을 살펴봅니다. 글을 다 읽고 나면 기존 Argo CD 환경에 Kargo를 붙여 동작하는 3단계 파이프라인 초안을 만들 수 있는 상태가 됩니다. 이 글은 Kubernetes와 Argo CD를 실제로 운영해본 백엔드·DevOps 엔지니어를 대상으로 합니다. Kustomize, Helm, RBAC 개념이 낯선 분이라면 Argo CD 공식 문서를 먼저 훑어보시는 것을 권장합니다.
Kargo는 2023년 Argo CD의 개발사인 Akuity가 오픈소스로 공개한 Kubernetes 네이티브 프로모션 오케스트레이션 플랫폼입니다. 2024년 v1.0 GA를 찍으며 프로덕션 사용을 공식 지원하기 시작했고, 2025년 현재 v1.10까지 빠르게 발전하고 있습니다. Argo CD가 "Git에 있는 걸 클러스터에 맞춘다"는 역할이라면, Kargo는 "어떤 버전을 언제 어느 환경으로 올릴지"를 결정합니다. 두 도구는 경쟁 관계가 아니라 레이어가 다릅니다.
핵심 개념
GitOps의 빠진 퍼즐 조각 — 프로모션 레이어
전통적인 GitOps 워크플로를 떠올려 보면, Argo CD는 Git 저장소를 바라보며 클러스터 상태를 동기화합니다. 그런데 "dev 환경의 이미지 태그를 staging 환경의 매니페스트에 반영하는" 작업은 누가 할까요? 보통은 CI 스크립트가 Git을 직접 커밋하거나, 팀원이 PR을 올리거나, 심하면 슬랙에 "staging 올려도 됩니까?" 메시지를 보냅니다. Kargo는 이 공백을 메우기 위해 세 가지 핵심 리소스를 도입합니다.
| 리소스 | 역할 |
|---|---|
| Warehouse | 컨테이너 이미지 레지스트리·Git 저장소·Helm 차트 저장소를 구독하며 새 버전 감지 |
| Freight | 프로모션의 최소 단위. 특정 이미지 태그 + Git 커밋 SHA + Helm 버전의 묶음 |
| Stage | 환경(dev/staging/prod)을 표현하며, DAG 구조로 연결되어 파이프라인을 형성 |
Freight란? 단순한 이미지 태그가 아닙니다. 컨테이너 이미지, Git 커밋 SHA, Helm 차트 버전을 하나로 묶은 불변(immutable) 배포 단위입니다. 이 Freight가 Stage 체인을 따라 상위 환경으로 이동하는 것이 곧 "프로모션"입니다.
Warehouse — 새 버전을 가장 먼저 알아채는 감시자
Warehouse는 지속적으로 소스를 폴링하며, 새로운 버전이 감지되면 Freight를 자동 생성합니다. 처음 이 YAML을 보고 discoveryLimit이 뭔지 헷갈렸는데, 한 번에 추적할 최신 버전 수를 제한하는 옵션입니다. 10으로 설정하면 최근 10개 태그만 Freight 후보로 관리합니다.
apiVersion: kargo.akuity.io/v1alpha1
kind: Warehouse
metadata:
name: my-app-warehouse
namespace: my-project
spec:
subscriptions:
- image:
repoURL: ghcr.io/my-org/my-app
tagSelectionStrategy: SemVer
allowTags: ^v\d+\.\d+\.\d+$
discoveryLimit: 10allowTags 정규식으로 추적할 태그 패턴을 제어할 수 있어, 피처 브랜치 이미지가 프로덕션 파이프라인에 섞여 들어오는 사고를 원천 차단할 수 있습니다.
Stage — 환경을 DAG로 연결하는 파이프라인
Stage는 단순히 "환경"이 아니라 "이전 Stage에서 검증된 Freight만 받겠다"는 게이트 역할도 합니다. 아래 staging Stage는 반드시 dev Stage를 통과한 Freight만 수락합니다.
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: staging
namespace: my-project
spec:
requestedFreight:
- origin:
kind: Warehouse
name: my-app-warehouse
sources:
stages:
- devsources.stages에 여러 Stage를 나열하면 기본적으로 그 중 하나만 검증되어도 Freight가 수락되는 OR 의미론으로 동작합니다. 모든 상위 Stage에서 검증된 Freight만 허용하고 싶다면 v1.3에서 도입된 availabilityStrategy: AllMustBeVerified를 활용할 수 있습니다. 복잡한 파이프라인을 설계할 때 이 차이를 모르면 의도치 않은 프로모션이 발생할 수 있어 주의가 필요합니다.
PromotionTask — 반복 제거를 위한 모듈화
Stage가 3개(dev, staging, prod)라면 프로모션 스텝 시퀀스를 세 번 복붙해야 할까요? 저도 처음에 그렇게 했다가, Stage 5개쯤 되니까 git-commit 메시지 형식 하나 바꾸려고 다섯 군데를 수정하는 상황이 왔습니다. PromotionTask는 코드에서 함수를 분리하는 것처럼 공통 프로모션 로직을 한 곳에 정의하고 여러 Stage에서 재사용할 수 있게 해줍니다.
apiVersion: kargo.akuity.io/v1alpha1
kind: PromotionTask
metadata:
name: standard-gitops-flow
namespace: my-project
spec:
vars:
- name: appName
- name: overlayPath
steps:
- uses: git-clone
config:
repoURL: https://github.com/my-org/gitops-config
branch: main
- uses: kustomize-set-image
config:
path: ${{ vars.overlayPath }}
images:
- image: ghcr.io/my-org/my-app
newTag: ${{ freight.images[0].tag }}
- uses: git-commit
config:
message: "chore: promote ${{ freight.images[0].tag }} to ${{ vars.appName }}"
- uses: git-push
- uses: argocd-update
config:
apps:
- name: ${{ vars.appName }}
sources:
- repoURL: https://github.com/my-org/gitops-config
- uses: argocd-wait
config:
apps:
- name: ${{ vars.appName }}vars로 Stage마다 달라지는 값(앱 이름, overlay 경로)만 파라미터화하면, 파이프라인 로직이 바뀌어도 PromotionTask 하나만 수정하면 전 환경에 반영됩니다.
실전 적용
예시 1: dev → staging → prod 전체 파이프라인 구성
이 예시는 단일 마이크로서비스(my-app)를 운영하는 소규모 팀을 가정합니다. GitOps 설정 저장소(gitops-config)는 overlays/dev, overlays/staging, overlays/prod 구조의 Kustomize overlay를 갖고 있으며, 각 환경에 대응하는 Argo CD 앱(my-app-dev, my-app-staging, my-app-prod)이 이미 동작 중입니다. CI가 이미지를 빌드·푸시하면 Kargo가 감지해서 dev에 자동 배포하고, dev 검증이 통과하면 staging으로 자동 프로모션한 뒤, prod는 수동 승인을 거치는 구조입니다.
Git 자격증명 설정 — 가장 먼저 막히는 부분이기도 한데, 프라이빗 저장소에 접근하려면 Kargo가 인식하는 형식의 Kubernetes Secret을 먼저 만들어야 합니다.
apiVersion: v1
kind: Secret
metadata:
name: gitops-config-credentials
namespace: my-project
labels:
kargo.akuity.io/cred-type: git
stringData:
repoURL: https://github.com/my-org/gitops-config
username: git
password: ghp_YOUR_GITHUB_TOKEN # GitHub Personal Access Token이 Secret이 없으면 git-clone 스텝에서 인증 오류가 납니다. Kargo는 kargo.akuity.io/cred-type: git 레이블이 붙은 Secret을 자동으로 인식해서 해당 저장소 접근에 사용합니다.
dev Stage — Warehouse에서 직접 Freight를 받고, 앞서 정의한 PromotionTask를 참조합니다.
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: dev
namespace: my-project
spec:
requestedFreight:
- origin:
kind: Warehouse
name: my-app-warehouse
sources:
direct: true
promotionTemplate:
spec:
steps:
- task:
name: standard-gitops-flow
vars:
- name: appName
value: my-app-dev
- name: overlayPath
value: overlays/devstaging Stage — dev를 통과한 Freight만 수락하고, 24시간 소크 타임을 거쳐야 prod 프로모션이 허용됩니다.
소크 타임(Soak Time)이란? 특정 환경에 배포된 후 일정 시간이 지나야 다음 Stage로 프로모션을 허용하는 대기 시간입니다. staging에서 24시간 이상 문제가 없어야 prod 프로모션을 허용하는 식으로 활용합니다.
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: staging
namespace: my-project
spec:
requestedFreight:
- origin:
kind: Warehouse
name: my-app-warehouse
sources:
stages:
- dev
verification:
soak:
duration: 24h
promotionTemplate:
spec:
steps:
- task:
name: standard-gitops-flow
vars:
- name: appName
value: my-app-staging
- name: overlayPath
value: overlays/stagingprod Stage — staging 통과 필수이며, Argo Rollouts의 AnalysisTemplate으로 스모크 테스트를 실행합니다.
AnalysisTemplate이란? Argo Rollouts에서 정의하는 리소스로, Prometheus 지표, HTTP 엔드포인트, 커스텀 스크립트 등을 기반으로 배포 성공 기준을 코드로 정의합니다. Kargo의
verification.analysisTemplates는 이 리소스를 참조해 배포 후 자동으로 검증을 실행합니다.
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: prod
namespace: my-project
spec:
requestedFreight:
- origin:
kind: Warehouse
name: my-app-warehouse
sources:
stages:
- staging
verification:
analysisTemplates:
- name: smoke-test # Argo Rollouts AnalysisTemplate 참조
promotionTemplate:
spec:
steps:
- task:
name: standard-gitops-flow
vars:
- name: appName
value: my-app-prod
- name: overlayPath
value: overlays/prod수동 승인은 어떻게? Kargo UI 또는 CLI에서 해당 Stage의 Freight에 승인 표시를 하거나, RBAC(Role-Based Access Control — 역할 기반 접근 제어)으로 특정 역할(예:
release-manager)에게만promotion리소스 생성 권한을 부여하는 방식으로 구현합니다. Kargo의Project리소스에서 Stage별 역할 바인딩을 처음부터 정의해두는 것을 권장합니다. 팀원 누구나 prod를 프로모션할 수 있는 상태로 운영하다 사고가 나는 패턴은 실무에서 꽤 자주 봤습니다.
예시 2: 조건부 스텝으로 배포 실패 시 Slack 알림 보내기
Kargo v1.3부터 도입된 조건부 스텝(if: 표현식)을 활용하면 프로모션 실패 시 Slack 웹훅을 호출하는 로직을 파이프라인 안에 녹일 수 있습니다. 솔직히 이 기능 나오기 전에는 외부 모니터링에 의존하거나 별도 알림 파이프라인을 만들었는데, 이제는 Stage 안에서 해결됩니다.
Slack 웹훅 URL은 평문으로 YAML에 넣으면 보안 문제가 생기므로, Kubernetes Secret으로 관리하고 환경 변수나 ${{ secrets.slackWebhook }} 방식으로 주입하는 것을 권장합니다.
promotionTemplate:
spec:
steps:
- uses: git-clone
- uses: kustomize-set-image
- uses: git-commit
- uses: git-push
- uses: argocd-update
- uses: argocd-wait
as: deploy-wait # 스텝에 이름을 붙여 이후 조건 참조에 사용
- uses: http
if: ${{ steps['deploy-wait'].status == 'Failure' }}
config:
method: POST
url: ${{ secrets.slackWebhookUrl }}
headers:
- name: Content-Type
value: application/json
body: |
{"text": "prod 배포 실패: ${{ freight.images[0].tag }}"}
- uses: fail
if: ${{ steps['deploy-wait'].status == 'Failure' }}
config:
message: "argocd-wait 실패로 프로모션 중단"| 스텝 | if: 조건 |
역할 |
|---|---|---|
argocd-wait |
— | Argo CD 헬스 체크 결과 수집 (as: deploy-wait로 이름 부여) |
http |
이전 스텝 실패 시 | Slack 웹훅으로 알림 발송 |
fail |
이전 스텝 실패 시 | 프로모션을 명시적으로 실패 처리하여 추적 가능하게 함 |
as: deploy-wait로 스텝에 이름을 붙이고 steps['deploy-wait'].status로 참조하는 패턴은 공식 문서에서도 잘 강조되지 않는데, 실무에서 꽤 유용합니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 선언형 파이프라인 | 모든 프로모션 정책이 YAML로 Git에 버전 관리되어, CI 스크립트나 수작업 의존성이 사라집니다 |
| 완전한 추적성 | 어떤 Freight가 언제, 누구의 승인으로, 어느 환경에 배포됐는지 전부 기록됩니다 |
| 원자적 프로모션 | 이미지 + Helm 차트 + Git 커밋을 하나의 Freight로 묶어 일관성을 보장합니다 |
| 세밀한 RBAC | QA팀은 staging, SRE팀은 prod 승인 권한처럼 Stage별로 역할을 분리할 수 있습니다 |
| 기존 도구와 공존 | Argo CD와 Argo Rollouts를 대체하지 않고 오케스트레이션 레이어로만 추가됩니다 |
| Freight 단위 롤백 | 문제 발생 시 이전 Freight로 즉시 롤백이 가능해 장애 대응 속도가 높아집니다 |
단점 및 주의사항
학습 곡선 Warehouse·Freight·Stage·PromotionTask 등 새 개념을 한꺼번에 익혀야 합니다. 처음 개념을 잡는 데 이틀은 각오하는 것이 좋습니다.
- 권장: 공식 Quick Start 예제를 직접 실행해보며 개념을 체화하는 것을 권장합니다
운영 오버헤드 Kargo 컨트롤러를 클러스터에 별도로 운영해야 하고, Argo CD와의 상태 동기화를 함께 이해해야 합니다.
- 권장: Akuity Platform(관리형 서비스)을 사용하면 운영 부담을 줄일 수 있습니다
디버깅 복잡도 조건부 스텝·검증 실패·소크 타임 만료 등 실패 원인이 다양해 파악이 어려울 수 있습니다.
- 권장: Kargo UI의 Stage 상태 패널과
kubectl describe promotion로그를 함께 확인하는 것이 좋습니다
젊은 생태계 v1.0 GA가 2024년이라 엔터프라이즈 모범 사례가 아직 쌓이는 중입니다.
- 권장: JumpCloud Engineering 블로그나 ProSiebenSat.1 사례 등 실무 사례를 함께 참고하는 것을 권장합니다
Argo 스택 의존성 최적 활용을 위해 Argo CD와 Argo Rollouts 조합이 사실상 필수입니다. Flux 기반 환경이라면 통합 성숙도가 낮으므로 신중하게 검토하는 것이 좋습니다.
실무에서 가장 흔한 실수
- Warehouse 없이 Stage만 만드는 경우 — Freight의 출처가 없으면 파이프라인이 동작하지 않습니다. 반드시 Warehouse → Freight → Stage 흐름을 먼저 설계하고, Warehouse가 실제로 이미지를 감지하는지 UI에서 확인해보는 것을 권장합니다.
argocd-update이후argocd-wait를 생략하는 경우 — 동기화 트리거만 하고 헬스 체크를 기다리지 않으면, 실제로 파드가 CrashLoop 상태여도 프로모션이 성공으로 처리될 수 있습니다. v1.10부터 두 스텝이 분리된 이유가 여기에 있습니다.- Stage별 RBAC을 초반에 설정하지 않는 경우 — 팀원 누구나 prod Stage를 프로모션할 수 있는 상태로 운영하다 사고가 나는 패턴입니다.
Project리소스에서 Stage별 역할 바인딩을 처음부터 정의해두는 것을 권장합니다.
마치며
Kargo는 GitOps가 "동기화"만 해결하던 시대에서, "프로모션까지 선언형으로 관리"하는 시대로 넘어가는 핵심 도구입니다. JumpCloud Engineering이 도입 후 배포 빈도 48% 증가, 리드 타임 45% 감소를 달성한 것은 단순한 수치가 아니라, 프로모션 결정권을 사람에서 파이프라인으로 이전한 패러다임 전환의 결과입니다.
지금 바로 시작해볼 수 있는 3단계:
- 로컬 클러스터에 Kargo 설치해보기 — 아래 명령으로 설치 후, 공식 Quick Start의
guestbook예제를 그대로 따라가 보시면 Warehouse → Freight → Stage 흐름이 눈으로 보입니다.bashhelm install kargo oci://ghcr.io/akuity/kargo-charts/kargo \ --namespace kargo --create-namespace - 기존 Argo CD 앱 중 가장 단순한 것부터 연결해보기 — 이미 운영 중인 Argo CD 애플리케이션 하나를 골라, 이미지 레지스트리를 구독하는 Warehouse와 dev Stage 하나만 먼저 붙여보는 것을 권장합니다. 전체를 한꺼번에 바꾸기보다 점진적으로 검증하는 방식이 훨씬 안전합니다.
- PromotionTask로 공통 스텝 분리하기 — Stage가 2개 이상 생기면 즉시 PromotionTask를 도입해 중복을 제거하는 것이 좋습니다. 초반에 하지 않으면 나중에 Stage 10개의 YAML을 일일이 수정하는 상황이 옵니다.
참고로, prod Stage의 verification.analysisTemplates를 최대한 활용하려면 Argo Rollouts를 함께 운영하는 것이 좋습니다. Argo Rollouts는 Kubernetes에서 카나리·Blue-Green 배포를 지원하는 고급 배포 컨트롤러로, Kargo의 검증 기능과 연동하면 배포 후 Prometheus 지표나 HTTP 엔드포인트를 기반으로 성공 기준을 자동으로 평가할 수 있습니다.
참고 자료
입문 및 Quick Start
- What is Kargo? Simplifying Continuous Promotion with GitOps | Akuity
- Kargo 공식 문서 | docs.kargo.io
- Kargo Explained: How Warehouses, Freight, and Stages Replace Manual Promotions | Burrell Technology
- Continuous Promotion on Kubernetes with GitOps | Piotr's TechBlog
- From Commit to Production: GitHub Actions + Argo CD + Helm + Kargo | freeCodeCamp
레퍼런스 및 공식 릴리즈 노트
- GitHub - akuity/kargo
- Kargo v1.3 릴리즈 노트 — 조건부 스텝 & 고급 검증 | Akuity Blog
- Kargo v1.10 릴리즈 노트 — Custom Steps, HTTP Notifications | Akuity Blog
- Implementing a Modular Kargo Promotion Workflow: PromotionTask | DEV Community
- Change Management with Pulumi Kubernetes Operator and Kargo | Pulumi Blog
사례 연구