
7.0 들어가며
쿠버네티스에서의 배포(Delivery)는 이제 수동 kubectl apply나 “사람이 파이프라인 마지막 단계에서 승인 → 배포” 같은 절차형 모델에서 벗어나고 있다.
대신, 원하는 상태(Desired State)를 Git에 선언하고, 클러스터가 그 선언을 지속적으로 따라가도록 자동으로 유지시키는 방식이 보편화되고 있다. 이 방식을 GitOps라고 부른다.
Argo CD는 GitOps 기반 쿠버네티스 전용 CD(Continuous Delivery) 컨트롤러다.
- Git 리포지토리를 단일 진실 공급원(SSOT)으로 삼는다.
- Git에 선언된 상태(Desired State)와 실제 클러스터 상태(Live State)를 비교한다.
- 차이가 있으면 OutOfSync로 감지하고, 필요하면 자동으로 클러스터를 Git과 일치시키도록 동기화(Sync)한다.
Argo CD는 Helm, Kustomize, Jsonnet, 순수 YAML 디렉터리 등 다양한 매니페스트 소스를 지원하고, 여러 클러스터/네임스페이스에 애플리케이션을 배포/유지/롤백하며, UI·CLI·API를 통해 상태를 시각화한다.
이 장에서는 Kind 기반 클러스터에 Argo CD를 설치하고, Git 저장소(ops-deploy)에 준비한 Helm 차트를 DEV/PRD로 배포하고, 자동 동기화/Prune/Webhook/Sync Window까지 포함한 실제 운영 패턴을 다룬다.
7.1 Argo CD를 사용한 애플리케이션 배포
이 섹션은 “Argo CD를 설치하고, Git에 있는 애플리케이션을 실제 쿠버네티스에 배포하는 기본 루프”를 다룬다.
7.1.1 Argo CD 설치 (Kind 클러스터 기준)
- 네임스페이스 생성
- kubectl create ns argocd
- Helm values 준비 (argocd-values.yaml)
- Dex 비활성화 (SSO 안 쓸 경우)
- Argo CD 서버(Service)를 NodePort로 노출
- --insecure로 HTTPS 대신 HTTP 접근 허용 (랩 환경 편의)
dex: enabled: false server: service: type: NodePort nodePortHttps: 30002 extraArgs: - --insecure - 설치
- helm repo add argo https://argoproj.github.io/argo-helm helm install argocd argo/argo-cd --version 9.0.5 \ -f argocd-values.yaml \ --namespace argocd
- 구성 요소/CRD 확인여기서 applications.argoproj.io, applicationsets.argoproj.io, appprojects.argoproj.io 같은 CRD가 존재해야 한다. 이 CRD들이 Argo CD의 핵심 리소스다.
- kubectl get pod,svc,cm,secret -n argocd kubectl get crd | grep argo
- admin 초기 비밀번호로 로그인브라우저에서 http://127.0.0.1:30002 접속 → admin 로그인 → 비밀번호 변경.
- kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 -d ; echo
Settings 화면에서 Clusters, Projects, Accounts 등을 확인할 수 있다. 여기서 Git repo 자격증명과 대상 클러스터 접근 권한도 관리된다.
7.1.2 배포 대상 Git 리포지토리 준비 (ops-deploy)
Argo CD는 Git을 바라본다.
예제로 ops-deploy 라는 Git 저장소(예: Gogs)에 아래와 같은 Helm 차트를 넣는다:
nginx-chart
├── Chart.yaml
├── VERSION
├── templates
│ ├── configmap.yaml
│ ├── deployment.yaml
│ └── service.yaml
├── values-dev.yaml
└── values-prd.yaml
- templates/configmap.yaml
index.html 내용을 ConfigMap으로 넣는다. - templates/deployment.yaml
.Values.image.repository, .Values.image.tag, .Values.replicaCount 등으로 Deployment를 정의한다. - templates/service.yaml
NodePort(Service type: NodePort, 예: 30000)로 외부에서 접근 가능. - values-dev.yaml / values-prd.yaml
환경별(repllicaCount, HTML 내용, 이미지 태그 등) 차이를 분리. - VERSION
현재 nginx 버전 같은 정보를 텍스트로 기록.
이렇게 준비된 Repo URL (예: http://<IP>:3000/devops/ops-deploy) 을 Argo CD에 등록한다. Argo CD UI의 Settings → Repositories에서 repo URL, 사용자/토큰(Gogs Personal Access Token 등)을 등록하면 된다.
7.1.3 Argo CD Application 생성 (수동 방식)
Web UI에서 NEW APP을 눌러 애플리케이션을 정의한다. 이건 내부적으로 Application CRD를 하나 만든다.
예: DEV 배포용 dev-nginx
- GENERAL
- Application Name: dev-nginx
- Project: default
- Sync Policy: Manual (처음엔 수동으로 맞춘다)
- Sync Options: AUTO-CREATE NAMESPACE 체크 → 대상 네임스페이스가 없으면 자동 생성
- Prune Propagation Policy: foreground / background / orphan 중 선택해 삭제 순서를 제어할 수 있다.
- SOURCE
- Repo URL: 위에서 등록한 ops-deploy Git
- Revision: HEAD
- Path: nginx-chart
- Helm Values files: values-dev.yaml
- DESTINATION
- Cluster: 기본 클러스터 (https://kubernetes.default.svc)
- Namespace: dev-nginx
CREATE 후 상태는 보통 OutOfSync다. 아직 실제 리소스가 생성되지 않았기 때문이다.
이제 화면에서 SYNC 버튼을 누르면:
- Repo Server가 Helm 차트를 렌더링해 최종 매니페스트(YAML)를 만든다.
- Application Controller가 해당 매니페스트를 클러스터에 적용한다. 네임스페이스가 없으면 자동으로 만든다.
- Deployment / Service / ConfigMap이 dev-nginx 네임스페이스에 생성된다.
확인:
kubectl get all -n dev-nginx -o wide
curl http://127.0.0.1:30000
정상적으로라면 NodePort(30000)로 접속 시 values-dev.yaml에 정의했던 HTML 페이지가 나온다.
7.2 자동 동기화
7.1의 수동 Sync는 사람이 버튼을 눌러주는 방식이었다. 자동 동기화는 이걸 없앤다.
Argo CD의 Application 리소스는 spec에 syncPolicy.automated 블록을 둘 수 있다:
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=true
여기서 중요한 건 두 가지다.
- automated: Git이 바뀌어 Desired State가 업데이트되면 Argo CD가 자동으로 Sync를 호출한다. 수동으로 “SYNC” 버튼을 누를 필요가 없다.
- prune: true: Git에서 삭제된 리소스를 클러스터에서도 제거한다. 즉 Git이 더 이상 선언하지 않은 Deployment/Service/ConfigMap 등을 자동으로 정리한다.
또한 syncOptions: - CreateNamespace=true는 대상 네임스페이스가 없을 경우 자동 생성하라는 의미다. UI의 “AUTO-CREATE NAMESPACE” 체크와 동일한 효과다.
이 설정을 활용하면 “Git 수정 → 커밋/푸시 → Argo CD가 자동 감지 → 클러스터 업데이트”까지가 완전히 자동화된다. 사람이 배포 버튼을 누르지 않아도 된다.
7.3 커스터마이즈 연동
Argo CD는 Helm뿐 아니라 Kustomize도 직접 이해한다. 즉, repo 안에 kustomization.yaml이 있고, 그 안에서 base/overlay 구조로 리소스를 재정의하면 Argo CD가 그걸 렌더링해서 배포할 수 있다.
일반적인 Kustomize 패턴은 아래와 비슷하다:
app/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml # 공통 스펙
└── overlays/
├── dev/
│ ├── kustomization.yaml # 이미지 태그, replicaCount 등 dev용 patch
└── prd/
├── kustomization.yaml # prd용 patch
Argo CD Application을 정의할 때 source.path를 overlays/dev 또는 overlays/prd로 지정하면, 각 환경별 overlay 결과가 그대로 클러스터에 적용된다. dev와 prd를 완전히 다른 값(예: replica 1 vs replica 3, dev 태그 vs prd 태그 등)으로 유지하면서도 base를 공유할 수 있다.
즉, Helm values-dev.yaml / values-prd.yaml로 환경을 나누는 대신 Kustomize overlay를 사용할 수도 있고, 팀 선호와 기존 자산에 따라 둘 중 하나(또는 혼합)를 선택하면 된다.
7.4 헬름 연동
이번 실습에서는 Helm 차트 (nginx-chart/)를 사용했다. Argo CD는 Helm 차트를 직접 렌더링할 수 있고, values 파일을 환경별로 나눠둘 수 있다.
구조 요약:
- Chart.yaml : 차트 메타데이터 (name, appVersion 등)
- templates/ : Deployment, Service, ConfigMap 등 쿠버네티스 리소스 템플릿
- values-dev.yaml, values-prd.yaml : 환경별 설정
- replicaCount
- Nginx 이미지 태그
- index.html 내용 (DEV / PRD 문구)
- VERSION : 현재 배포 중인 버전 정보 기록용 (사람이 repo만 보고도 현재 버전을 이해할 수 있다)
Argo CD Application에서 Helm 설정은 아래처럼 들어간다:
source:
repoURL: http://<IP>:3000/devops/ops-deploy
targetRevision: HEAD
path: nginx-chart
helm:
valueFiles:
- values-dev.yaml
PRD에 배포할 때는 같은 차트에 values-prd.yaml만 바꿔서 다른 네임스페이스(prd-nginx)로 배포하면 된다. 이 방식으로 동일한 코드베이스에서 DEV/PRD를 동시에 관리할 수 있다.
7.5 이미지 갱신

이제 실제로 애플리케이션 버전을 올린다고 가정해 보자.
예: Nginx 버전 1.26.1 → 1.26.2, replicaCount 1 → 2.
- Helm values 파일을 수정한다. 예: values-dev.yaml의 image.tag와 replicaCount 변경.
- Git에 커밋/푸시한다.
- Argo CD는 Git 변화를 감지한다.
Argo CD는 기본적으로 약 180초(3분)마다 Git/Helm repo를 폴링한다(timeout.reconciliation: 180s 기본값). 이 값은 argocd-cm ConfigMap에서 조정 가능하다. 수동으로는 UI에서 REFRESH를 눌러 즉시 재평가시킬 수 있다.
변경이 감지되면:
- Application은 OutOfSync로 표시된다.
- DIFF 화면에서 Git의 새 버전과 현재 클러스터 리소스를 비교할 수 있다.
- 수동 Sync 모드라면 SYNC를 눌러 반영한다.
- 자동 Sync 모드라면 Application Controller가 알아서 Deployment를 업데이트하고 replicaCount를 조정한다.
추가로 Webhook까지 연결하면 실제로는 폴링 주기(180초)를 기다릴 필요도 없다. 아래 7.6, 7.8에서 이어진다.
7.6 비공개 Git 저장소 배포
실습에서는 사설 Git 서비스(Gogs 등)를 사용하고 있다. Argo CD가 비공개 저장소에서 매니페스트를 읽으려면 인증 정보를 등록해야 한다.
Argo CD UI → Settings → Repositories → “CONNECT REPO”
- Connection method: HTTPS
- Type: git
- Repo URL: http://<IP>:3000/devops/ops-deploy
- Username / Password: Git 계정 + Personal Access Token
- Project: default (또는 해당 AppProject)
이렇게 등록하면 Argo CD Repo Server는 인증된 상태로 Git repo를 clone/cache할 수 있고, 해당 repo를 소스로 하는 Application을 정상적으로 렌더링/배포할 수 있다.
자동화/보안을 위해서는:
- 배포 전용 계정/토큰을 발급해서 최소 권한(읽기 전용)만 부여하는 것이 일반적이다.
- repo URL은 HTTPS로 연결하며 토큰 기반 Basic Auth를 사용한다.
- 해당 자격증명은 Argo CD 내에서 K8S Secret로 저장된다. API Server는 이 Secret을 사용해서 Repo Server에 전달하고, Repo Server는 이를 이용해 repo를 pull한다.
7.7 쿠버네티스 매니페스트 배포 순서
여기서는 크게 세 가지 포인트가 중요하다.

(1) Prune과 리소스 삭제 순서
Argo CD Sync에는 Prune 개념이 있다.
- Prune: Git에서 사라진 리소스를 클러스터에서 삭제해 일관성을 유지하는 기능
- prune: true (자동 동기화 설정 안)인 경우, Git 선언에서 제거된 Deployment/Service/ConfigMap을 Sync 시점에 K8S에서도 지운다.
Prune 시 리소스 삭제 순서를 어떻게 처리할지도 선택할 수 있다. Argo CD UI의 Sync 옵션에서 foreground / background / orphan 등이 등장하는데 이는 K8S의 PropagationPolicy와 비슷한 개념이다.
- foreground: 상위(owner) 리소스가 먼저 정리되며, 그 과정에서 자식 리소스가 차례로 제거된다.
- background: 자식 리소스가 백그라운드에서 제거된다.
- orphan: 부모를 지우되 자식은 남겨둔다.
(2) Finalizer
Application 리소스의 metadata.finalizers에 resources-finalizer.argocd.argoproj.io를 지정할 수 있다:
metadata:
finalizers:
- resources-finalizer.argocd.argoproj.io
이 Finalizer는 Application을 삭제할 때 해당 Application이 생성·관리하던 하위 리소스(Deployment, Service, ConfigMap 등)도 같이 정리하도록 강제한다.
Kubernetes Finalizer 메커니즘은 리소스를 즉시 지우지 않고, finalizer 항목이 처리될 때까지 Terminating 상태로 유지시키는 방식으로 동작한다. Argo CD는 이를 이용해 “Application은 사라졌는데 파드/서비스가 고아로 방치되는 상황”을 막는다.
(3) Drift 감지
누군가가 클러스터에서 직접 리소스를 수정하면(예: ConfigMap에 수동으로 필드 추가), Git에는 없는 내용이 클러스터에만 존재하게 된다.
Argo CD는 이를 감지해 Application 상태를 OutOfSync로 표시하고, Diff 화면에서 차이를 보여준다. 필요하면 Sync를 통해 Git 선언 상태로 되돌릴 수 있다.
이 “drift 감지 → 복구” 루프가 GitOps의 핵심이다. 결과적으로 배포 이력/현재 상태/롤백 포인트가 모두 Git에 남고, 운영자는 Git만 바꿔도 전체 환경을 동일하게 재현할 수 있다.
참고

7.8 동기화 윈도 정의
여기서는 “언제 동기화를 허용할 것인가”를 제어하는 운영 측면의 개념을 다룬다.
Argo CD는 크게 두 가지 방식으로 동기화 타이밍을 제어할 수 있다:
- 폴링 / 수동 Refresh / Webhook 트리거
- 기본적으로 Argo CD는 약 180초(3분)마다 Git/Helm repo를 폴링하며 변경을 감지한다. (timeout.reconciliation 설정으로 조정 가능)
- 사용자는 UI의 REFRESH 버튼으로 즉시 비교(Refresh)를 유도할 수 있다.
- Git 서버(Gogs 등)에서 Webhook을 /api/webhook 엔드포인트로 보내도록 설정해두면, push 시점에 바로 Argo CD가 변경을 감지한다. 이 경우 사실상 지연 없이 Sync까지 이어질 수 있다.
- 자동 Sync on/off와 승인 정책
- syncPolicy.automated를 켜면 변경이 감지될 때마다 자동으로 Sync가 수행된다.
- 운영(특히 PRD)에서는 이 자동 동기화에 제한을 두고, “지금은 동기화하지 마라” 또는 “이 시간대에는 동기화 금지” 같은 정책을 둘 수 있다.
- 이를 통해 야간이나 특정 기간(예: 블랙프라이데이, 대규모 이벤트 기간)에는 자동 배포를 막고 수동 승인을 거치게 할 수 있다.
즉 동기화 윈도는 단순히 “변경을 감지하느냐”를 넘어서 “언제 실제 클러스터에 반영할 수 있도록 허용할 것인가”까지 포함한 운영 정책의 문제다. Argo CD가 자동 동기화까지 담당할 수 있기 때문에, 자동화 범위를 어떻게 둘지와 Sync를 허용할 시간대를 어떻게 관리할지가 팀의 안정성 정책과 직결된다.
정리
7장은 다음을 보여준다.
- Argo CD는 Git을 단일 진실 공급원으로 보고, Git에 선언된 상태를 쿠버네티스 클러스터에 자동으로 유지시키는 GitOps형 CD 컨트롤러다.
- 설치 후에는 Application이라는 CRD로 “이 Repo의 이 경로/이 values를 이 네임스페이스에 배포해라”라는 선언을 만든다.
- Sync는 수동·자동 모두 가능하며, 자동 Sync에서는 prune으로 Git에서 사라진 리소스까지 정리할 수 있다.
- Helm과 Kustomize 모두 지원하므로 환경별 설정(DEV/PRD)이나 overlay 방식 구성이 자연스럽다.
- 이미지 버전/replicaCount 같은 스펙 변경은 Git values(or overlay)만 수정하면 되고, Argo CD가 이를 감지해 클러스터에 반영한다. 폴링, Refresh, Webhook으로 변경을 트리거할 수 있다.
- Finalizer와 Prune 정책을 통해 Application 삭제나 리소스 정리도 선언형으로 관리할 수 있다.
- 동기화 윈도를 통해 “언제 자동 반영을 허용할 것인지”라는 운영 정책까지 모델링할 수 있다.
결국 이 모델은 “Git에 선언 → 컨트롤러가 동기화 → drift 감지 및 복구 → 삭제/정리까지 선언형 관리”라는 완결된 라이프사이클을 제공한다. Argo CD는 배포 그 자체뿐 아니라, 운영 안정성·감사 가능성·롤백 가능성까지 쿠버네티스 네이티브 컨트롤러로 끌어온다.
'스터디(Study) > CI·CD Study' 카테고리의 다른 글
| 로컬 환경에서 Jenkins + Gogs + Kind(K8s) 기반 CI/CD 파이프라인 구축하기 (0) | 2025.11.01 |
|---|---|
| GitOps Cookbook 8장: 고급 주제 (0) | 2025.11.01 |
| GitOps Cookbook 6장: 클라우드 네이티브 CI/CD (0) | 2025.10.25 |
| GitOps Cookbook 5장: 헬름 (0) | 2025.10.25 |
| GitOps Cookbook 4장: 커스터마이즈 (0) | 2025.10.18 |
댓글