
Intro
안녕하세요. 환이s입니다 👋
지난 글에서는 데이터 레이크하우스 플랫폼의
일곱 번째 스택으로 Superset을 Kubernetes 위에 구축하고
Trino와 연동해서 Delta Lake 데이터를 시각화하는 과정을 정리해 봤습니다.
이번 글에서는 여덟 번째 스택,
ArgoCD를 Kubernetes 환경에 구축하고
플랫폼 전체를 GitOps 방식으로 관리하기 위한 기반을 구성하는 과정을 정리해보려고 합니다.

지금까지
Kafka → Spark → Delta Lake → Trino → Superset 까지 구축했다면,
이제 이 모든 스택을 코드로 관리하고 자동으로 배포하는 도구가 필요합니다.
그 역할을 담당하는 것이 바로 ArgoCD입니다.
이번 글에서는
- Harbor private registry에서 이미지와 Helm Chart를 가져오는 방법
- Helm으로 ArgoCD를 설치하는 방법
- MetalLB + ingress-nginx + sslip.io로 Web UI에 접근하는 방법
- Secret과 ConfigMap으로 저장소 인증, 계정, CRD health check를 구성하는 방법
- 설치 후 검증하는 방법
까지 순서대로 확인해 보겠습니다.
1. ArgoCD 아키텍처 개요
본격적인 설치에 앞서,
이번 구성의 전체 아키텍처를 먼저 이해하는 것이 중요합니다.
[웹 접근 경로]
브라우저
↓
argocd.192.168.2.240.sslip.io
↓ (MetalLB → ingress-nginx)
argocd-server:80
[GitOps 동기화 경로]
ArgoCD (application-controller)
↓ polling (3분 간격)
Git 저장소 (Gitea)
↓ 변경 감지 시
클러스터 자동 동기화
각 컴포넌트의 역할은 아래와 같습니다.
| 컴포넌트 | 역할 |
| MetalLB | ingress-nginx에 External IP(192.168.2.240) 할당 |
| ingress-nginx | sslip.io 도메인을 ArgoCD 서버로 라우팅 |
| Harbor | Private 이미지 및 Helm Chart 레지스트리 |
| ArgoCD | Git 저장소를 기반으로 클러스터 상태를 자동 동기화 |
즉, 여기서 확인할 수 있는 핵심은
ArgoCD는 Git 저장소를 단일 진실의 원천(Single Source of Truth)으로 삼아 클러스터 상태를 코드와 항상 일치시킨다는 점입니다.
2. 설치 순서
이번 구축에서 사용하는 디렉토리 구조는 아래와 같습니다.
bootstrap/
└── 03_argocd/
├── helm/
│ ├── install.sh # 설치 스크립트
│ └── values.yaml # Helm values
└── manifests/
├── 10_ingress_argocd.yaml # Ingress 설정
├── 20_repo_secret.yaml # Git 저장소 인증 Secret
├── 30_root_app.yaml # platform-root Application
├── 35_webapps_root.yaml # webapps-root Application
├── 40_argocd_cm.yaml # ConfigMap (계정, CephCluster health check)
├── 50_argocd_tls_certs_cm.yaml # Harbor TLS 인증서 신뢰 설정
├── 60_harbor_repo_secret.yaml # Harbor OCI 레지스트리 인증 Secret
└── 70_argocd_secret.yaml # RBAC 권한 설정
설치 순서는 아래와 같습니다.
values.yaml 작성 → Helm 설치 → manifests 적용 (Ingress, Secret, ConfigMap) → 설치 후 검증
3. values.yaml 설정
먼저 공식 이미지를 기준으로 기본 설정을 살펴보겠습니다.
global:
image:
repository: quay.io/argoproj/argocd
tag: v3.3.4
redis:
image:
repository: redis
tag: 7
dex:
enabled: false # SSO 인증관련 서비스 사용여부
server:
service:
type: NodePort
nodePortHttp: 30010
configs:
params:
server.insecure: true # ArgoCD 서버를 HTTP 모드로 실행
주요 설정 포인트는 아래와 같습니다.
| 설정 | 설명 |
| dex.enabled: false | - LDAP/OAuth SSO를 쓰지 않는 경우 비활성화 |
| server.insecure: true | - ArgoCD 서버가 HTTP로 동작. - TLS 없이 Ingress에서 직접 80 포트로 수신 |
글쓴이는 외부 인터넷이 차단된 온프레미스 환경에서
Harbor private registry를 운영하는 목적 기반으로 하고 있어,
아래와 같이 이미지 경로와 Helm Chart 레지스트리를 Harbor 기준으로 변경해서 사용하고 있습니다.
global:
image:
repository: harbor.local/library/argocd/argocd
tag: v3.3.4
redis:
image:
repository: harbor.local/library/redis/redis
tag: 7
dex:
enabled: false # SSO 인증관련 서비스 사용여부
server:
service:
type: NodePort
nodePortHttp: 30010
configs:
params:
helm.oci.enabled: true # OCI 형식 Helm 차트 사용
server.insecure: true # ArgoCD 서버를 HTTP 모드로 실행
repoServer:
env:
- name: HELM_EXPERIMENTAL_OCI
value: "1"
cm:
url: http://argocd.192.168.2.240.sslip.io
repositories:
harbor-helm:
url: harbor.local/helm-chart
type: helm
name: harbor
tls:
certificates:
harbor.local: |
-----BEGIN CERTIFICATE-----
# Harbor CA 인증서 내용
-----END CERTIFICATE-----
즉, 여기서 확인할 수 있는 핵심은
Git 저장소 인증과 Harbor OCI 레지스트리 인증은 values.yaml 외에 별도 Secret으로도 등록한다는 점입니다.
이 부분은 이후 섹션에서 하나씩 확인해 보겠습니다.
4. Helm 설치 스크립트
#!/bin/bash
set -e
NAMESPACE=argocd
CHART=oci://harbor.local/helm-chart/argo-cd
VERSION=9.4.14
echo "== namespace 생성 =="
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
echo "== harbor login =="
helm registry login harbor.local
echo "== argocd 설치 =="
helm upgrade --install argocd $CHART \
--version $VERSION \
-n $NAMESPACE \
-f values.yaml
echo "== manifests 적용 =="
kubectl apply -f ../manifests/
echo "== 완료 =="
스크립트 구조 설명은 아래와 같습니다.
| 명령어 | 설명 |
| --dry-run=client -o yaml | kubectl apply -f - | namespace가 이미 존재해도 에러 없이 처리 |
| helm registry login | Harbor OCI 레지스트리 인증 |
| helm upgrade --install | 없으면 설치, 있으면 업그레이드(idempotent) |
| kubectl apply -f ../manifests/ | Secret, ConfigMap, Ingress 등 추가 리소스 일괄 적용 |
💡 참고: set -e 옵션으로 중간에 에러가 발생하면 스크립트가 즉시 종료됩니다. 설치 실패 시 어느 단계에서 멈췄는지 확인하세요.
5. Ingress 설정
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type"
spec:
ingressClassName: nginx
rules:
- host: argocd.192.168.2.240.sslip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 80
sslip.io는
별도 DNS 설정 없이 IP가 포함된 도메인을 자동으로 해당 IP로 해석해주는 서비스 입니다.
💡 참고: TLS 설정이 없기 때문에 브라우저에서 주의 요함이 표시될 수 있습니다. 내부망 구성에서는 HTTP로 운영하고, 운영 환경에서는 cert-manager로 인증서를 발급하는 것을 권장합니다.
6. Git 저장도 인증 Secret 설정
ArgoCD가 Gitea 저장소에 접근하기 위한 인증 정보를 Secret으로 등록합니다.
# 20_repo_secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: repo-data-platform
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
url: http://192.168.2.8:37000/eluna/data-platform.git
username: argocd
password: <GITEA_ACCESS_TOKEN>
즉, 여기서 확인할 수 있는 핵심은
argocd.argoproj.io/secret-type: repository 라벨을 붙이면
ArgoCD가 이 Secret을 저장소 인증 정보로 자동 인식한다는 점입니다.
7. Helm Chart 레지스트리 인증 Secret 설정
공식 Helm 레지스트리(ArtifactHub 등 공인 레지스트리)를 사용하는 경우,
별도 Secret 없이 values.yaml의 configs.repositories에 직접 등록하면 됩니다.
# values.yaml - 공식 Helm 레지스트리 사용 시
configs:
repositories:
argo-helm:
url: https://argoproj.github.io/argo-helm
type: helm
name: argo
인증이 필요한 private 레지스트리라면 Secret으로 등록합니다.
apiVersion: v1
kind: Secret
metadata:
name: repo-private-helm
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: helm
name: private-helm
url: https://your-private-helm-repo
username: <USERNAME>
password: <PASSWORD>
글쓴이는 온프레미스 환경에서 Harbor를 OCI 레지스트리로 사용하고 있어, 아래와 같이 OCI 전용 Secret으로 등록합니다.
# 60_harbor_repo_secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: repo-harbor-oci
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: helm
name: harbor-oci
url: harbor.local
enableOCI: "true"
username: admin
password: <HARBOR_PASSWORD>
| 필드 | 설명 |
| type: helm | Helm 레지스트리 타입으로 등록 |
| enableOCI: "true" | OCI 프로토콜 사용 활성화 |
| url : harbor.local | Harbor 도메인 (포트 없이 도메인만) |
즉, 여기서 확인할 수 있는 핵심은
argocd.argoproj.io/secret-type: repository 라벨을 붙이면
ArgoCD가 이 Secret을 Helm 레지스트리 인증 정보로 자동 인식한다는 점입니다.
8. TLS 인증서 신뢰 설정
Let`s Encrypt나 공인 CA에서 발급한 인증서를 사용하는 경우,
ArgoCD가 기본적으로 신뢰하므로 별도 설정이 필요하지 않습니다,.
글쓴이는 사내 self-signed CA 인증서를 사용하고 있어, ArgoCD repo-server가 Harbor에 접근할 때 인증서를 신뢰하도록 아래와 같이 등록합니다.
# 50_argocd_tls_certs_cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-tls-certs-cm
namespace: argocd
data:
harbor.local: |
-----BEGIN CERTIFICATE-----
# Harbor CA 인증서 내용
-----END CERTIFICATE-----
⚠️ 이 설정이 없으면 repo-server가 Harbor에서 Helm 차트를 pull할 때 아래와 같은 TLS 인증서 검증 오류가 발생합니다.
x509: certificate signed by unknown authority
즉, 여기서 확인할 수 있는 핵심은
공인 인증서 환경에서는 이 설정이 불필요하지만,
self-signed 인증서를 사용하는 경우 반드시 argocd-tls-certs-cm에 CA 인증서를 등록해야 한다는 점입니다.
9.ConfigMap 설정
# 40_argocd_cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# API 토큰 발급용 계정 생성
accounts.monitoring: apiKey
# Rook-Ceph CephCluster 커스텀 Health Check
resource.customizations.health.ceph.rook.io_CephCluster: |
hs = {}
if obj.status ~= nil then
local state = obj.status.state or ""
local health = ""
if obj.status.ceph ~= nil then
health = obj.status.ceph.health or ""
end
if state == "Created" and health == "HEALTH_OK" then
hs.status = "Healthy"
hs.message = "Ceph cluster is healthy"
return hs
end
hs.status = "Progressing"
hs.message = "State=" .. state .. " Health=" .. health
return hs
end
hs.status = "Progressing"
hs.message = "Waiting for CephCluster status"
return hs
주요 설정 포인트는 아래와 같습니다.
- accounts.monitoring: apiKey
- CI/CD 파이프라인 등에서 API 토큰으로 ArgoCD를 호출할 계정
- CephCluster health check
- ArgoCD는 기본적으로 CRD 리소스의 Health를 판단할 수 없습니다.
- Lua 스크립트를 통해 Rook-Ceph의 상태를 직접 파악하도록 커스터마이징 합니다.
즉, 여기서 확인할 수 있는 핵심은
ArgoCD는 기본 리소스(Deployment,Pod 등)의 Health는 자동으로 판단하지만, CephCluster 같은 CRD는 Lua 스크립트로 직접 Health 로직을 정의해줘야 한다는 점입니다.
10. RBAC 권한 설정
# 70_argocd_secret.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.csv: |
g, monitoring, role:readonly
monitoring 계정에 읽기 전용 권한을 부여합니다.
API 토큰을 발급받아 외부 시스템에서 ArgoCD 상태를 조회할 때 사용합니다.
11. 설치 후 검증
[Pod 상태 확인]
kubectl get pods -n argocd
NAME READY STATUS RESTARTS
argocd-application-controller-0 1/1 Running 0
argocd-applicationset-controller-xxx 1/1 Running 0
argocd-notifications-controller-xxx 1/1 Running 0
argocd-redis-xxx 1/1 Running 0
argocd-repo-server-xxx 1/1 Running 0
argocd-server-xxx 1/1 Running 0
[Service 확인]
kubectl get svc -n argocd
argocd-server가 NodePort(30010)로 노출되어 있는지 확인합니다.
[초기 admin 비밀번호 확인]
kubectl get secret argocd-initial-admin-secret -n argocd \
-o jsonpath="{.data.password}" | base64 -d
[Web UI 접속]
Ingress 설정 URL로 접속 후 로그인합니다.
- Username: admin
- Password: 위 명령어로 확인한 값
⚠️ 초기 비밀번호는 로그인 후 반드시 변경하세요.
Pod가 정상 상태가 되지 않는 경우 아래 명령어로 원인을 확인합니다.
# Pod 상태 상세 확인
kubectl describe pod <pod-name> -n argocd
# Pod 로그 확인
kubectl logs <pod-name> -n argocd
자주 발생하는 원인은 아래와 같습니다.
| 증상 | 원인 | 조치 |
| Pending 상태 지속 | 이미지 pull 실패 | Harbor 로그인 상태 및 이미지 경로 확인 |
| CrashLoopBackOff | values.yaml 설정 오류 | kubectl logs로 argocd-server 로그 확인 |
| repo-server TLS 오류 | Harbor 인증서 미등록 | argocd-tls-certs-cm ConfigMap 적용 여부 확인 |
| Harbor Helm Chart pull 실패 | OCI Secret 미등록 | repo-harbor-oci Secret 적용 여부 확인 |

📝 마무리
이번 글에서는 온프레미스 Kubernetes 환경에서 ArgoCD를 구축하는 과정을 정리해 봤습니다.
정리하면,
- Helm 설치 → helm upgrade --install로 idempotent 하게 설치
- Ingress → MetalLB + ingress-nginx + sslip.io로 도메인 접근
- Git 저장소 인증 → argocd.argoproj.io/secret-type: repository 라벨을 붙인 Secret으로 등록
- Harbor OCI 인증 → enableOCI: "true" Secret으로 별도 등록
- TLS 신뢰 → Harbor self-signed CA 인증서를 argocd-tls-certs-cm으로 등록
- ConfigMap → API 계정 생성 및 CRD health check Lua 스크립트 커스터마이징
- RBAC → argocd-rbac-cm으로 계정별 권한 설정
라고 볼 수 있습니다.
특히 이번 구축에서 주의해야 할 포인트는
- Git 저장소 인증과 Harbor OCI 인증은 values.yaml이 아닌 별도 Secret으로 관리해야 함
- Harbor self-signed 인증서는 반드시 argocd-tls-certs-cm에 등록해야 repo-server가 정상 동작
- server.insecure: true는 TLS 없이 HTTP로 운영할 때 사용하는 설정
이 3가지였습니다.
다음 편에서는 App of Apps 패턴을 활용해 플랫폼 전체 앱을 GitOps로 관리하는 방법을 다뤄보겠습니다. 🙌
궁금한 점이나 추가로 다뤄줬으면 하는 내용이 있다면 언제든지 편하게 말씀해 주세요! 😊
'[ Infra ] > Data Platform' 카테고리의 다른 글
| [Data Platform] KEDA 구축 가이드(Operator 설치부터 API 연동용 RBAC까지) (0) | 2026.07.10 |
|---|---|
| [Data Platform] ArgoCD GitOps 운영 가이드(App of Apps 패턴으로 플랫폼 관리) (0) | 2026.07.07 |
| [Data Platform] Superset 구축 가이드 (feat. Trino 연동) (0) | 2026.06.10 |
| [Data Platform] Prometheus + Grafana 구축 가이드 (feat. kube-prometheus-stack) (0) | 2026.06.09 |
| [Data Platform] Airflow 구축 가이드 (feat. Spark on Kubernetes) (0) | 2026.06.08 |