Skip to content

ArgoCD ๋ชจ๋ฒ” ์‚ฌ๋ก€ โ€‹

๊ฒ€ํ†  ๊ธฐ์ค€: Argo CD 3.5.2 / Helm Chart 10.8.4 / Kustomize 5.8.1. ๋งค๋‹ˆํŽ˜์ŠคํŠธ ์˜ˆ์ œ๋Š” ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ ๊ฒ€ํ†  ํ›„ ํŒจ์น˜ 3.5.4(Kustomize 5.8.1 ๋™์ผ)๋กœ ๊ฐฑ์‹ (์˜ˆ์ œ ์žฌ์‹คํ–‰ ์•ˆ ํ•จ) ๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ: 2026๋…„ 10์›” 12์ผ

๋ชฉ์ฐจ โ€‹

์ €์žฅ์†Œ ๊ตฌ์กฐ โ€‹

๋ชจ๋…ธ๋ ˆํฌ vs ํด๋ฆฌ๋ ˆํฌ โ€‹

๋ชจ๋…ธ๋ ˆํฌ๋Š” ํ•˜๋‚˜์˜ Git ์ €์žฅ์†Œ ์•ˆ์— app-a, app-b, infra ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ํ•จ๊ป˜ ๋“ค์–ด์žˆ๊ณ , ํด๋ฆฌ๋ ˆํฌ๋Š” ๊ฐ™์€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ app-a-repo, app-b-repo, infra-repo๋ผ๋Š” ๋…๋ฆฝ๋œ ์„ธ ๊ฐœ์˜ Git ์ €์žฅ์†Œ๋กœ ๋ถ„๋ฆฌํ•œ ๊ตฌ์กฐ๋ฅผ ๋น„๊ตํ•ด ๋ณด์—ฌ์ค€๋‹ค.

๋ชจ๋…ธ๋ ˆํฌ๋Š” ํ•˜๋‚˜์˜ Git ์ €์žฅ์†Œ ์•ˆ์— app-a, app-b, infra ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ํ•จ๊ป˜ ๋“ค์–ด์žˆ๊ณ , ํด๋ฆฌ๋ ˆํฌ๋Š” ๊ฐ™์€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ app-a-repo, app-b-repo, infra-repo๋ผ๋Š” ๋…๋ฆฝ๋œ ์„ธ ๊ฐœ์˜ Git ์ €์žฅ์†Œ๋กœ ๋ถ„๋ฆฌํ•œ ๊ตฌ์กฐ๋ฅผ ๋น„๊ตํ•ด ๋ณด์—ฌ์ค€๋‹ค.์ „์ฒด ํ™”๋ฉด์œผ๋กœ ์—ด๊ธฐ โ†—
๋ฐฉ์‹์žฅ์ ๋‹จ์ 
๋ชจ๋…ธ๋ ˆํฌ๋‹จ์ผ PR๋กœ ์—ฌ๋Ÿฌ ์•ฑ ๋ณ€๊ฒฝ, ์ผ๊ด€์„ฑ๊ถŒํ•œ ๊ด€๋ฆฌ ๋ณต์žก, ์ €์žฅ์†Œ ํฌ๊ธฐ ์ฆ๊ฐ€
ํด๋ฆฌ๋ ˆํฌํŒ€๋ณ„ ๋…๋ฆฝ์„ฑ, ์„ธ๋ถ„ํ™”๋œ ๊ถŒํ•œํฌ๋กœ์Šค ์•ฑ ๋ณ€๊ฒฝ ์–ด๋ ค์›€

๊ถŒ์žฅ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ โ€‹

App of Apps ํŒจํ„ด:

gitops-repo/
โ”œโ”€โ”€ apps/                           # ArgoCD Applications
โ”‚   โ”œโ”€โ”€ root-app.yaml              # Root Application
โ”‚   โ””โ”€โ”€ children/
โ”‚       โ”œโ”€โ”€ frontend.yaml
โ”‚       โ”œโ”€โ”€ backend.yaml
โ”‚       โ””โ”€โ”€ platform.yaml
โ”œโ”€โ”€ base/                           # ๊ณตํ†ต ๋ฒ ์ด์Šค
โ”‚   โ”œโ”€โ”€ frontend/
โ”‚   โ”‚   โ”œโ”€โ”€ deployment.yaml
โ”‚   โ”‚   โ”œโ”€โ”€ service.yaml
โ”‚   โ”‚   โ””โ”€โ”€ kustomization.yaml
โ”‚   โ”œโ”€โ”€ backend/
โ”‚   โ”‚   โ””โ”€โ”€ ...
โ”‚   โ””โ”€โ”€ platform/
โ”‚       โ””โ”€โ”€ ...
โ”œโ”€โ”€ overlays/                       # ํ™˜๊ฒฝ๋ณ„ ์˜ค๋ฒ„๋ ˆ์ด
โ”‚   โ”œโ”€โ”€ dev/
โ”‚   โ”‚   โ”œโ”€โ”€ frontend/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ kustomization.yaml
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ patches/
โ”‚   โ”‚   โ””โ”€โ”€ backend/
โ”‚   โ”œโ”€โ”€ staging/
โ”‚   โ”‚   โ””โ”€โ”€ ...
โ”‚   โ””โ”€โ”€ prod/
โ”‚       โ””โ”€โ”€ ...
โ”œโ”€โ”€ helm-values/                    # Helm values ํŒŒ์ผ
โ”‚   โ”œโ”€โ”€ dev/
โ”‚   โ”œโ”€โ”€ staging/
โ”‚   โ””โ”€โ”€ prod/
โ””โ”€โ”€ projects/                       # AppProject ์ •์˜
    โ”œโ”€โ”€ development.yaml
    โ”œโ”€โ”€ staging.yaml
    โ””โ”€โ”€ production.yaml

ํ™˜๊ฒฝ๋ณ„ ๋ถ„๋ฆฌ ๊ตฌ์กฐ:

gitops-repo/
โ”œโ”€โ”€ environments/
โ”‚   โ”œโ”€โ”€ dev/
โ”‚   โ”‚   โ”œโ”€โ”€ apps/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ frontend/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ backend/
โ”‚   โ”‚   โ””โ”€โ”€ argocd/
โ”‚   โ”‚       โ””โ”€โ”€ applications.yaml
โ”‚   โ”œโ”€โ”€ staging/
โ”‚   โ”‚   โ””โ”€โ”€ ...
โ”‚   โ””โ”€โ”€ prod/
โ”‚       โ””โ”€โ”€ ...
โ”œโ”€โ”€ charts/                         # ๋‚ด๋ถ€ Helm ์ฐจํŠธ
โ”‚   โ”œโ”€โ”€ frontend/
โ”‚   โ””โ”€โ”€ backend/
โ””โ”€โ”€ lib/                            # ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    โ”œโ”€โ”€ kustomize/
    โ””โ”€โ”€ jsonnet/

Kustomize ๋ชจ๋ฒ” ์‚ฌ๋ก€ โ€‹

yaml
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml

labels:
  - pairs:
      app.kubernetes.io/managed-by: argocd
    includeSelectors: false

---
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base

namespace: production

namePrefix: prod-

labels:
  - pairs:
      environment: production
    includeSelectors: false

replicas:
  - name: my-app
    count: 5

images:
  - name: my-app
    newName: my-registry/my-app
    newTag: v1.2.3

patches:
  - path: patches/resource-limits.yaml

์œ„ ์˜ˆ์ œ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ €์žฅ์†Œ์— ์‹ค์ œ base ๋ฆฌ์†Œ์Šค์™€ patch ํŒŒ์ผ์ด ์žˆ๋‹ค๋Š” ์ „์ œ์ž…๋‹ˆ๋‹ค. labels๋กœ selector๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. HPA๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋ ค๋ฉด resources์— HPA manifest๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  Git์˜ ๊ณ ์ • replicas ์„ค์ •์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์กด์žฌํ•˜์ง€ ์•Š๋Š” HPA๋ฅผ patch๋งŒ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. base์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์ด๋ฆ„์€ my-app์ด๋ผ๋Š” ์ „์ œ์ด๋ฉฐ ์ด๋ฆ„/ํƒœ๊ทธ ๋ณ€ํ™˜์€ overlay์—์„œ ํ•จ๊ป˜ ํ•ฉ๋‹ˆ๋‹ค. base์—์„œ ๋จผ์ € ์ด๋ฆ„์„ ๋ฐ”๊พธ๋ฉด ์ด์ „ ์ด๋ฆ„์„ ์ฐพ๋Š” overlay๊ฐ€ ํƒœ๊ทธ๋ฅผ ๊ฐฑ์‹ ํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ™˜๊ฒฝ ์Šน๊ฒฉ ์ „๋žต โ€‹

Git ๋ธŒ๋žœ์น˜ ๊ธฐ๋ฐ˜ ์Šน๊ฒฉ โ€‹

develop, staging, main ๋ธŒ๋žœ์น˜๊ฐ€ PR ์Šน์ธ์œผ๋กœ ์ˆœ์ฐจ ์Šน๊ฒฉ๋˜๊ณ  Dev์™€ Staging ํ™˜๊ฒฝ์€ Argo CD๊ฐ€ ์ž๋™ ๋ฐฐํฌํ•˜์ง€๋งŒ Prod ํ™˜๊ฒฝ๋งŒ ์ˆ˜๋™ ๋™๊ธฐํ™” ๊ฒŒ์ดํŠธ๋ฅผ ๊ฑฐ์น˜๋Š” Git ๋ธŒ๋žœ์น˜ ๊ธฐ๋ฐ˜ ํ™˜๊ฒฝ ์Šน๊ฒฉ ํ๋ฆ„์„ ๋ณด์—ฌ์ค€๋‹ค.

develop, staging, main ๋ธŒ๋žœ์น˜๊ฐ€ PR ์Šน์ธ์œผ๋กœ ์ˆœ์ฐจ ์Šน๊ฒฉ๋˜๊ณ  Dev์™€ Staging ํ™˜๊ฒฝ์€ Argo CD๊ฐ€ ์ž๋™ ๋ฐฐํฌํ•˜์ง€๋งŒ Prod ํ™˜๊ฒฝ๋งŒ ์ˆ˜๋™ ๋™๊ธฐํ™” ๊ฒŒ์ดํŠธ๋ฅผ ๊ฑฐ์น˜๋Š” Git ๋ธŒ๋žœ์น˜ ๊ธฐ๋ฐ˜ ํ™˜๊ฒฝ ์Šน๊ฒฉ ํ๋ฆ„์„ ๋ณด์—ฌ์ค€๋‹ค.์ „์ฒด ํ™”๋ฉด์œผ๋กœ ์—ด๊ธฐ โ†—

Application ์„ค์ •:

workloads AppProject๊ฐ€ ์•„๋ž˜ ์ €์žฅ์†Œยท๋Œ€์ƒ namespace๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  ๋Œ€์ƒ namespace๋Š” ๋ฏธ๋ฆฌ ์ค€๋น„๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋žœ์น˜ ์ „๋žต์€ ํ•˜๋‚˜์˜ ์„ ํƒ์ง€์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๊ฐ™์€ main์—์„œ PR๋กœ ์Šน๊ฒฉํ•˜๋ฉด ์žฅ๊ธฐ ๋ธŒ๋žœ์น˜ ๊ฐ„ ์ฐจ์ด๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. App of Apps๋Š” ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ์ด๋ฉฐ ํ•˜์œ„ Application ์ƒ์„ฑ ๊ถŒํ•œ๊ณผ ์ €์žฅ์†Œ ์“ฐ๊ธฐ ๊ถŒํ•œ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-dev
  namespace: argocd
spec:
  project: workloads
  source:
    repoURL: https://github.com/myorg/gitops.git
    targetRevision: develop
    path: overlays/dev
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app-dev
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-staging
  namespace: argocd
spec:
  project: workloads
  source:
    repoURL: https://github.com/myorg/gitops.git
    targetRevision: staging
    path: overlays/staging
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app-staging
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-prod
  namespace: argocd
spec:
  project: workloads
  source:
    repoURL: https://github.com/myorg/gitops.git
    targetRevision: main
    path: overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app-prod

์ด๋ฏธ์ง€ ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ์Šน๊ฒฉ โ€‹

๋™์ผํ•œ ๊ฒ€์ฆ๋œ ์ด๋ฏธ์ง€๋ฅผ ํ™˜๊ฒฝ ๊ฐ„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. registry๊ฐ€ ํƒœ๊ทธ ๋ถˆ๋ณ€์„ฑ์„ ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฉด digest๋ฅผ ๊ณ ์ •ํ•ฉ๋‹ˆ๋‹ค. dev-latest ๊ฐ™์€ ํƒœ๊ทธ์˜ ๋‚ด์šฉ๋งŒ ๊ต์ฒดํ•ด๋„ Git manifest๋‚˜ Deployment Pod template์ด ์ž๋™์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

yaml
# overlays/dev/kustomization.yaml์˜ images ์กฐ๊ฐ
images:
  - name: my-app
    newName: my-registry/my-app
    newTag: v1.2.3
---
# overlays/staging/kustomization.yaml์˜ images ์กฐ๊ฐ
images:
  - name: my-app
    newName: my-registry/my-app
    newTag: v1.2.3
---
# overlays/prod/kustomization.yaml์˜ images ์กฐ๊ฐ
images:
  - name: my-app
    newName: my-registry/my-app
    newTag: v1.2.3

์ž๋™ํ™”๋œ ์Šน๊ฒฉ ํŒŒ์ดํ”„๋ผ์ธ โ€‹

์ด ์›Œํฌํ”Œ๋กœ๋Š” ์ด๋ฏธ ํ…Œ์ŠคํŠธํ•œ digest๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ PR๋งŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. registry/overlay ๊ฒฝ๋กœ๋Š” ์˜ˆ์‹œ์ด๋ฉฐ ์‹ค์ œ ์ €์žฅ์†Œ์— ๋งž์ถฅ๋‹ˆ๋‹ค. ํ•œ๊ธ€ ์˜ˆ์ œ์˜ overlays/prod๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์•„๋ž˜ ๋‘ overlays/production ๊ฒฝ๋กœ๋„ ํ•จ๊ป˜ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. GITOPS_PR_TOKEN์€ ๋Œ€์ƒ ์ €์žฅ์†Œ์˜ contents/pull requests ์“ฐ๊ธฐ ๊ถŒํ•œ์„ ๊ฐ€์ง„ GitHub App ํ† ํฐ ๋˜๋Š” ์ œํ•œ๋œ ํ† ํฐ์œผ๋กœ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ GITHUB_TOKEN์œผ๋กœ ๋งŒ๋“  ๋ณ€๊ฒฝ์€ ํ›„์† workflow ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์ œํ•œ๋˜๋ฏ€๋กœ required checks ์‹คํ–‰ ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์Šน์ธยทํ…Œ์ŠคํŠธยท์„œ๋ช…/์ •์ฑ… ๊ฒ€์ฆ์€ ์ €์žฅ์†Œ์˜ branch protection/ruleset์—์„œ ๊ฐ•์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

yaml
name: Promote tested image to production
on:
  workflow_dispatch:
    inputs:
      digest:
        description: 'Tested image digest (sha256: followed by 64 hex characters)'
        required: true
        type: string
permissions:
  contents: read
concurrency:
  group: promote-production
  cancel-in-progress: false
jobs:
  promote:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false
      - name: Install verified Kustomize
        shell: bash
        run: |
          set -euo pipefail
          tool_dir="$RUNNER_TEMP/kustomize-bin"
          mkdir -p "$tool_dir"
          cd "$tool_dir"
          curl -fsSL -o kustomize.tar.gz \
            https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v5.8.1/kustomize_v5.8.1_linux_amd64.tar.gz
          echo "029a7f0f4e1932c52a0476cf02a0fd855c0bb85694b82c338fc648dcb53a819d  kustomize.tar.gz" | sha256sum -c -
          tar -xzf kustomize.tar.gz kustomize
          echo "$tool_dir" >> "$GITHUB_PATH"
      - name: Update production overlay
        env:
          IMAGE_DIGEST: ${{ inputs.digest }}
        shell: bash
        run: |
          set -euo pipefail
          [[ "$IMAGE_DIGEST" =~ ^sha256:[a-f0-9]{64}$ ]] || exit 1
          cd overlays/production
          kustomize edit set image "my-app=my-registry/my-app@${IMAGE_DIGEST}"
          kustomize build . > /dev/null
      - name: Create reviewed promotion PR
        uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
        with:
          token: ${{ secrets.GITOPS_PR_TOKEN }}
          branch: promote-production
          title: 'Promote tested image to production'
          commit-message: 'chore: promote tested image digest'
          add-paths: overlays/production/kustomization.yaml
          body: |
            Promote the already tested image digest: ${{ inputs.digest }}
            Require the repository's validation and approval checks before merging.

๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ โ€‹

์ปดํฌ๋„ŒํŠธ ๋ฆฌ์†Œ์Šค โ€‹

๋‹ค์Œ์€ Chart 10.8.4์šฉ ์ธก์ • ์‹œ์ž‘๊ฐ’์ด๋ฉฐ ๋ณด์žฅ๋œ sizing ํ‘œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ธฐ์กด values์— ๋ณ‘ํ•ฉํ•˜๊ณ  ํ•˜๋‚˜์˜ ๊ด€๋ฆฌ ๊ฒฝ๋กœ๋กœ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. chart๊ฐ€ ์‹ค์ œ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„๊ณผ workload ์œ ํ˜•์„ ๊ฒฐ์ •ํ•˜๋ฏ€๋กœ ๋ถˆ์™„์ „ํ•œ Deployment patch๋กœ ์ƒˆ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

yaml
fullnameOverride: argocd
controller:
  replicas: 1
  resources:
    requests:
      cpu: 500m
      memory: 1Gi
    limits:
      cpu: '2'
      memory: 4Gi
server:
  replicas: 2
  resources:
    requests:
      cpu: 100m
      memory: 256Mi
    limits:
      cpu: 500m
      memory: 512Mi
repoServer:
  replicas: 2
  resources:
    requests:
      cpu: 200m
      memory: 512Mi
    limits:
      cpu: '1'
      memory: 2Gi
์ธก์ •๊ฐ’์กฐ์ • ๋ฐฉํ–ฅ
manifest ์ƒ์„ฑ ์‹œ๊ฐ„ยท๋™์‹œ ์š”์ฒญยทrepo ํฌ๊ธฐrepo-server CPU/๋ฉ”๋ชจ๋ฆฌ, parallelism, ๋””์Šคํฌ
ํด๋Ÿฌ์Šคํ„ฐ๋ณ„ ๋ฆฌ์†Œ์Šค ์ˆ˜ยทwatch/cache ๋ฉ”๋ชจ๋ฆฌcontroller ๋ฉ”๋ชจ๋ฆฌ, ํด๋Ÿฌ์Šคํ„ฐ ๋ถ„์‚ฐ
reconciliation/sync ํ ๋Œ€๊ธฐยทAPI throttlingprocessor ์ˆ˜์™€ ๋Œ€์ƒ API ์šฉ๋Ÿ‰์„ ํ•จ๊ป˜ ๊ฒ€ํ† 
CPU throttlingยทOOMยทPod ์žฌ์‹œ์ž‘requests/limits์™€ ๋™์‹œ ์‹คํ–‰ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ์กฐ์ •

Application ๊ฐœ์ˆ˜๋งŒ์œผ๋กœ 100/500๊ฐœ๋ถ€ํ„ฐ ์ƒค๋”ฉ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Redis๋Š” ์žฌ์ƒ์„ฑ ๊ฐ€๋Šฅํ•œ ์บ์‹œ์ง€๋งŒ ์žฅ์•  ์‹œ ์žฌ๊ณ„์‚ฐ ๋ถ€ํ•˜์™€ ์ง€์—ฐ์€ ์ธก์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. HA ๊ตฌ์„ฑ์€ ์„ค์น˜ ์žฅ์˜ ๋…ธ๋“œ/anti-affinity/PDB ์ „์ œ๊นŒ์ง€ ํ•จ๊ป˜ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌด์กฐ๊ฑด ์—ฌ๋Ÿฌ ๊ฐœ ๋ณต์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„ ํƒ์  repo-server HPA โ€‹

Metrics Server์™€ CPU requests๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. HPA๋ฅผ ์„ ํƒํ•˜๋ฉด replica ์ˆ˜๋Š” HPA๊ฐ€ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. CPU ๊ธฐ๋ฐ˜ ํ™•์žฅ์€ manifest ์ƒ์„ฑ ๋ณ‘๋ชฉ ์ „์ฒด๋ฅผ ์„ค๋ช…ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ์‚ฌ์šฉ๋Ÿ‰๋งŒ์œผ๋กœ ํ™•์žฅํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ๋ณต์ œ๊ฐ€ ์ง€์†๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

yaml
repoServer:
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 5
    targetCPUUtilizationPercentage: 70
    targetMemoryUtilizationPercentage: null
    behavior:
      scaleDown:
        stabilizationWindowSeconds: 300

์„ฑ๋Šฅ ์ตœ์ ํ™” โ€‹

์„ค์ • ์œ„์น˜์™€ ์˜๋ฏธ โ€‹

์•„๋ž˜๋„ ๊ธฐ์กด Helm values์— ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค. configs.params๋Š” argocd-cmd-params-cm, configs.cm์€ argocd-cm์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋ช…๋ นํ–‰/ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์ฝ๋Š” ๊ฐ’์€ ํ•ด๋‹น controller/repo-server/server rollout์ด ํ•„์š”ํ•˜๋ฉฐ ์‹ค์ œ ๋ Œ๋”๋ง๋œ Pod์™€ ๋กœ๊ทธ์—์„œ ์ ์šฉ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

yaml
configs:
  params:
    controller.status.processors: '20'
    controller.operation.processors: '10'
    controller.repo.server.timeout.seconds: '180'
    server.repo.server.timeout.seconds: '180'
    reposerver.parallelism.limit: '2'
    reposerver.repo.cache.expiration: 24h
    reposerver.git.request.timeout: 30s
    reposerver.git.lsremote.parallelism.limit: '5'
  cm:
    timeout.reconciliation: 300s
    timeout.reconciliation.jitter: 60s
    application.resourceTrackingMethod: annotation
repoServer:
  env:
  - name: ARGOCD_EXEC_TIMEOUT
    value: 2m
  • status/operation.processors๋Š” ๋™์‹œ ์ฒ˜๋ฆฌ ์ˆ˜์ด๋ฉฐ ์ฃผ๊ธฐ ์„ค์ •์ด ์•„๋‹™๋‹ˆ๋‹ค. ์œ„ 20/10์€ ๊ธฐ๋ณธ ๋™์‹œ ์ฒ˜๋ฆฌ ์ˆ˜์ž…๋‹ˆ๋‹ค.
  • repo-server RPC timeout(180์ดˆ), ๋„๊ตฌ ์‹คํ–‰ timeout(2๋ถ„), Git ์š”์ฒญ timeout(30์ดˆ)์€ ๋‹ค๋ฅธ ์ œํ•œ์ž…๋‹ˆ๋‹ค. ๋ฌด์กฐ๊ฑด ๋Š˜๋ฆฌ๊ธฐ ์ „์— ๋А๋ฆฐ ๋‹จ๊ณ„์™€ ์ทจ์†Œ ๋™์ž‘์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • reposerver.parallelism.limit๋Š” ์บ์‹œ TTL์ด ์•„๋‹ˆ๋ผ ๋™์‹œ manifest ์ƒ์„ฑ ์ œํ•œ์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌยทํ”„๋กœ์„ธ์Šค ํ•œ๋„์™€ ํ•จ๊ป˜ ๋ถ€ํ•˜ ์‹œํ—˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ periodic reconciliation์€ 120์ดˆ + ์ตœ๋Œ€ 60์ดˆ jitter์ž…๋‹ˆ๋‹ค. ์˜ˆ์ œ์˜ 300์ดˆ + 60์ดˆ๋Š” 5โ€“6๋ถ„์ด๋ฉฐ Git webhook ๋“ฑ ๋‹ค๋ฅธ refresh ์›์ธ์€ ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค.
  • application.resourceTrackingMethod๋Š” ๋ฆฌ์†Œ์Šค ์ถ”์  ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ƒˆ๋กœ๊ณ ์นจ ๊ฐ„๊ฒฉ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ธฐ์กด tracking ๋ฐฉ์‹์˜ ๋ณ€๊ฒฝ์€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์˜ํ–ฅ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ๋Œ€์ƒ ํด๋Ÿฌ์Šคํ„ฐ์˜ ์ƒค๋”ฉ โ€‹

๊ธฐ๋ณธ ์ƒค๋”ฉ ๋‹จ์œ„๋Š” ๋Œ€์ƒ ํด๋Ÿฌ์Šคํ„ฐ์ž…๋‹ˆ๋‹ค. ํ•œ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋งŽ์€ Application์ด replica ์ˆ˜๋งŒ ๋Š˜๋ฆฐ๋‹ค๊ณ  ๊ณ ๋ฅด๊ฒŒ ๋ถ„์‚ฐ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์•„๋ž˜ Chart ๊ฐ’์€ StatefulSet replicas์™€ ARGOCD_CONTROLLER_REPLICAS๋ฅผ ํ•จ๊ป˜ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. round-robin/consistent-hashing๊ณผ dynamic cluster distribution์€ ์ด ๋ฒ„์ „์—์„œ ์‹คํ—˜์ ์ด๋ฏ€๋กœ ์ผ๋ฐ˜ ์šด์˜ ๊ธฐ๋ณธ๊ฐ’์ฒ˜๋Ÿผ ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

yaml
controller:
  replicas: 3
configs:
  params:
    controller.sharding.algorithm: legacy

Application ๊ฒฝ๊ณ„์™€ HPA โ€‹

ํฐ Application์€ ์†Œ์œ ๊ถŒยท์ˆ˜๋ช…์ฃผ๊ธฐ๊ฐ€ ๋ถ„๋ฆฌ๋˜๋Š” ๊ฒฝ๊ณ„๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค. ์ž„์˜๋กœ ๋ฆฌ์†Œ์Šค ์ข…๋ฅ˜๋ณ„๋กœ ์ชผ๊ฐœ๋ฉด Secret/Service/Deployment ์˜์กด์„ฑ๊ณผ ์‚ญ์ œ ์ˆœ์„œ๊ฐ€ ๋ณต์žกํ•ด์ง‘๋‹ˆ๋‹ค. App of Apps์˜ child Application๋“ค์ด ํ•˜๋‚˜์˜ ์›์ž์  ๋ฐฐํฌ๊ฐ€ ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” workloads ํ”„๋กœ์ ํŠธยทnamespaceยทHPA๊ฐ€ ์ด๋ฏธ ์žˆ๊ณ , HPA๊ฐ€ my-app Deployment์˜ replicas๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. Git์—์„œ replicas๋ฅผ ์ƒ๋žตํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ด๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ฐจ์ด/์ ์šฉ ๋ฌด์‹œ๋ฅผ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์—๋งŒ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ignoreDifferences.name์€ Kustomize prefix/suffix๊นŒ์ง€ ์ ์šฉ๋œ ์ตœ์ข… ์ด๋ฆ„์— ๋งž์ถฅ๋‹ˆ๋‹ค. ApplyOutOfSyncOnly๋Š” apply ๋Œ€์ƒ ์ตœ์ ํ™”์ด๋ฉฐ sync ์ฃผ๊ธฐ ๋ณ€๊ฒฝ์ด ์•„๋‹™๋‹ˆ๋‹ค.

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: large-app
  namespace: argocd
spec:
  project: workloads
  source:
    repoURL: https://github.com/myorg/gitops.git
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app-production
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
    - ApplyOutOfSyncOnly=true
    - RespectIgnoreDifferences=true
  ignoreDifferences:
  - group: apps
    kind: Deployment
    name: my-app
    namespace: my-app-production
    jsonPointers:
    - /spec/replicas

์žฌํ•ด ๋ณต๊ตฌ โ€‹

๋ฐฑ์—… ๋ฒ”์œ„ โ€‹

argocd admin export๋Š” Application/AppProject/ApplicationSet, ํ•ต์‹ฌ ConfigMap 4์ข…๊ณผ ์„ ํƒ๋œ Argo CD Secret์„ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ „์ฒด namespace ๋ฐฑ์—…์ด ์•„๋‹™๋‹ˆ๋‹ค. argocd-cmd-params-cm, Notifications/CMP ์„ค์ •, ๋ณ„๋„ TLS/์•Œ๋ฆผ Secret ๋“ฑ์ด ์ž๋™์œผ๋กœ ๋ชจ๋‘ ํฌํ•จ๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Application/Set์˜ ์ถ”๊ฐ€ namespace ์„ค์ •๋„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋™์ผ ๋ฒ„์ „ CLI, ํ™•์ธ๋œ kubecontext, age ๋„๊ตฌ์™€ ์กฐ์ง์˜ ๊ณต๊ฐœ ์ˆ˜์‹ ์ž ํ‚ค๋ฅผ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธํ‚ค๋Š” ๋ฐฑ์—…๊ณผ ๋ณ„๋„๋กœ ๋ณด๊ด€ํ•˜๊ณ  ๋ณตํ˜ธํ™”/๋ณต๊ตฌ๋ฅผ ์ •๊ธฐ์ ์œผ๋กœ ์‹œํ—˜ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ๋ณด์™„ snapshot์€ namespace์˜ ๋ชจ๋“  ConfigMap/Secret์„ ์•”ํ˜ธํ™”ํ•˜๋ฏ€๋กœ Helm release Secret๊นŒ์ง€ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณต๊ตฌ ์‹œ ํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ์„ ๋ณ„ํ•˜๋ฉฐ ์ด snapshot ์ „์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ applyํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

bash
#!/usr/bin/env bash
set -euo pipefail
umask 077
: "${ARGO_BACKUP_RECIPIENT:?Set the approved age public recipient}"
ARGO_BACKUP_DIR="./argocd-backup-$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -m 700 "$ARGO_BACKUP_DIR"
kubectl config current-context
kubectl get configmap argocd-cm -n argocd -o name

argocd admin export -n argocd |
  age --recipient "$ARGO_BACKUP_RECIPIENT" --output "$ARGO_BACKUP_DIR/data.yaml.age.tmp"
mv "$ARGO_BACKUP_DIR/data.yaml.age.tmp" "$ARGO_BACKUP_DIR/data.yaml.age"

# Supplement: all namespace ConfigMaps/Secrets, including custom configuration.
kubectl get configmaps,secrets -n argocd -o yaml |
  age --recipient "$ARGO_BACKUP_RECIPIENT" --output "$ARGO_BACKUP_DIR/namespace-config.yaml.age.tmp"
mv "$ARGO_BACKUP_DIR/namespace-config.yaml.age.tmp" "$ARGO_BACKUP_DIR/namespace-config.yaml.age"

๋ณ„๋„๋กœ ๋ฒ„์ „ ๊ณ ์ •๋œ ์„ค์น˜ manifest/Helm values, CRD์™€ ํ™•์žฅ ์ปจํŠธ๋กค๋Ÿฌ, ์™ธ๋ถ€ Secret/KMSยทSSOยทDNSยท์ธ์ฆ์„œ ๋ณต๊ตฌ ์ ˆ์ฐจ๋ฅผ ๋ณด๊ด€ํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค/PV ๋ฐฑ์—…์€ Argo CD ๊ตฌ์„ฑ ๋ฐฑ์—…๊ณผ ๋ณ„๋„์ž…๋‹ˆ๋‹ค. ๋ฐฑ์—… ์ฃผ๊ธฐยท๋ณด์กด ๊ธฐ๊ฐ„์€ RPO/RTO์™€ ์ ‘๊ทผ ์ •์ฑ…์œผ๋กœ ์ •ํ•ฉ๋‹ˆ๋‹ค.

Velero ๊ตฌ์„ฑ ๋ฐฑ์—… ๋Œ€์•ˆ โ€‹

์ด๋ฏธ ์„ค์น˜๋œ Velero์™€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ aws-s3 BackupStorageLocation์„ ์ „์ œ๋กœ ํ•˜๋Š” Schedule์ž…๋‹ˆ๋‹ค. ์ ์šฉ ์‹œ๊ฐ„๋Œ€์™€ ์•”ํ˜ธํ™”ยท์ ‘๊ทผ ์ œ์–ด๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž Application์— ์—†๋Š” app.kubernetes.io/part-of ๋ ˆ์ด๋ธ”๋กœ ํ•„ํ„ฐ๋งํ•˜๋ฉด ๋ฐฑ์—…์—์„œ ๋น ์งˆ ์ˆ˜ ์žˆ์–ด ํ•ด๋‹น ํ•„ํ„ฐ๋ฅผ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. CRD/์„ค์น˜ ๋ฆฌ์†Œ์Šค/PV ๋ณต๊ตฌ๋ฅผ ํฌํ•จํ•˜๋Š” ์ „์ฒด DR ์ž‘์—…์€ ๋ณ„๋„์ž…๋‹ˆ๋‹ค.

yaml
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: argocd-config-backup
  namespace: velero
spec:
  schedule: 0 2 * * *
  template:
    includedNamespaces:
    - argocd
    includedResources:
    - applications.argoproj.io
    - applicationsets.argoproj.io
    - appprojects.argoproj.io
    - secrets
    - configmaps
    includeClusterResources: false
    storageLocation: aws-s3
    ttl: 720h0m0s

๋‹จ๊ณ„์  ๋ณต๊ตฌ โ€‹

๋จผ์ € ๊ธฐ์กด๊ณผ ๊ฐ™์€ ๋ฒ„์ „/๋ฐฉ์‹์œผ๋กœ ๊ฒฉ๋ฆฌ๋œ ๋ณต๊ตฌ์šฉ Argo CD๋ฅผ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ์›๋ณธ๊ณผ ๋ณต๊ตฌ๋ณธ์ด ๊ฐ™์€ ์›Œํฌ๋กœ๋“œ๋ฅผ ๋™์‹œ์— ์ˆ˜์ •ํ•˜์ง€ ์•Š๋„๋ก ๋‹จ์ผ ๊ด€๋ฆฌ ์ฃผ์ฒด๋ฅผ ์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ StatefulSet ๊ตฌ์„ฑ์—์„œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ Application ๋ฐ ApplicationSet controller๋ฅผ ๋ฉˆ์ถ˜ ์ƒํƒœ๋กœ import ๊ณ„ํš์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. dynamic distribution์ด๋ฉด ์‹ค์ œ Deployment ์œ ํ˜•์— ๋งž๊ฒŒ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

bash
set -euo pipefail
umask 077
: "${ARGO_BACKUP_FILE:?Set the encrypted data.yaml.age path}"
: "${ARGO_BACKUP_IDENTITY:?Set the protected age identity file}"

# Fresh, isolated recovery installation: default StatefulSet controller layout.
kubectl config current-context
kubectl scale statefulset/argocd-application-controller -n argocd --replicas=0
kubectl scale deployment/argocd-applicationset-controller -n argocd --replicas=0

ARGO_RESTORE_DIR="$(mktemp -d)"
trap 'rm -rf "$ARGO_RESTORE_DIR"' EXIT
age --decrypt --identity "$ARGO_BACKUP_IDENTITY" "$ARGO_BACKUP_FILE" \
  > "$ARGO_RESTORE_DIR/data.yaml"
argocd admin import -n argocd --dry-run "$ARGO_RESTORE_DIR/data.yaml"
# Keep controllers stopped while reviewing the recovery copy and destinations.

๊ณ„ํš์„ ํ™•์ธํ•œ ๋’ค ๊ฐ™์€ shell์˜ ๋ณดํ˜ธ๋œ ๋ณต๊ตฌ ํŒŒ์ผ์„ ๊ฒ€ํ† ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์ƒ cluster/namespace, repository/cluster ์ž๊ฒฉ ์ฆ๋ช…, ์‚ญ์ œ finalizer, ์ž๋™ sync ์ •์ฑ… ๋ฐ ์ €์žฅ๋œ operation์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ž๋™ sync๋ฅผ ๋ณด๋ฅ˜ํ•˜๋ ค๋ฉด Application๊ณผ ApplicationSet template์˜ ์ •์ฑ…์„ ํ•จ๊ป˜ ๋ฐ”๊พธ๊ณ  ์ง„ํ–‰ ์ค‘ operation์„ ์ œ๊ฑฐํ•œ ๋ณต๊ตฌ ์‚ฌ๋ณธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด controller๋ฅผ ์žฌ๊ฐœํ•˜๊ธฐ ์ „์— Helm/Git ์›๋ณธ์ด ์ด ๋ณด๋ฅ˜ ์„ค์ •์„ ๋˜๋Œ๋ฆฌ๋Š”์ง€๋„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

bash
argocd admin import -n argocd "$ARGO_RESTORE_DIR/data.yaml"

ํ•„์š”ํ•œ ๋ณด์™„ ConfigMap/Secret๊ณผ ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ๋ณต๊ตฌํ•˜๊ณ , ๊ฒ€ํ† ๋œ ์„ค์น˜ ๊ฐ’์˜ replica ์ˆ˜๋กœ controller๋ฅผ ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ๋Œ€ํ‘œ Application์˜ diff/health๋ฅผ ํ™•์ธํ•œ ํ›„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋ฐฐํฌ๋ฅผ ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ์•ฑ ๊ฐ•์ œ sync, import --prune, namespace ์‚ญ์ œ๋Š” ๊ธฐ๋ณธ ๋ณต๊ตฌ ์ ˆ์ฐจ์— ๋„ฃ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—…๊ทธ๋ ˆ์ด๋“œ ์ „๋žต โ€‹

๋ฒ„์ „๊ณผ ์„ค์น˜ ์ฃผ์ฒด โ€‹

์•„๋ž˜๋Š” 3.5.x patch ์ˆ˜์ค€์—์„œ 3.5.4๋กœ ๊ฐ€๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. 2.x/์ด์ „ minor์—์„œ ๋ฐ”๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ „ํ™˜๋œ๋‹ค๋Š” ๋œป์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ง€๋‚˜๊ฐ€๋Š” ๋ชจ๋“  minor/major migration note, ์ง€์› Kubernetes ์กฐํ•ฉ, CRDยทRBACยทSSOยทCMP ๋ณ€๊ฒฝ์„ ๊ฒ€ํ† ํ•˜๊ณ  ๋น„ํ”„๋กœ๋•์…˜์—์„œ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. manifest/Helm/GitOps ์ค‘ ๊ธฐ์กด ๊ด€๋ฆฌ ๋ฐฉ์‹์„ ์œ ์ง€ํ•˜๋ฉฐ EKS ๊ด€๋ฆฌํ˜• Argo CD capability์— ์ด ์ ˆ์ฐจ๋ฅผ ๊ฒน์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

bash
# Example: reviewed 3.5.x patch upgrade to 3.5.4, manifest-managed non-HA install.
kubectl config current-context
argocd version
kubectl apply --server-side -n argocd \
  -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.4/manifests/install.yaml
kubectl rollout status deployment/argocd-server -n argocd --timeout=5m
kubectl rollout status deployment/argocd-repo-server -n argocd --timeout=5m
kubectl rollout status statefulset/argocd-application-controller -n argocd --timeout=5m
kubectl rollout status deployment/argocd-applicationset-controller -n argocd --timeout=5m
kubectl rollout status deployment/argocd-notifications-controller -n argocd --timeout=5m
argocd version
argocd app list

HA manifest ์„ค์น˜๋Š” manifests/ha/install.yaml์„ ์‚ฌ์šฉํ•˜๊ณ , ์‚ฌ์šฉ์ž overlay๋Š” ๊ณ ์ •ํ•œ base๋ฅผ ๊ฐฑ์‹ ํ•ด ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. CRD ํฌ๊ธฐ ๋•Œ๋ฌธ์— server-side apply๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. field ownership ์ถฉ๋Œ์„ ๋จผ์ € ๊ฒ€ํ† ํ•˜๋ฉฐ, ๊ณต์‹ ์—…๊ทธ๋ ˆ์ด๋“œ ์•ˆ๋‚ด์˜ --force-conflicts๋Š” ์˜๋„ํ•œ ownership ์ด์ „์—๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Pod rollout ์„ฑ๊ณต๋งŒ์œผ๋กœ migrationยทSSOยทdiffยท๋™๊ธฐํ™” ๊ฒ€์ฆ์ด ์™„๋ฃŒ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

Helm ์„ค์น˜์˜ ๋Œ€์•ˆ ์ ˆ์ฐจ โ€‹

๊ฒ€ํ† ํ•œ chart 10.8.4๋Š” Argo CD v3.5.2๋ฅผ ๋ฐฐํฌํ•˜๋ฏ€๋กœ ์ด Helm ์ ˆ์ฐจ๋กœ๋Š” ์œ„์˜ ํŒจ์น˜ 3.5.4์— ๋„๋‹ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Argo CD 3.5.4๋Š” chart 10.9.7๋ถ€ํ„ฐ ํฌํ•จ๋˜๋ฉฐ, ์ด ๋ฌธ์„œ๋Š” ๊ทธ chart minor ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฒ€ํ† ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

bash
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update argo
helm upgrade argocd argo/argo-cd --version 10.8.4 \
  --namespace argocd -f reviewed-values.yaml --dry-run=server --hide-secret
# After reviewing the dry run and the version-specific migration notes:
helm upgrade argocd argo/argo-cd --version 10.8.4 \
  --namespace argocd -f reviewed-values.yaml --wait --timeout 10m

--hide-secret์€ dry-run ์ถœ๋ ฅ์˜ Secret ๋…ธ์ถœ์„ ์ค„์ž…๋‹ˆ๋‹ค. ๋ฏผ๊ฐํ•œ ๊ฐ’์ด ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค์— ๋“ค์–ด ์žˆ์ง€ ์•Š์€์ง€๋„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. CRD/์ €์žฅ ๋ฐ์ดํ„ฐ/์™ธ๋ถ€ ์—ฐ๋™ ๋ณ€๊ฒฝ์€ ๋‹จ์ˆœ ์ด๋ฏธ์ง€ rollback๋งŒ์œผ๋กœ ๋ณต๊ตฌ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฒ€์ฆ๋œ ๋ฐฑ์—…๊ณผ ๋ณต๊ตฌ ๊ณ„ํš์„ ํ•จ๊ป˜ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.

๋ณ‘ํ–‰ ๊ฒ€์ฆ์˜ ์ œ์•ฝ โ€‹

๊ฐ™์€ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋‹ค๋ฅธ namespace๋Š” CRD์™€ ์ผ๋ถ€ cluster-scoped ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. namespace๋งŒ ๋ฐ”๊พธ์–ด ์„ค์น˜ํ•˜๋ฉด ClusterRoleBinding ๋Œ€์ƒ๋„ ์ž๋™ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Kubernetes์—๋Š” kubectl rename namespace ๋ช…๋ น์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ณ„๋„ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์ƒˆ ๋ฒ„์ „์„ ๊ฒ€์ฆํ•˜๊ณ , ์ž๊ฒฉ ์ฆ๋ช…ยทtracking/instance IDยทํ™œ์„ฑ controllerยทํŠธ๋ž˜ํ”ฝ์„ ๋ช…์‹œ์ ์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์„ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค. namespace ์‚ญ์ œ๋กœ ์ด์ „ ์„ค์น˜๋ฅผ ์ •๋ฆฌํ•˜๋ฉด Application finalizer๋ฅผ ํ†ตํ•œ ์›Œํฌ๋กœ๋“œ ์‚ญ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ ํ•ด๊ฒฐ โ€‹

Sync์™€ ์ฐจ์ด ํ™•์ธ โ€‹

bash
argocd app get my-app
argocd app diff my-app
argocd app history my-app
argocd app resources my-app
kubectl describe application my-app -n argocd
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller --tail=100

# Re-check desired state after identifying the cause; this does not apply resources.
argocd app get my-app --refresh
# Invalidates the cached target manifests for this Application; use sparingly.
argocd app get my-app --hard-refresh

--force๋Š” ์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜ ํ•ด๊ฒฐ ์˜ต์…˜์ด ์•„๋‹ˆ๋ฉฐ ๋ฆฌ์†Œ์Šค ์žฌ์ƒ์„ฑ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. hard refresh๋„ apply/rollback์€ ์•„๋‹ˆ์ง€๋งŒ manifest ์žฌ์ƒ์„ฑ ๋ถ€ํ•˜๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๋ชจ๋“  ์•ฑ์— ๋ฐ˜๋ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ €์žฅ์†Œ์™€ Webhook โ€‹

bash
argocd repo list
argocd repo get https://github.com/myorg/myrepo.git
kubectl logs -n argocd deployment/argocd-repo-server --tail=100
kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository
kubectl logs -n argocd deployment/argocd-server --tail=100 | grep -i webhook

TLS/SSH ์‹ ๋ขฐ, ์ž๊ฒฉ ์ฆ๋ช… ๋ฒ”์œ„, DNSยทegress, provider webhook ์„œ๋ช…ยทURLยท์ด๋ฒคํŠธ delivery ๊ธฐ๋ก์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ €์žฅ์†Œ ๋ชฉ๋ก์˜ Secret ๊ฐ’์„ ์ถœ๋ ฅํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. argocd repo update --repo-cache-expiration์€ ์˜ฌ๋ฐ”๋ฅธ cache ์„ค์ • ๋ช…๋ น์ด ์•„๋‹™๋‹ˆ๋‹ค.

OOM๊ณผ ๋А๋ฆฐ ์ฒ˜๋ฆฌ โ€‹

bash
kubectl top pods -n argocd
kubectl get pods -n argocd
kubectl describe pods -n argocd -l app.kubernetes.io/name=argocd-repo-server
argocd app get my-app -o json |
  jq '.status.operationState | {phase, startedAt, finishedAt}'

์ข…๋ฃŒ ์›์ธ์ด OOMKilled์ธ์ง€, CPU throttlingยทrepo clone ๋””์Šคํฌยทmanifest ํฌ๊ธฐยทGit timeoutยทAPI throttling์ด ์›์ธ์ธ์ง€ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์œ„ Helm values์—์„œ ๋ฆฌ์†Œ์Šค/๋™์‹œ ์‹คํ–‰ ์ˆ˜๋ฅผ ์กฐ์ •ํ•˜๊ณ  Git/Helm ๊ฒฝ๋กœ๋กœ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. repo-server Pod ์ „์ฒด ์‚ญ์ œ๋Š” Redis์˜ manifest cache๋ฅผ ์ง€์šฐ๋Š” ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ฉฐ ์ผ์‹œ์  ์ฒ˜๋ฆฌ ์ค‘๋‹จ๊ณผ clone ๋ถ€ํ•˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ํ™•์ธ ๋ช…๋ น โ€‹

bash
argocd app manifests my-app
argocd app list -o wide
argocd cluster list
argocd cluster get https://my-target-cluster.example.com
kubectl logs -n argocd statefulset/argocd-application-controller --tail=100
kubectl logs -n argocd deployment/argocd-server --tail=100
kubectl logs -n argocd deployment/argocd-repo-server --tail=100

manifest ์ถœ๋ ฅ์—๋Š” ์ƒ์„ฑ๋œ Secret์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ณต์œ  ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ controller๋Š” StatefulSet์ด๋ฉฐ dynamic distribution ๊ตฌ์„ฑ์—์„œ๋Š” ์‹ค์ œ Deployment๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์ž„์‹œ debug logging์€ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์— ํ•œ์ •ํ•˜๊ณ  rollout/ํ•ด์ œ ์ ˆ์ฐจ๋ฅผ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

EKS ๋ชจ๋ฒ” ์‚ฌ๋ก€ โ€‹

AWS ์ž๊ฒฉ ์ฆ๋ช… โ€‹

ServiceAccount์— role ARN ํ•˜๋‚˜๋ฅผ ์ ๋Š” ๊ฒƒ์œผ๋กœ ๋Œ€์ƒ EKS ์ ‘๊ทผ์ด ์™„์„ฑ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. controller/server์˜ EKS ์ธ์ฆ, ๋Œ€์ƒ role assume ๊ถŒํ•œ, EKS access entry ๋˜๋Š” ๊ธฐ์กด ์ธ์ฆ ๋งคํ•‘, Kubernetes RBAC๋ฅผ ํ•จ๊ป˜ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. repo-server๋Š” S3/OCI/CMP ๋“ฑ ์‹ค์ œ AWS ์ ‘๊ทผ์ด ํ•„์š”ํ•  ๋•Œ๋งŒ ๋ณ„๋„ ์ตœ์†Œ ๊ถŒํ•œ ์—ญํ• ์„ ์ค๋‹ˆ๋‹ค. IRSA OIDC trust ๋˜๋Š” Pod Identity association๋„ ํ•„์š”ํ•˜๋ฉฐ, Pod ์ด๋ฏธ์ง€ pull ๊ถŒํ•œ๊ณผ ๋™์ผ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์„ค์น˜ ์žฅ์˜ EKS ํ†ตํ•ฉ์„ ๊ธฐ์ค€์œผ๋กœ ์‹ค์ œ ๋Œ€์ƒ๊ณผ ์„œ๋น„์Šค ๊ณ„์ •์„ ๋งž์ถฅ๋‹ˆ๋‹ค.

๋‚ด๋ถ€ ALB์™€ HTTPS โ€‹

AWS Load Balancer Controller, ํ•ด๋‹น VPC์—์„œ์˜ ๊ด€๋ฆฌ์ž ์ ‘๊ทผ, ์˜ฌ๋ฐ”๋ฅธ DNS/ACM ์ธ์ฆ์„œ, ์ œํ•œ๋œ ๋ณด์•ˆ ๊ทธ๋ฃน, SSO๊ฐ€ ์„ ํ–‰ ์กฐ๊ฑด์ž…๋‹ˆ๋‹ค. ์ธ์ฆ์„œ ARN๊ณผ hostname์„ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. server.insecure=false์˜ HTTPS backend์ด๋ฉฐ ๋‹จ์ผ HTTP target group์„ ์“ฐ๋Š” CLI๋Š” --grpc-web์œผ๋กœ ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd
  namespace: argocd
  annotations:
    alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/backend-protocol: HTTPS
    alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS
    alb.ingress.kubernetes.io/healthcheck-path: /healthz
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:123456789012:certificate/REPLACE_WITH_CERTIFICATE_ID
    alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
spec:
  ingressClassName: alb
  rules:
  - host: argocd.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 443

WAF๋Š” ๊ฐ™์€ ๋ฆฌ์ „์˜ ๊ฒ€ํ† ๋œ regional Web ACL ARN์„ ๋ณ„๋„ annotation์œผ๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ALB access log bucket ์ •์ฑ…๊ณผ ๋Œ€์ƒ ๋ฆฌ์ „๋„ ๋งž์ถฅ๋‹ˆ๋‹ค. Shield Advanced์ฒ˜๋Ÿผ ๋ณ„๋„ ๊ฐ€์ž…/๋น„์šฉ์ด ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๋ฌด์กฐ๊ฑด ์ผœ๋Š” ๊ธฐ๋ณธ ์˜ˆ์ œ๋กœ ๋‘์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

EKS ๋ฒ„์ „ ์—…๊ทธ๋ ˆ์ด๋“œ โ€‹

ํ˜„์žฌ/๋ชฉํ‘œ EKS์™€ Argo CD์˜ ํ…Œ์ŠคํŠธ๋œ ์กฐํ•ฉ, add-onยทCRDยทnodeยทKubelet ํ˜ธํ™˜์„ฑ ๋ฐ ์ œ๊ฑฐ API๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. EKS control plane์€ ํ•œ minor์”ฉ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋ฉฐ node/add-on ๊ฐฑ์‹ ์€ ๋ณ„๋„์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ฒ„์ „ ์—…๊ทธ๋ ˆ์ด๋“œ๋งŒ์œผ๋กœ API endpoint๋ฅผ ์ƒˆ ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ€ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ ๊ต์ฒด๋ผ๋ฉด endpoint/CA/์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

์ž๋™ sync๋ฅผ ๋ณด๋ฅ˜ํ•  ๊ฒฝ์šฐ ์›๋ž˜ ์„ค์ •์„ ๊ธฐ๋กํ•˜๊ณ  ์ด๋ฅผ ์†Œ์œ ํ•œ Git/ApplicationSet์—์„œ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. child Application์˜ CLI ์„ค์ •๋งŒ ๋ฐ”๊พธ๋ฉด ์ƒ์œ„ controller๊ฐ€ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—…๊ทธ๋ ˆ์ด๋“œ ํ›„ ์—ฐ๊ฒฐยทdiffยท์ƒ˜ํ”Œ ๋™๊ธฐํ™”๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ์›๋ž˜ prune/selfHeal/automated ์ •์ฑ…์„ ๋ณต๊ตฌํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ž˜๋œ 1.29๋ฅผ ๊ณ ์ •ํ•œ ๋ช…๋ น์ด๋‚˜ ๋ฌด์กฐ๊ฑด automated๋กœ ์žฌ์„ค์ •ํ•˜๋Š” ์ ˆ์ฐจ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ โ€‹

  • [ ] SSO/RBAC/TLS์™€ ๋ณต๊ตฌ์šฉ ์ ‘๊ทผ์„ ๊ฒ€์ฆํ•œ ๋’ค ๊ธฐ๋ณธ admin ๋น„ํ™œ์„ฑํ™”
  • [ ] Secret ์•”ํ˜ธํ™”ยท์™ธ๋ถ€ ์ €์žฅ, repository/cluster ์ž๊ฒฉ ์ฆ๋ช… ๋ฒ”์œ„ ํ™•์ธ
  • [ ] ์‹ค์ œ ๋ถ€ํ•˜ ๊ธฐ๋ฐ˜ requests/limitsยท๋™์‹œ ์ฒ˜๋ฆฌยท์ƒค๋”ฉ ํ•„์š”์„ฑ ๊ฒ€์ฆ
  • [ ] HA ๋…ธ๋“œ/anti-affinity/PDB, ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์˜ replica/leader election ํ™•์ธ
  • [ ] metricsยทServiceMonitor ์„ ํƒ ์กฐ๊ฑดยท์•Œ๋ฆผ ์ˆ˜์‹  ๊ฒ€์ฆ, JSON ๋กœ๊ทธ์™€ Kubernetes audit/event ์ˆ˜์ง‘
  • [ ] AppProject source/destinationยทsync windowยท์Šน๊ฒฉ PR ์ •์ฑ… ์ ์šฉ
  • [ ] ์•”ํ˜ธํ™”๋œ ๋ฐฑ์—… ๋ณตํ˜ธํ™”, ๋ˆ„๋ฝ ์„ค์ • ์ ๊ฒ€, ๋‹จ์ผ ๊ด€๋ฆฌ ์ฃผ์ฒด๋กœ DR ์—ฐ์Šต
  • [ ] ๋ฒ„์ „๋ณ„ ์—…๊ทธ๋ ˆ์ด๋“œยท์žฅ์•  ๋Œ€์‘ยท์›๋ž˜ ์„ค์ • ๋ณต์› runbook ์œ ์ง€

๋‹ค์Œ ๋‹จ๊ณ„ โ€‹

์ฐธ๊ณ  ์ž๋ฃŒ โ€‹

ํ€ด์ฆˆ โ€‹

๋ชจ๋ฒ” ์‚ฌ๋ก€ ํ€ด์ฆˆ์—์„œ ํ•™์Šต ๋‚ด์šฉ์„ ํ™•์ธํ•˜์„ธ์š”.