ArgoCD를 통한 CD를 학습해보겠습니다.

ArgoCD에 대해서 간략하게 설정하자면 Git Repository에서 선언된 상태와 클러스터의 상태를 일치시켜주는 것입니다.

 

실습환경 구성

cluster 구성

kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
  - containerPort: 30003
    hostPort: 30003
EOF

 

ArgoCD

GitOps

ArgoCD는 GitOps 기반으로 동작된다.

GitOps란 인프라 및 애플리케이션의 구성을 코드화하고, 이를 Git 저장소를 Single Source of Truth 로 삼아 운영하는 방식이다.

 

ArgoCD

📌 ArgoCD란?

선언적 쿠버네티스 GitOps CD(Continuous Delivery) 도구

  • Git 리포지터리를 원천 소스(Source of Truth)로 사용
  • 애플리케이션 컨트롤러가 현재 상태와 의도한 상태를 지속적으로 비교하여 자동 동기화
  • 구성 드리프트 문제 해결 및 배포 이력 추적 용이

주요 사용 사례

  • 배포 자동화: Git 커밋 시 자동으로 클러스터에 반영
  • 관찰 가능성: UI/CLI로 동기화 상태 확인 및 알림
  • 멀티 테넌시: RBAC 정책으로 여러 클러스터 관리

🔑 핵심 개념

Reconciliation(조정)

  • Git 리포지터리의 의도한 상태를 클러스터의 현재 상태와 일치시키는 프로세스
  • Helm 차트 → YAML 렌더링 → kubectl apply로 배포 (helm install 사용 안 함)

주요 용어

용어 설명

타깃 상태 Git에 정의된 의도한 상태
현재 상태 클러스터에 배포된 실제 상태
동기화 상태 타깃 상태와 현재 상태의 일치 여부
동기화(Sync) 클러스터를 타깃 상태로 변경
새로고침 Git과 현재 상태의 차이점 비교
서비스 상태 애플리케이션의 운영 가능 여부

🏗️ 아키텍처 (3대 핵심 구성 요소)

1️⃣ API 서버

  • Web UI, CLI, CI/CD 시스템과 상호작용
  • 역할: 애플리케이션 관리, 인증/SSO, RBAC 정책 강화

2️⃣ 리포지터리 서버

  • Git 리포지터리의 로컬 캐시 유지
  • 쿠버네티스 매니페스트를 다른 컴포넌트에 제공

3️⃣ 애플리케이션 컨트롤러

  • 현재 상태를 지속적으로 모니터링하고 의도한 상태와 비교
  • 불일치 시 자동 동기화 수행 (기본 3분 간격)

동기화 트리거 방법

  1. UI에서 수동 시작
  2. CLI 사용: argocd app sync myapp
  3. Webhook 설정 (GitHub, GitLab 등)

📦 핵심 CRD 리소스

Application

클러스터에 배포할 애플리케이션 인스턴스 정의

kind: Application
spec:
  project: default              # 소속 프로젝트
  source:                        # Git 소스 정보
    repoURL: https://...
    chart: nginx
  destination:                   # 배포 대상
    namespace: nginx
    server: <https://kubernetes.default.svc>

AppProject

관련 애플리케이션을 논리적으로 그룹화

  • 배포 가능한 Repository / Namespace / Resource 제한 가능

Credentials

Repository Credentials (Secret)

Private Git 리포지터리 접근용

labels:
  argocd.argoproj.io/secret-type: repository

  • HTTPS 인증: username/password(PAT)
  • SSH 인증: sshPrivateKey

Cluster Credentials (Secret)

멀티 클러스터 환경에서 각각의 클러스터에 접근하기 위한 설정

labels:
  argocd.argoproj.io/secret-type: cluster

  • bearerToken과 TLS 인증서 포함
  • CLI로도 등록 가능: argocd cluster add CONTEXT_NAME

ArgoCD 설치하기

ArgoCD를 설치하는 방법은 총 4가지 방식이 있다.

  1. Helm Chart로 설치하기
  2. Kustomize로 설치하기
  3. ArgoCLI로 설치하기
  4. Argo-CD Autopilot으로 설치하기

Helm, Kustomize, CLI 방식은 기존에 많이 사용했었던 방식인데 Autopilot으로 설치하는 것은 해본적이 없어서 Autopoilot으로 설치해서 구성하는 방법에 대해서 작성해볼려고 합니다.

ArgoCD Autopilot이란?

배경

부트스트랩 문제

  • Argo CD Application이 동작하려면 → Argo CD가 필요
  • 그런데 Argo CD를 배포하려면 → Argo CD Application이 필요
  • 순환 참조 문제 발생!

핵심 아이디어

Argo CD가 자기 자신을 GitOps 방식으로 관리

  • Autopilot이 초기 부트스트랩을 수행
  • 이후 Argo CD가 자신의 배포와 구성을 스스로 관리

🎯 주요 기능

1️⃣ 자동화된 초기 설정

  • Argo CD 설치 자동화
  • GitOps 환경 초기화
  • Git 리포지터리를 구조화된 형태로 자동 구성

2️⃣ 선언적 관리

  • 애플리케이션/클러스터를 선언적으로 관리
  • Argo CD 수명 주기 전체를 Git으로 관리

3️⃣ 환경 관리

  • 여러 환경(dev, staging, prod)에서 애플리케이션 업데이트
  • 환경 간 승격(promote) 지원

4️⃣ 재해 복구

  • 장애 조치(failover) 클러스터 부트스트랩
  • 필요한 모든 유틸리티와 애플리케이션 자동 복구

ArgoCD Autopilot 설치하기

ArgoCD Autopilot CLI 설치하기

brew install argocd-autopilot
# 버전확인
argocd-autopilot version
v0.4.20

Git Token & Repository 준비하기

  • https://github.com/settings/tokens 에서 classic 모드로 scope에서 repo 체크 후 토큰 생성을 한다.
  • Private 으로 autopilot이라는 Repository를 생성한다.

설치하기

토큰 및 레포 설정하기(토큰 인증방식으므로 https 로 되어 있는 주소를 기입한다.

# 각자 자신의 Git 정보 사용하자
export GIT_TOKEN=<자신의 Git Token>
export GIT_REPO=<자신의 Repo> # 토큰 인증이므로 https로 되어있는 주소를 기입.

부트스트랩 생성하기(아이디, 패스워드는 터미널에서 나오는 값을 참조!)

argocd-autopilot repo bootstrap
# 설치되면 터미널에서 마지막에 패스워드가 나오며 아이디는 admin이다.
INFO running argocd login to initialize argocd config
'admin:login' logged in successfully
Context 'autopilot' updated
INFO argocd initialized. password: hDJIP1Syu5qSZgFJ
INFO run:

    kubectl port-forward -n argocd svc/argocd-server 8080:80

# crd 확인하기
kubectl get crd -n argocd
NAME                          CREATED AT
applications.argoproj.io      2025-11-08T10:49:34Z
applicationsets.argoproj.io   2025-11-08T10:49:34Z
appprojects.argoproj.io       2025-11-08T10:49:34Z

# pod 확인하기
kubectl get pod -n argocd
NAME                                               READY   STATUS    RESTARTS        AGE
argocd-application-controller-0                    1/1     Running   0               2m38s
argocd-applicationset-controller-fc5545556-7b9w8   1/1     Running   0               2m38s
argocd-dex-server-f59c65cff-d9r5g                  1/1     Running   1 (2m17s ago)   2m38s
argocd-notifications-controller-59f6949d7-427cj    1/1     Running   0               2m38s
argocd-redis-75c946f559-drmvz                      1/1     Running   0               2m38s
argocd-repo-server-6959c47c44-jfj58                1/1     Running   0               2m38s
argocd-server-65544f4864-96klq                     1/1     Running   0               2m38s

# 기본 프로젝트 확인
kubectl get appprojects.argoproj.io -n argocd
NAME      AGE
default   2m33s

# 애플리케이션 확인하기
# argo-cd, autopilot-bootstrap, cluster-resources-in-cluster, root이라는 애플리케이션을 자동으로 생성했음을 알 수 있음
kubectl get applications.argoproj.io -n argocd -owide
NAME                           SYNC STATUS   HEALTH STATUS   REVISION                                   PROJECT
argo-cd                        Synced        Healthy         7cce11c26ed4c4ad8ba22ec0e44616716af4ab9b   default
autopilot-bootstrap            Synced        Healthy         7cce11c26ed4c4ad8ba22ec0e44616716af4ab9b   default
cluster-resources-in-cluster   Synced        Healthy         7cce11c26ed4c4ad8ba22ec0e44616716af4ab9b   default
root                           Synced        Healthy         7cce11c26ed4c4ad8ba22ec0e44616716af4ab9b   default

만약 bootstrap을 지정해서 설치하고자 한다면 아래와 같이 배포할 수 있다(따로 bootstrap을 관리하는 경우)

argocd-autopilot repo bootstrap \\
  --repo <https://github.com/your-org/your-repo.git> \\
  --installation-path custom/bootstrap/path

 

Git 소스확인

 

실제 Github에 배포 소스가 올라가있고 kustomize로 배포된 것 같다. 버전은 v0.4.20으로 배포되어있다.

디렉터리 구조

  • apps : 애플리케이션 디렉터리
  • bootstrap : ArgoCD 초기 설정 및 클러스터 리소스
  • projects : 환경별 프로젝트 정의

외부 접근을 위해 NodePort 설정하기

autopilot git clone을 한 다음 bootstrap/argo-cd/kustomization.yaml 을 아래와 같이 수정한 후 git commit & push 를 해준다.

autopilot이 ArgoCD 관리를 위해 application을 생성 해놓았기에 argocd-server service의 type을 NodePort로 설정하면 port-forwarding 없이 접근할 수 있다.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argocd
resources:
- github.com/argoproj-labs/argocd-autopilot/manifests/base?ref=v0.4.20

patches:
- patch: |-
    apiVersion: v1
    kind: Service
    metadata:
      name: argocd-server
      namespace: argocd
    spec:
      type: NodePort
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 8080
        nodePort: 30000
  target:
    kind: Service
    name: argocd-server

 

확인하기

http://localhost:30000 으로 접속하면 아래와 같이 autopilot이 생성한 애플리케이션을 볼 수 있고, ArgoCD 관리도 Git 기반으로 관리함을 볼 수 있다.

 

ArgoCD Autopilot 구조

📂 Git 리포지터리 디렉토리 구조

Autopilot가 생성하는 GitOps 리포지터리는 3개의 주요 폴더로 구성된다.

gitops-repo/
├── bootstrap/              # Argo CD 자체 관리
├── projects/               # AppProject 정의
└── apps/                   # 실제 애플리케이션 (또는 kustomize/)

🏗️ 1. Bootstrap 폴더

Argo CD 자체를 부트스트랩하고 관리하는 핵심 구조

bootstrap/
├── argo-cd.yaml                    # Argo CD Application 정의
├── cluster-resources.yaml          # 클러스터 리소스 ApplicationSet
├── root.yaml                       # 프로젝트 루트 Application
├── argo-cd/
│   └── kustomization.yaml         # Argo CD 설치 Kustomization
└── cluster-resources/
    ├── in-cluster.json            # 클러스터 정보 (변수)
    └── in-cluster/
        ├── argocd-ns.yaml         # argocd 네임스페이스
        └── README.md

핵심 Application 구조

Autopilot 부트스트랩 후 3개의 Application이 자동 생성

1) autopilot-bootstrap Application

  • 역할: 최상위 부모 Application
  • 관리 대상: bootstrap/ 디렉토리 전체
  • 특징: 클러스터에 직접 apply됨 (Git에 저장 안 됨)
  • 나머지 2개 Application을 관리하는 루트

2) argo-cd Application

3) root Application

  • 역할: 모든 프로젝트와 애플리케이션 관리
  • 경로: projects/ 디렉토리
  • 특징: 부트스트랩 직후에는 DUMMY 파일만 존재

🗂️ 2. Projects 폴더

AppProject와 ApplicationSet을 관리

projects/
├── staging.yaml            # Staging AppProject + ApplicationSet
├── production.yaml         # Production AppProject + ApplicationSet
└── README.md

AppProject 예시

# projects/staging.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: staging
spec:
  sourceRepos:
  - '*'
  destinations:
  - namespace: '*'
    server: '<https://kubernetes.default.svc>'
  clusterResourceWhitelist:
  - group: '*'
    kind: '*'
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: staging
spec:
  generators:
  - git:
      repoURL: <https://github.com/user/repo>
      revision: HEAD
      files:
      - path: "apps/**/staging/config.json"
  template:
    # Application 템플릿...

동작 방식

  • ApplicationSet의 Git Generator가 apps/*/staging/config.json 파일들을 감지
  • 각 파일마다 자동으로 Application 생성

📦 3. Apps 폴더 (또는 Kustomize 폴더)

실제 애플리케이션 매니페스트를 Kustomize 패턴으로 관리

apps/ (또는 kustomize/)
└── my-app/
    ├── base/                       # 기본 매니페스트
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   └── kustomization.yaml
    └── overlays/                   # 환경별 오버레이
        ├── staging/
        │   ├── config.json         # Autopilot 설정
        │   ├── kustomization.yaml  # 환경별 커스터마이징
        │   └── configmap.yaml      # 환경별 추가 리소스
        └── production/
            ├── config.json
            ├── kustomization.yaml
            └── configmap.yaml

config.json 구조

{
  "appName": "my-app",
  "userGivenName": "my-app",
  "destNamespace": "default",
  "destServer": "<https://kubernetes.default.svc>",
  "srcPath": "apps/my-app/overlays/staging",
  "srcRepoURL": "<https://github.com/user/repo>",
  "srcTargetRevision": "HEAD"
}

config.json의 역할:

  • ApplicationSet의 Git Generator가 이 파일을 읽음
  • 파일 내용이 Application 생성의 파라미터가 됨
  • 각 환경마다 다른 설정 적용 가능

🔄 전체 동작 흐름

1. argocd-autopilot repo bootstrap
   ↓
2. K8s 클러스터에 Argo CD 직접 배포
   ↓
3. Git 리포지터리에 구조 생성:
   - bootstrap/
   - projects/ (DUMMY)
   - apps/ (없음)
   ↓
4. autopilot-bootstrap Application을 클러스터에 apply
   ↓
5. autopilot-bootstrap이 argo-cd와 root Application 생성
   ↓
6. Argo CD가 자기 자신을 GitOps로 관리 시작

Phase 2: Project 생성

argocd-autopilot project create staging
   ↓
1. projects/staging.yaml 생성 (AppProject + ApplicationSet)
   ↓
2. Git에 커밋
   ↓
3. root Application이 변경 감지
   ↓
4. staging AppProject와 ApplicationSet 자동 배포

Phase 3: Application 추가

argocd-autopilot app create my-app \\
  --app github.com/user/app-repo \\
  -p staging
argocd-autopilot app create my-app \\
  --app github.com/user/app-repo \\
  -p staging
   ↓
1. apps/my-app/ 구조 생성:
   - base/ (원본 매니페스트)
   - overlays/staging/config.json
   ↓
2. Git에 커밋
   ↓
3. staging ApplicationSet이 config.json 감지
   ↓
4. my-app Application 자동 생성 및 배포

🎯 핵심 패턴 요약

1. App of Apps 패턴

autopilot-bootstrap (최상위)
  ├── argo-cd (자기 관리)
  └── root
      ├── staging (Project)
      │   └── my-app (Application)
      └── production (Project)
          └── my-app (Application)

2. Kustomize Overlay 패턴

  • base/: 환경 무관한 기본 리소스
  • overlays/: 환경별 커스터마이징 (dev, staging, prod)

3. Git Generator 패턴

  • ApplicationSet이 config.json 파일 감지
  • 파일 기반 자동 Application 생성
  • 선언적 멀티 환경 관리

ArgoCD Autopilot 실습

Proejct, Application 만들기

프로젝트 생성하기

argocd-autopilot project create dev
argocd-autopilot project create prd

# 프로젝트 생성확인
kubectl get appprojects.argoproj.io -n argocd
NAME      AGE
default   52m
dev       7m49s
prd       7m49s

애플리케이션 만들기

https://github.com/argoproj-labs/argocd-autopilot/examples/demo-app 앱을 사용

hellow-world1 app을 dev, prd 프로젝트에 각각 생성한다. 이를 통해 다양한 배포환경에 대한 애플리케이션을 관리 할 수 있다.

argocd-autopilot app create hello-world1 --app github.com/argoproj-labs/argocd-autopilot/examples/demo-app/ -p dev --type kustomize
argocd-autopilot app create hello-world1 --app github.com/argoproj-labs/argocd-autopilot/examples/demo-app/ -p prd --type kustomize

# 애플리케이션 삭제
argocd-autopilot app delete hello-world1 -p prd

# 애플리케이션 확인
kubectl get applications.argoproj.io -n argocd -owide
NAME                           SYNC STATUS   HEALTH STATUS   REVISION                                   PROJECT
argo-cd                        Synced        Healthy         7efcade9f291f724277bda5e923ac5e0aa31e087   default
autopilot-bootstrap            Synced        Healthy         7efcade9f291f724277bda5e923ac5e0aa31e087   default
cluster-resources-in-cluster   Synced        Healthy         7efcade9f291f724277bda5e923ac5e0aa31e087   default
dev-hello-world1               OutOfSync     Healthy         7efcade9f291f724277bda5e923ac5e0aa31e087   dev
prd-hello-world1               OutOfSync     Healthy         7efcade9f291f724277bda5e923ac5e0aa31e087   prd
root                           Synced        Healthy         7efcade9f291f724277bda5e923ac5e0aa31e087   default

# dev와 prd에 나누어서 배포된 앱 확인
kubectl get deploy,pod
NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/simple-deployment   1/1     1            1           5m8s

NAME                                     READY   STATUS    RESTARTS   AGE
pod/simple-deployment-7854dd65f8-96xq8   1/1     Running   0          5m8s

Git을 확인 해보면 overlays에 두 개의 환경으로 나뉘어져 설정됨을 확인 할 수 있다.

 

ArgoCD에서는 동일한 애플리케이션이 dev, prd 각각 배포되어 있다.

 

실제 ArgoCD을 Kustomize 패턴으로 Git을 설계하는 과정이 처음에 할려면 어렵고 복잡한데 Autopilot을 이용하면 그러한 설정을 자동으로 해주는 것 같다. 해당 템플릿을 이용해서 Autopilot CLI으로 bootstrap을 만들고 실제 Git을 수정해서 관리하면 초반에 환경구축하는데 좋을 것 같아 보인다.

 

Blue-Green 배포

Argo Rollouts는 두 개의 서비스를 사용합니다

  • Active Service: 현재 프로덕션 트래픽을 받는 서비스
  • Preview Service: 새 버전을 테스트하는 서비스

동작과정

초기 상태:
┌─────────────┐
│ Active Svc  │ ──> Blue Pods (v1.0) ──> 사용자 트래픽
└─────────────┘

새 버전 배포:
┌─────────────┐
│ Active Svc  │ ──> Blue Pods (v1.0) ──> 사용자 트래픽
└─────────────┘

┌──────────────┐
│ Preview Svc  │ ──> Green Pods (v2.0) ──> 테스트용 (트래픽 없음)
└──────────────┘

트래픽 전환:
┌─────────────┐
│ Active Svc  │ ──> Green Pods (v2.0) ──> 사용자 트래픽 (전환됨)
└─────────────┘

┌──────────────┐
│ Preview Svc  │ ──> Blue Pods (v1.0) ──> 롤백 대기
└──────────────┘

 

argo rollout plugin 설치하기

curl -LO <https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-darwin-arm64>
chmod +x ./kubectl-argo-rollouts-darwin-arm64
sudo mv ./kubectl-argo-rollouts-darwin-arm64 /usr/local/bin/kubectl-argo-rollouts
kubectl argo rollouts version

kubectl-argo-rollouts: v1.8.3+49fa151
  BuildDate: 2025-06-04T22:19:21Z
  GitCommit: 49fa1516cf71672b69e265267da4e1d16e1fe114
  GitTreeState: clean
  GoVersion: go1.23.9
  Compiler: gc
  Platform: darwin/arm64

 

Rollout 설치하기

blue-green 테스트를 하기 위해서 rollout을 설치해야 한다. 아래의 파일들을 autopilot repo에서 생성하고 commit & push를 한다.

디렉터리는 표시된대로 생성 한 후 진행한다.

 

bootstrap/argo-rollouts/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argo-rollouts

resources:
  - <https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml>

 

bootstrap/cluster-resources/in-cluster/argo-rollouts-ns.yaml

apiVersion: v1
kind: Namespace
metadata:
  annotations:
    argocd.argoproj.io/sync-options: Prune=false
  creationTimestamp: null
  name: argo-rollouts
spec: {}
status: {}

 

bootstrap/argo-rollout.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  creationTimestamp: null
  labels:
    app.kubernetes.io/managed-by: argocd-autopilot
    app.kubernetes.io/name: argo-rollout
  name: argo-rollout
  namespace: argocd
spec:
  destination:
    namespace: argo-rollouts
    server: <https://kubernetes.default.svc>
  ignoreDifferences:
  - group: argoproj.io
    jsonPointers:
    - /status
    kind: Application
  project: default
  source:
    path: bootstrap/argo-rollouts
    repoURL: ***<본인의 autopilot git 주소>***
  syncPolicy:
    automated:
      allowEmpty: true
      prune: true
      selfHeal: true
    syncOptions:
    - allowEmpty=true
status:
  health: {}
  sourceHydrator: {}
  summary: {}
  sync:
    comparedTo:
      destination: {}
      source:
        repoURL: ""
    status: ""

 

blue-green applicaion 과 project를 만들어서 배포해본다.

실제 동작할 rollout, application, project를 만든다.

apps/blue-green-demo/blue-green/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- rollout.yaml
- active-service.yaml
- preview-service.yaml

 

apps/blue-green-demo/blue-green/active-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: blue-green-demo-active
  namespace: default
spec:
  selector:
    app: blue-green-demo
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
    nodePort: 30002

 

apps/blue-green-demo/blue-green/preview-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: blue-green-demo-preview
  namespace: default
spec:
  selector:
    app: blue-green-demo
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
    nodePort: 30001

 

apps/blue-green-demo/blue-green/rollout.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: blue-green-demo
  namespace: default
spec:
  replicas: 2
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: blue-green-demo
  template:
    metadata:
      labels:
        app: blue-green-demo
    spec:
      containers:
      - name: rollouts-demo
        image: argoproj/rollouts-demo:blue
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
  strategy:
    blueGreen:
      activeService: blue-green-demo-active
      previewService: blue-green-demo-preview
      autoPromotionEnabled: true
      autoPromotionSeconds: 100

 

projects/blue-green.yaml

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  annotations:
    argocd-autopilot.argoproj-labs.io/default-dest-server: <https://kubernetes.default.svc>
    argocd.argoproj.io/sync-options: PruneLast=true
    argocd.argoproj.io/sync-wave: "-2"
  name: blue-green
  namespace: argocd
spec:
  clusterResourceWhitelist:
  - group: '*'
    kind: '*'
  description: blue-green project
  destinations:
  - namespace: '*'
    server: '*'
  namespaceResourceWhitelist:
  - group: '*'
    kind: '*'
  sourceRepos:
  - '*'

---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: blue-green-demo
  namespace: argocd
  labels:
    app.kubernetes.io/managed-by: argocd-autopilot
    app.kubernetes.io/name: blue-green-demo
spec:
  project: blue-green
  source:
    repoURL: ***<본인의 autopilot git 주소>***
    targetRevision: main
    path: apps/blue-green-demo/blue-green
  destination:
    server: <https://kubernetes.default.svc>
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
  ignoreDifferences:
  - group: argoproj.io
    jsonPointers:
    - /status
    kind: Rollout

위 와 같이 만들고 commit & push 를 하면 rollout이 배포됨을 확인 할 수 있다.

배포확인

k get rollouts
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
blue-green-demo   2         2         2            2           56m

k get pods
NAME                               READY   STATUS    RESTARTS   AGE
blue-green-demo-5b4d597cd6-6flz7   1/1     Running   0          26m
blue-green-demo-5b4d597cd6-fmcbr   1/1     Running   0          26m

# rollout 상태 추적
kubectl argo rollouts get rollout blue-green-demo  --watch

블루그린 확인(preview, active 둘다 블루이다)

 

preview localhost:30001 active localhost:30002

 

argocd rollout 상태

그럼 apps/blue-green-demo/blue-green/rollout.yaml 에서 image을 blue 에서 green 으로 변경해본다.

    spec:
      containers:
      - name: rollouts-demo
        image: argoproj/rollouts-demo:green

수정 후 commit & push

green 으로 배포 되면 preview에서는 green 이 active 에서는 blue가 보인다.

 

active localhost:30002 preview localhost:30002

 

초기 preview 만 배포 상태
100초 이후 preview, active 둘 다 green으로 배포된 상태

autoPromotionSeconds: 100 로 설정했기에 100초 이후 preview, active 둘 다 green 으로 변경됨을 확인 할 수 있다.

 

ArgoCD HA 구성하기

ArgoCD를 실제 Production에서 운영하기 위해서 HA를 설정해서 운영을 해야하는데 그 과정에 대해서 다뤄본다. 상세설명

  • Argo CD HA의 핵심은 Controller, Repo-server, Server 3대 구성요소를 다중화 + Redis HA 구성
  • Redis HA는 Sentinel + HAProxy 로 장애 시 자동 failover
  • Controller는 Leader Election으로 1개만 active, 나머지는 standby
  • Repo-server / Server는 수평 확장으로 부하 분산
  • 모든 구성요소는 Argo CD CRD(Application)를 watch하여 자동 GitOps 수행

설치하기

사전에 argocd-ha 라는 Private Github Repository를 생성하고 clone 한 후 진행한다.

git clone <자신의 Github Repo 주소>
cd argocd-ha
mkdir resources

cat << EOF > resources/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: argocd
EOF

kubectl apply -f resources/namespace.yaml
wget <https://raw.githubusercontent.com/argoproj/argo-cd/refs/heads/master/manifests/ha/install.yaml>
mv install.yaml resources/
kubectl apply -f resources/install.yaml -n argocd

# 확인
watch -d kubectl get pod -n argocd

# 비밀번호 확인
kubectl get secret -n argocd argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d ; echo
LGKo7EJ1e08v1fdM

# NodePort 수정
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: server
    app.kubernetes.io/name: argocd-server
    app.kubernetes.io/part-of: argocd
  name: argocd-server
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    nodePort: 30000
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8080
  selector:
    app.kubernetes.io/name: argocd-server

# 원격 리포지터리에 커밋하고 푸시한다.
git add . && git commit -m "Deploy Argo CD " && git push -u origin main

ArgoCD 자체 관리

ArgoCD 배포 이후 ArgoCD 자기 자신을 GItOps로 관리할 수 있는 기능을 제공한다.

  • Argo CD UI → Settings → Repo 에 자신의 Repo 추가
  • ArgoCD 애플리케이션 생성
  • cat <* targetRevision: main syncPolicy: automated: {} destination: namespace: argocd server: <https://kubernetes.default.svc> EOF # 확인하기 kubectl get applications.argoproj.io -n argocd -owide NAME SYNC STATUS HEALTH STATUS REVISION PROJECT argocd Synced Healthy e8d0e07367cc648be4de0b9d7f5d12f204f20644 default

Argo CD 설정 변경

  • networkpolicy 를 삭제 한 후 실제로 반영이 이루어지는 지 확인해보자.
  • install.yaml 에서 networkpolicy 관련 설정들을 삭제하고 Push 한다.
  • Push 이후 ArgoCD UI에서 Prune 설정을 켜고(install.yaml 에서 설정가능) Sync 된 것을(180초 이후) 확인 하며 삭제된 것을 볼 수 있다.
# 배포된 networkpolicy
kubectl get networkpolicies.networking.k8s.io -n argocd
NAME                                              POD-SELECTOR                                              AGE
argocd-application-controller-network-policy      app.kubernetes.io/name=argocd-application-controller      40m
argocd-applicationset-controller-network-policy   app.kubernetes.io/name=argocd-applicationset-controller   40m
argocd-dex-server-network-policy                  app.kubernetes.io/name=argocd-dex-server                  40m
argocd-notifications-controller-network-policy    app.kubernetes.io/name=argocd-notifications-controller    40m
argocd-redis-ha-proxy-network-policy              app.kubernetes.io/name=argocd-redis-ha-haproxy            40m
argocd-redis-ha-server-network-policy             app.kubernetes.io/name=argocd-redis-ha                    40m
argocd-repo-server-network-policy                 app.kubernetes.io/name=argocd-repo-server                 40m
argocd-server-network-policy                      app.kubernetes.io/name=argocd-server                      40m

# 삭제 후 확인
kubectl get networkpolicies.networking.k8s.io -n argocd
No resources found in argocd namespace.

관찰 가능성

kube-prometheus-stack 설치

# repo 추가
helm repo add prometheus-community <https://prometheus-community.github.io/helm-charts>

# 파라미터 파일 생성
cat < monitor-values.yaml
prometheus:
  prometheusSpec:
    scrapeInterval: "15s"
    evaluationInterval: "15s"
  service:
    type: NodePort
    nodePort: 30002

grafana:
  defaultDashboardsTimezone: Asia/Seoul
  adminPassword: prom-operator
  service:
    type: NodePort
    nodePort: 30003

alertmanager:
  enabled: false
defaultRules:
  create: false
prometheus-windows-exporter:
  prometheus:
    monitor:
      enabled: false
EOT
cat monitor-values.yaml

# 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 75.15.1 \\
-f monitor-values.yaml --create-namespace --namespace monitoring

# 각각 웹 접속 실행
open  # Prometheus
open  # Grafana

# 확인
## grafana : 프로메테우스는 메트릭 정보를 저장하는 용도로 사용하며, 그라파나로 시각화 처리
## prometheus-0 : 모니터링 대상이 되는 파드는 ‘exporter’라는 별도의 사이드카 형식의 파드에서 모니터링 메트릭을 노출, pull 방식으로 가져와 내부의 시계열 데이터베이스에 저장
## node-exporter : 노드익스포터는 물리 노드에 대한 자원 사용량(네트워크, 스토리지 등 전체) 정보를 메트릭 형태로 변경하여 노출
## operator : 시스템 경고 메시지 정책(prometheus rule), 애플리케이션 모니터링 대상 추가 등의 작업을 편리하게 할수 있게 CRD 지원
## kube-state-metrics : 쿠버네티스의 클러스터의 상태(kube-state)를 메트릭으로 변환하는 파드
helm list -n monitoring
kubectl get pod,svc,ingress,pvc -n monitoring
kubectl get-all -n monitoring
kubectl get prometheus,servicemonitors -n monitoring
~~~~kubectl get crd | grep monitoring

# 프로메테우스 버전 확인
kubectl exec -it sts/prometheus-kube-prometheus-stack-prometheus -n monitoring -c prometheus -- prometheus --version

# 프로메테우스 리소스 정보 확인
kubectl get prometheuses.monitoring.coreos.com -n monitoring
kubectl get prometheuses.monitoring.coreos.com -n monitoring -o yaml | k neat | yq

serviceMonitorSelector 의 Label 이 일치해야 모니터링 정보를 가져올 수 있다.
  serviceMonitorSelector:
    matchLabels:
      release: kube-prometheus-stack

Argo CD 구성요소에 대한 ServiceMonitor 생성

Prometheus Operator의 CRD로, 쿠버네티스 서비스의 메트릭을 자동으로 수집하도록 설정

Argo CD 메트릭 엔드포인트

컴포넌트 Service 이름 포트 메트릭 경로

Application Controller argocd-metrics 8082 /metrics
Server argocd-server-metrics 8083 /metrics
Repo Server argocd-repo-server 8084 /metrics
ApplicationSet Controller argocd-applicationset-controller 8080 /metrics
Dex Server argocd-dex-server 5558 /metrics
Redis HAProxy argocd-redis-ha-haproxy 9101 /metrics
Notifications Controller argocd-notifications-controller-metrics 9001 /metrics
# 테스트용 파드 기동
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
EOF
    
# application-controller 메트릭 호출
kubectl exec -it -n default nginx -- curl argocd-metrics.argocd.svc:8082/metrics
...

# 추적 argocd-metrics 이 실제 수집하는 곳은?
# endpoints/argocd-metrics 를 수집
kubectl get svc,ep -n argocd -l app.kubernetes.io/name=argocd-metrics
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/argocd-metrics   ClusterIP   10.96.203.215   <none>        8082/TCP   82m

NAME                       ENDPOINTS          AGE
endpoints/argocd-metrics   10.244.2.22:8082   82m

# endpoints/argocd-metrics 조회 시 argocd-application-controller 를 바라봄
kubectl get svc -n argocd argocd-metrics -o yaml | k neat | yq
...
  ports:
    - name: metrics
      port: 8082
  selector:
    app.kubernetes.io/name: argocd-application-controller

# argocd-application-controller 확인
kubectl get pod -n argocd -l app.kubernetes.io/name=argocd-application-controller
NAME                              READY   STATUS    RESTARTS   AGE
argocd-application-controller-0   1/1     Running   0          109m

# ServiceMonitor 생성
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-metrics
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
EOF

# argocd-server 메트릭 호출
kubectl exec -it -n default nginx -- curl argocd-server-metrics.argocd.svc:8083/metrics
...

# argocd service 중에 argocd-server-metrics label을 가지고 있는 
k get svc,ep -n argocd -l app.kubernetes.io/name=argocd-server-metrics
NAME                            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/argocd-server-metrics   ClusterIP   10.96.1.83   <none>        8083/TCP   72m

NAME                              ENDPOINTS                         AGE
endpoints/argocd-server-metrics   10.244.1.5:8083,10.244.3.4:8083   72m

k get svc -n argocd argocd-server-metrics -o yaml | k neat | yq
...
  ports:
    - name: metrics
      port: 8083
  selector:
    app.kubernetes.io/name: argocd-server

kubectl get pod -n argocd -l app.kubernetes.io/name=argocd-server
NAME                            READY   STATUS    RESTARTS   AGE
argocd-server-8b767f58c-pd2dj   1/1     Running   0          92m
argocd-server-8b767f58c-qwk7z   1/1     Running   0          92m

# ServiceMonitor 생성
# release: kube-prometheus-stack 값이 serviceMonitorSelector 와 일치해야 수집이 가능하다.
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-server-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-server-metrics
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
EOF

# repo-server 메트릭 호출
kubectl exec -it -n default nginx -- curl argocd-repo-server.argocd.svc:8084/metrics
...

# ServiceMonitor 생성
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-repo-server-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-repo-server
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
EOF

# 나머지 ServiceMonitor 생성
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-applicationset-controller-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-applicationset-controller
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-dex-server
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-dex-server
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-redis-haproxy-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-redis-ha-haproxy
  endpoints:
    - port: http-exporter-port
  namespaceSelector:
    matchNames:
      - argocd
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-notifications-controller
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-notifications-controller-metrics
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
EOF

# 나머지 확인
kubectl get servicemonitors -n monitoring | grep argocd
argocd-applicationset-controller-metrics         7m52s
argocd-dex-server                                7m52s
argocd-notifications-controller                  7m52s
argocd-redis-haproxy-metrics                     7m52s
argocd-repo-server-metrics                       8m
argocd-server-metrics                            8m19s

Grafana Application 생성 후 확인

# guestbook helm 차트 애플리케이션 생성
cat <https://github.com/argoproj/argocd-example-apps>
    targetRevision: HEAD
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: guestbook
    server: <https://kubernetes.default.svc>
EOF

'스터디 > [gasida] ci-cd 스터디 1기' 카테고리의 다른 글

OpenLDAP + KeyCloak + Argo CD + Jenkins  (0) 2025.11.23
ArgoCD ApplicationSet  (0) 2025.11.23
Arocd Rollout  (0) 2025.11.16
ArgoCD + Ingress + Self Managed  (0) 2025.11.16
3주차: Jenkins + ArgoCD  (0) 2025.11.01

+ Recent posts