GitOps on K3s: ArgoCD로 완전한 홈랩 관리

발행: (2026년 6월 14일 PM 09:02 GMT+9)
8 분 소요
원문: Dev.to

출처: Dev.to
원래 wooitzik.dev에 게시되었습니다.

대부분의 쿠버네티스 튜토리얼은 kubectl apply -f 로 마무리됩니다. 배포한 것이 정상적으로 작동하고 바로 진행합니다. 세 주가 지나면 클러스터에 어떤 것이 실행 중인지, 왜 그렇게 구성되었는지, 혹은 문제가 발생했을 때 어떻게 재현할 수 있는지 알 수 없습니다.

GitOps는 이 문제를 해결합니다. ArgoCD를 사용하면 Git 저장소가 클러스터 안의 모든 것을 하나의 진리(source of truth)로 삼습니다. 수동 kubectl apply도, 쉘 히스토리에 Helm 명령어도, 구성 드리프트도 없습니다. Git에 없으면 존재하지 않습니다.

이 문서는 MetalLB, Traefik, Longhorn, cert-manager, Authelia, Vaultwarden 으로 구성된 완전한 홈랩 스택을 ArgoCD의 App-Of-Apps 패턴을 사용해 단일 Git 저장소로 관리하는 방법을 기록합니다.

GitHub에서 전체 홈랩 인프라 소스를 확인하세요 🐙

모든 것이 하나의 저장소에 있으며 kubernetes/ 디렉터리 안에 위치합니다:
homelab-infrastructure/
└── kubernetes/
├── apps/ # User- facing applications
│ ├── authelia/
│ │ ├── authelia.yml # Deployment + Service
│ │ ├── configuration.yml # ConfigMap
│ │ ├── ingress.yml
│ │ └── users_database.yml
│ └── vaultwarden/
│ ├── ingress.yml
│ └── pvc.yml
└── system/ # Cluster infrastructure
├── argocd-config/ # ArgoCD Application definitions
├── cert-manager/ # Helm chart Application
├── cert-manager-config/ # ClusterIssuer + Certificate CRDs
├── longhorn/ # Helm chart Application
├── metallb/ # Helm chart Application
├── metallb-config/ # IPAddressPool + L2Advertisement
├── traefik/ # Helm chart Application
└── test-app/ # nginx for smoke testing

apps/ 와 system/ 사이의 구분은 의도적입니다. 시스템 구성 요소는 클러스터 인프라이며, 애플리케이션이 실행되기 전에 먼저 필요합니다. 애플리케이션은 시스템 구성 요소를 의존합니다. ArgoCD의 sync waves는 이 순서를 보장합니다.

각 ArgoCD Application을 수동으로 만들 대신, App-Of-Apps 패턴을 사용합니다. 단일 루트 Application이 argocd-config/ 디렉터리를 가리키며, 여기에는 모든 애플리케이션의 Application 매니페스트가 포함되어 있습니다.

이 단일 Application이 모든 것을 부트스트랩합니다. ArgoCD가 설치되고 이 루트 Application이 생성된 후, 클러스터는 Git에서 자동으로 조립됩니다.

각 구성 요소는 Helm 차트인지 raw manifests인지에 따라 두 가지 패턴 중 하나를 따릅니다.

Pattern 1: Helm Chart from External Registry
업스트림 차트(MetalLB, Traefik, Longhorn, cert-manager)에서는 Application이 직접 Helm 저장소를 가리킵니다:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cert-manager
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://charts.jetstack.io
    targetRevision: v1.14.4
    chart: cert-manager
    helm:
      values: |
        installCRDs: true
        extraArgs:
           - --dns01-recursive-nameservers=1.1.1.1:53,8.8.8.8:53
           - --dns01-recursive-nameservers-only
  destination:
    server: https://kubernetes.default.svc
    namespace: cert-manager
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
       - CreateNamespace=true

차트 버전은 고정되어 있습니다(v1.14.4) — 시스템 구성 요소에서는 최신을 사용하지 마세요. 업그레이드 시점을 직접 제어하고, ArgoCD가 무작위로 동기화하는 것을 방지합니다.

Pattern 2: Raw Manifests from Git
Helm 차트를 확장하는 CRD 구성 및 커스텀 리소스의 경우, 별도의 Application이 Git 저장소 내 경로를 가리킵니다:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cert-manager-config
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/dwoitzik/homelab-infrastructure.git
    targetRevision: main
    path: kubernetes/system/cert-manager-config
  destination:
    server: https://kubernetes.default.svc
    namespace: cert-manager
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

이 패턴은 MetalLB, cert-manager, Longhorn에 적용됩니다. 분리가 필요한 이유는 Helm 차트에 의해 설치된 CRD가 Configuration 리소스를 적용하기 전에 존재해야 하기 때문입니다. 암묵적 순서를 갖는 두 개의 Application이 한 개의 Application 안에서 관리하는 것보다 cleaner합니다.

클러스터가 실행된 후 전체 배포 워크플로는:

  1. 리포지토리의 파일 수정
  2. git commit -m "변경 사항 설명"
  3. git push

기본적으로 ArgoCD는 저장소를 3분마다 폴링합니다. 푸시 후 3분 이내에 ArgoCD는 Git(desired state)과 클러스터(actual state) 사이의 드리프트를 감지하고 자동으로 reconciliation 합니다.

kubectl apply도, helm upgrade도, 노드에 SSH로 접속하지 않습니다. Git 히스토리는 배포 로그입니다.

한 번의 닭과 알 문제(Chicken-and-egg problem)가 있습니다: ArgoCD 자체가 존재해야 Anything을 관리할 수 있습니다. 부트스트랩 순서는:

1. ArgoCD 자체를 설치합니다 (한 번만 수행하는 수동 단계)

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

2. 루트 Application 생성 (일회성 수동 단계)

kubectl apply -f kubernetes/system/argocd-config/root-app.yaml

3. 이후 모든 것이 자동으로 진행됩니다

step 2 이후, ArgoCD는 argocd-config/ 디렉터리를 읽고 모든 하위 Application을 생성하며, 클러스터가 자동으로 조립됩니다.

이 설정의 모든 Application은 자동 동기화와 selfHeal: true를 사용합니다. 이는:

  • ArgoCD가 Git과 클러스터 사이의 드리프트를 감지하면 자동으로 변경을 적용합니다.
  • kubectl edit, 포털 클릭 등으로 클러스터 내에서 수동으로 변경이 이루어지면 ArgoCD는 몇 분 안에 이를 되돌립니다.
  • prune: true는 Git에서 삭제된 리소스를 클러스터에서도 삭제한다는 의미입니다.

이것은 의도적으로 엄격합니다. 클러스터가 Git을 진리(source of truth)로 강제하며, 수동 변경 사항은 동기화 사이클을 통과하지 못합니다.

배포 전 변경을 검토하고 싶다면 생산 워크로드에서는 수동 동기화를 전환하고 ArgoCD UI 또는 CLI를 사용해 배포를 승인합니다.

전체 홈랩(바레 메탈에서 Authelia와 Vaultwarden 실행까지)은 Git 저장소입니다. 클러스터가 소각될 경우 kubectl apply -f root-app.yaml 후 기다리면 됩니다.

엔터프라이즈 Azure 환경에서도 동일한 GitOps 원칙이 적용됩니다. Terraform을 인프라 레이어로 사용하고, AKS 위에 ArgoCD 또는 Flux가 애플리케이션 계층을 관리합니다. 규제 환경용 Azure 네트워크 기반을 구축한다면, Enterprise Terraform Blueprint는 그 아래에 있는 제로 트러스트 네트워킹 레이어를 포함합니다.

0 조회
Back to Blog

관련 글

더 보기 »

넷라 보안

🔱 Building Netra Security: Creating a Python-Based Static Application Security Testing SAST Tool As a cybersecurity student, I've always been curious about how...