고가용성
고가용성 (High Availability)
Argo CD는 대부분 무상태(stateless)예요. 모든 데이터는 Kubernetes 객체로 유지되고, 이는 다시 Kubernetes의 etcd에 저장돼요. Redis는 단지 일회용 캐시로만 사용되며 서비스 중단 없이 안전하게 재구축할 수 있어요. Argo CD를 고가용성 방식으로 실행하고 싶은 사용자를 위해 HA 매니페스트 세트가 제공되며, 더 많은 컨테이너를 실행하고 Redis를 HA 모드로 실행해요.
출처: 문서
본문
[!NOTE] HA 설치는 스펙의 파드 반-어피니티(pod anti-affinity) 규칙 때문에 최소 세 개의 다른 노드가 필요해요. 또한 IPv6 전용 클러스터는 지원되지 않아요.
확장 (Scaling Up)
argocd-repo-server
설정(s):
argocd-repo-server는 Git 리포지토리를 복제하고 최신 상태로 유지하며 적절한 도구로 매니페스트를 생성하는 책임을 져요.
-
argocd-repo-server는 매니페스트를 생성하기 위해 config 관리 도구를 fork/exec 해요. fork는 메모리 부족이나 OS 스레드 수 제한 때문에 실패할 수 있어요.--parallelismlimit플래그는 동시에 몇 개의 매니페스트 생성이 실행되는지 제어하고 OOM kill을 피하는 데 도움을 줘요. -
argocd-repo-server는 Kustomize, Helm, 커스텀 플러그인 같은 config 관리 도구를 사용해 매니페스트 생성 중 리포지토리가 깨끗한 상태인지 보장해요. 결과적으로 여러 애플리케이션이 있는 Git 리포지토리는 리포지토리 서버 성능에 영향을 줄 수 있어요. 자세한 내용은 Monorepo 확장 고려사항을 참고하세요. -
argocd-repo-server는 리포지토리를/tmp(또는TMPDIR환경 변수에 지정된 경로)에 복제해요. 리포지토리가 너무 많거나 파일이 많으면 파드가 디스크 공간이 부족해질 수 있어요. 이 문제를 피하려면 영구 볼륨을 마운트하세요. -
argocd-repo-server는HEAD, 브랜치, 태그 이름 같은 모호한 리비전을 해석하기 위해git ls-remote를 사용해요. 이 작업은 자주 발생하며 실패할 수 있어요. 실패한 sync를 피하려면ARGOCD_GIT_ATTEMPTS_COUNT환경 변수를 사용해 실패한 요청을 재시도하세요. -
argocd-repo-server는 기본적으로 3분마다 앱 매니페스트의 변경을 확인해요. Argo CD는 기본적으로 매니페스트가 저장소가 변경될 때만 변경된다고 가정하므로 생성된 매니페스트를 캐시해요(기본 24h). Kustomize 원격 베이스를 사용하거나, 버전 번호를 올리지 않고 Helm 차트가 변경되는 경우에는, 리포지토리가 변경되지 않았는데도 예상 매니페스트가 변경될 수 있어요. 캐시 시간을 줄이면 24시간을 기다리지 않고 변경 사항을 얻을 수 있어요.--repo-cache-expiration duration을 사용하세요. 낮은 트래픽 환경에서는1h를 시도해보는 것을 권장해요. 너무 낮게 설정하면 캐싱의 이점이 사라진다는 점을 명심하세요. -
argocd-repo-server는helm이나kustomize같은 config 관리 도구를 실행하고 90초 타임아웃을 강제해요. 이 타임아웃은ARGOCD_EXEC_TIMEOUT환경 변수로 변경할 수 있어요. 값은 Go time duration 문자열 형식이어야 해요(예:2m30s). -
argocd-repo-server는ARGOCD_EXEC_TIMEOUT을 초과한 명령에SIGTERM신호를 보내요. 대부분의 경우 잘 동작하는(well-behaved) 명령은 신호를 받는 즉시 종료돼요. 하지만 그렇지 않으면argocd-repo-server는ARGOCD_EXEC_FATAL_TIMEOUT의 추가 타임아웃을 기다린 후SIGKILL로 명령을 강제 종료해 멈춤(stall)을 방지해요.SIGTERM으로 종료되지 않는 것은 보통 문제의 명령이나argocd-repo-server가 호출하는 방식의 버그이며, 추가 조사를 위해 이슈 트래커에 보고되어야 해요. -
Config Management Plugins(CMP)에서
discovery옵션을 사용할 때,argocd-repo-server는 리포지토리(또는argocd.argoproj.io/manifest-generate-paths어노테이션으로 지정된 파일만)를 각 플러그인용으로 별도 디렉터리에 복사해요. 이것은 특히 리포지토리에 큰 파일이 포함된 경우 argocd-repo-server에 디스크 리소스 부하를 줄 수 있어요. 완화하려면discovery를 비활성화하거나 Plugin tar stream 제외를 사용하는 것을 고려하세요.
메트릭(s):
argocd_git_request_total- git 요청 수. 이 메트릭은 두 개의 태그를 제공해요:repo- Git repo URL,request_type-ls-remote또는fetch.ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM- RPC 성능 메트릭 수집을 활성화하는 환경 변수. 성능 문제를 해결해야 한다면 활성화하세요. 참고: 이 메트릭은 조회와 저장 모두 비싸요!
argocd-application-controller
설정(s):
argocd-application-controller는 argocd-repo-server를 사용해 생성된 매니페스트를 얻고, Kubernetes API 서버를 사용해 실제 클러스터 상태를 얻어요.
-
각 컨트롤러 레플리카는 애플리케이션 reconcile(밀리초)과 앱 sync(초)를 처리하는 두 개의 별도 큐를 사용해요. 각 큐의 큐 프로세서 수는
--status-processors(기본 20)와--operation-processors(기본 10) 플래그로 제어돼요. Argo CD 인스턴스가 너무 많은 애플리케이션을 관리하면 프로세서 수를 늘리세요. 1000개 애플리케이션의 경우--status-processors에 50,--operation-processors에 25를 사용해요. -
Source Hydrator가 활성화되면 컨트롤러는 별도 큐로 매니페스트를 hydration하며, 그 동시성은
--hydration-processors플래그(기본 5)로 제어돼요. hydration 큐는 소스 repo, 대상 리비전, 대상 브랜치로 키가 지정되므로 같은 키는 한 번에 둘 이상의 프로세서로 hydration되지 않아요. 개수를 늘리면 서로 다른 키에 대한 hydration만 병렬화돼요. 단일 컨트롤러가 많은 독립 리포지토리나 브랜치를 hydration하고 hydration이 병목이 된다면 늘리세요. -
매니페스트 생성은 보통 reconcile 중 가장 많은 시간을 차지해요. 매니페스트 생성 기간은 컨트롤러 새로고침 큐가 넘치지 않도록 제한돼요. 매니페스트 생성이 너무 오래 걸리면 앱 reconcile이
Context deadline exceeded오류로 실패해요. 해결 방법으로--repo-server-timeout-seconds값을 늘리고argocd-repo-serverdeployment를 확장하는 것을 고려하세요. -
컨트롤러는 Kubernetes watch API를 사용해 경량 Kubernetes 클러스터 캐시를 유지해요. 이렇게 하면 앱 reconcile 중에 Kubernetes를 쿼리하지 않아도 되며 성능이 크게 개선돼요. 성능 때문에 컨트롤러는 리소스의 선호(preferred) 버전만 모니터링하고 캐시해요. reconcile 중에 컨트롤러는 캐시된 리소스를 선호 버전에서 Git에 저장된 리소스 버전으로 변환해야 할 수 있어요.
kubectl convert가 변환을 지원하지 않아 실패하면 컨트롤러는 Kubernetes API 쿼리로 폴백하며 reconcile이 느려져요. 이 경우 Git에서 선호 리소스 버전을 사용하길 권장해요. -
컨트롤러는 기본적으로 3분마다 Git을 폴링해요. 이 기간은
argocd-cmConfigMap의timeout.reconciliation과timeout.reconciliation.jitter설정으로 변경할 수 있어요. 필드 값은 duration string이며 예를 들어60s,1m,1h예요. -
컨트롤러가 너무 많은 클러스터를 관리하고 너무 많은 메모리를 사용한다면 여러 컨트롤러 레플리카에 클러스터를 샤딩할 수 있어요. 샤딩을 활성화하려면
argocd-application-controllerStatefulSet에서 레플리카 수를 늘리고,ARGOCD_CONTROLLER_REPLICAS환경 변수에 레플리카 수를 반복하세요. 아래의 전략적 병합 패치는 두 개의 컨트롤러 레플리카를 구성하는 데 필요한 변경을 보여줘요. -
기본적으로 컨트롤러는 10초마다 클러스터 정보를 업데이트해요. 클러스터 네트워크 환경에 문제가 있어 업데이트 시간이 오래 걸린다면,
ARGO_CD_UPDATE_CLUSTER_INFO_TIMEOUT환경 변수를 수정해 타임아웃을 늘려볼 수 있어요(단위는 초).
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: argocd-application-controller
spec:
replicas: 2
template:
spec:
containers:
- name: argocd-application-controller
env:
- name: ARGOCD_CONTROLLER_REPLICAS
value: "2"
-
클러스터의 샤드 번호를 수동으로 설정하려면 클러스터를 만들 때 선택적
shard속성을 지정하세요. 지정하지 않으면 애플리케이션 컨트롤러가 즉석에서 계산해요. -
argocd-application-controller의 샤드 분배 알고리즘은--sharding-method파라미터로 설정할 수 있어요. 지원되는 샤딩 방법은:legacy모드는uid기반 분배를 사용해요(비균일).round-robin은 모든 샤드에 걸쳐 동일 분배를 사용해요.consistent-hashing은 샤드나 클러스터가 추가/제거될 때 클러스터·애플리케이션 재분배를 줄이는 경향이 있는 바운드 부하(bounded loads)가 있는 consistent hashing 알고리즘을 사용해요.
--sharding-method 파라미터는 argocd-cmd-params-cm ConfigMap에서 controller.sharding.algorithm 키를 설정하거나(가급적) ARGOCD_CONTROLLER_SHARDING_ALGORITHM 환경 변수를 설정하고 같은 가능한 값을 지정해 덮어쓸 수도 있어요.
[!WARNING] 알파 기능 (Alpha Features)
round-robin샤드 분배 알고리즘은 실험적 기능이에요. 클러스터 제거가 있는 특정 시나리오에서 reshuffling이 발생하는 것으로 알려져 있어요. rank-0 클러스터가 제거되면 모든 샤드에 걸쳐 모든 클러스터의 reshuffling이 발생하고 일시적으로 성능에 부정적 영향을 줄 수 있어요.consistent-hashing샤드 분배 알고리즘은 실험적 기능이에요. 광범위한 벤치마크가 CNOE 블로그에 문서화되어 있으며 고무적인 결과를 보여줘요. 이 기능을 프로덕션 준비 상태로 만들기 전에 커뮤니티 피드백을 크게 환영해요.
- 클러스터는 클러스터 secret의
shard필드를 패치해 특정shard에 수동으로 할당하고 강제할 수 있어요. 예:
apiVersion: v1
kind: Secret
metadata:
name: mycluster-secret
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
shard: 1
name: mycluster.example.com
server: https://mycluster.example.com
config: |
{
"bearerToken": "<authentication token>",
"tlsClientConfig": {
"insecure": false,
"caData": "<base64 encoded certificate>"
}
}
-
ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM- RPC 성능 메트릭 수집을 활성화하는 환경 변수. 성능 문제를 해결해야 한다면 활성화하세요. 참고: 이 메트릭은 조회와 저장 모두 비싸요! -
ARGOCD_CLUSTER_CACHE_LIST_PAGE_BUFFER_SIZE- 클러스터 캐시를 동기화하면서 K8s API 서버에 대해 list 작업을 수행할 때 컨트롤러가 메모리에 버퍼링하는 페이지 수를 제어하는 환경 변수. 이것은 클러스터에 많은 수의 리소스가 있고 클러스터 동기화 시간이 기본 etcd 컴팩션 간격 타임아웃을 초과할 때 유용해요. 이 시나리오에서 클러스터 캐시를 동기화하려 할 때 애플리케이션 컨트롤러가continue parameter is too old to display a consistent list result오류를 던질 수 있어요. 이 환경 변수에 더 높은 값을 설정하면 비동기적으로 처리되는 프리페치된 페이지를 저장할 더 큰 버퍼로 컨트롤러를 구성해서, etcd 컴팩션 간격 타임아웃이 만료되기 전에 모든 페이지가 가져와질 가능성이 높아져요. 가장 극단적인 경우 운영자는ARGOCD_CLUSTER_CACHE_LIST_PAGE_SIZE * ARGOCD_CLUSTER_CACHE_LIST_PAGE_BUFFER_SIZE가 가장 큰 리소스 수(list 작업 병렬성의 세분 단위인 k8s api version별로 그룹화된)를 초과하도록 값을 설정할 수 있어요. 이 경우 모든 리소스가 메모리에 버퍼링되며, 처리로 인해 API 서버 요청이 차단되지 않아요. -
ARGOCD_CLUSTER_CACHE_BATCH_EVENTS_PROCESSING- 컨트롤러가 Kubernetes 리소스의 이벤트를 수집해 배치로 처리할 수 있게 하는 환경 변수. 클러스터에 많은 수의 리소스가 있고 컨트롤러가 이벤트 수에 압도될 때 유용해요. 기본값은true예요.false는 컨트롤러가 이벤트를 하나씩 처리한다는 뜻이에요. -
ARGOCD_CLUSTER_CACHE_EVENTS_PROCESSING_INTERVAL- 이벤트를 배치로 처리하는 간격을 제어하는 환경 변수. 유효한 값은 Go time duration 문자열 형식이며, 예:1ms,1s,1m,1h. 기본값은100ms예요. 이 변수는ARGOCD_CLUSTER_CACHE_BATCH_EVENTS_PROCESSING이true로 설정된 경우에만 사용돼요. -
ARGOCD_APPLICATION_TREE_SHARD_SIZE- 하나의 Redis 키에 저장되는 최대 리소스 수를 제어하는 환경 변수. 애플리케이션 트리를 여러 키로 나누면 컨트롤러와 Redis 사이의 트래픽 양을 줄이는 데 도움을 줘요. 기본값은 0으로, 애플리케이션 트리가 단일 Redis 키에 저장된다는 뜻이에요. 합리적인 값은 100이에요.
메트릭(s):
-
argocd_app_reconcile- 초 단위의 애플리케이션 reconcile 지속 시간을 보고해요. 높은 수준의 reconcile 성능 그림을 얻기 위한 reconciliation 기간 heat map을 만드는 데 사용할 수 있어요. -
argocd_app_k8s_request_total- 애플리케이션당 k8s 요청 수. 폴백 Kubernetes API 쿼리 수 — 어떤 애플리케이션에 비선호 버전 리소스가 있고 성능 문제를 일으키는지 식별하는 데 유용해요.
argocd-server
argocd-server는 무상태이며 문제를 일으킬 가능성이 가장 낮아요. 업그레이드 중 다운타임이 없도록 레플리카 수를 3 이상으로 늘리고 ARGOCD_API_SERVER_REPLICAS 환경 변수에 그 수를 반복하는 것을 고려하세요. 아래의 전략적 병합 패치가 이를 보여줘요.
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-server
spec:
replicas: 3
template:
spec:
containers:
- name: argocd-server
env:
- name: ARGOCD_API_SERVER_REPLICAS
value: "3"
설정(s):
-
ARGOCD_API_SERVER_REPLICAS환경 변수는 각 레플리카에 동시 로그인 요청 수 제한( ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT )을 분배하는 데 사용돼요. -
ARGOCD_GRPC_MAX_SIZE_MB환경 변수는 서버 응답 메시지의 최대 크기를 메가바이트 단위로 지정할 수 있게 해줘요. 기본값은 200이에요. 3000개 이상의 애플리케이션을 관리하는 Argo CD 인스턴스에서는 늘려야 할 수 있어요. -
argocd-cmd-params-cm의server.glob.cache.sizeconfig 키(또는--glob-cache-size서버 플래그)는 RBAC 정책 평가를 위해 캐시되는 컴파일된 glob 패턴의 최대 수를 제어해요. glob 패턴 컴파일은 비싸며, 캐싱은 많은 애플리케이션이 관리될 때 RBAC 성능을 크게 개선해요. 기본값은 10000이에요. 자세한 내용은 RBAC Glob 매칭을 참고하세요.
argocd-dex-server, argocd-redis
argocd-dex-server는 인메모리 데이터베이스를 사용하며, 두 개 이상의 인스턴스는 일관되지 않은 데이터를 가질 수 있어요. argocd-redis는 총 세 개의 redis 서버/sentinel만 이해하도록 사전 구성되어 있어요.
Monorepo 확장 고려사항 (Monorepo Scaling Considerations)
Argo CD repo server는 리포지토리 복제본 하나를 로컬로 유지하고 애플리케이션 매니페스트 생성에 사용해요. 매니페스트 생성이 로컬 리포지토리 복제본의 파일 변경을 요구한다면, 서버 인스턴스당 하나의 동시 매니페스트 생성만 허용돼요. 이 제한은 여러 애플리케이션(50개 이상)이 있는 monorepo가 있다면 Argo CD를 상당히 느리게 만들 수 있어요.
완전히 정규화된 Git 참조 사용 (Use Fully Qualified Git References)
Application 매니페스트에서 targetRevision을 지정할 때, 짧은 이름 대신 완전히 정규화된 Git 참조 경로를 사용하면 repo-server 성능을 크게 개선할 수 있어요. 특히 수십만 개의 커밋과 태그가 있는 큰 monorepo에서 그렇죠.
성능 영향:
Git 참조를 해석할 때(예: main을 commit SHA로 변환), Argo CD는 다음을 해야 해요:
- 모든 Git 참조(브랜치와 태그)를 로드
- 일치하는 것을 찾기 위해 모든 참조를 순회
- 필요한 경우 심볼릭 참조 해석
많은 참조가 있는 리포지토리의 경우 이 과정은 CPU와 메모리 집약적이에요. 완전히 정규화된 참조를 사용하면 Argo CD가 해석 과정을 최적화하고 캐싱을 더 효과적으로 활용할 수 있어요.
권장 접근 방식:
# ❌ Less efficient - requires iteration through all refs
spec:
source:
targetRevision: main
# ✅ More efficient - directly identifies the reference type
spec:
source:
targetRevision: refs/heads/main
일반적인 완전 정규화 참조 형식:
- 브랜치:
refs/heads/<branch-name>(예:refs/heads/main,refs/heads/develop) - 태그:
refs/tags/<tag-name>(예:refs/tags/v1.0.0) - 풀 리퀘스트 (GitHub):
refs/pull/<pr-number>/head(예:refs/pull/123/head) - 머지 리퀘스트 (GitLab):
refs/merge-requests/<mr-number>/head
동시 처리 활성화 (Enable Concurrent Processing)
Argo CD는 매니페스트 생성이 로컬 리포지토리 복제본의 로컬 파일을 변경할 수 있는지 config 관리 도구와 애플리케이션 설정에 따라 결정해요. 매니페스트 생성에 부작용이 없다면 요청은 성능 저하 없이 병렬로 처리돼요. 다음은 느려질 수 있는 알려진 경우와 그 해결 방법이에요:
-
한 Git 리포지토리의 같은 디렉터리를 가리키는 여러 Helm 기반 애플리케이션: 역사적인 이유로 Argo CD는 Helm 매니페스트를 순차적으로 생성했어요. v3.0부터 Argo CD는 기본적으로 Helm 매니페스트를 병렬 생성해요.
-
여러 커스텀 플러그인 기반 애플리케이션: 매니페스트 생성 중 임시 파일 생성을 피하고 앱 디렉터리에
.argocd-allow-concurrency파일을 만들거나, 각 애플리케이션을 리포지토리의 임시 복사본으로 처리하는 사이드카 플러그인 옵션을 사용하세요. -
같은 리포지토리에서 파라미터 오버라이드가 있는 여러 Kustomize 애플리케이션: 현재 이 제한에 대한 해결 방법은 없어요.
Manifest Paths 어노테이션 (Manifest Paths Annotation)
Argo CD는 생성된 매니페스트를 적극적으로 캐시하고 리포지토리 커밋 SHA를 캐시 키로 사용해요. Git 리포지토리에 새 커밋이 생기면 리포지토리에 구성된 모든 애플리케이션의 캐시가 무효화돼요. 이것은 여러 애플리케이션이 있는 리포지토리에 부정적인 영향을 줄 수 있어요. 이 문제를 해결하고 성능을 개선하려면 argocd.argoproj.io/manifest-generate-paths Application CRD 어노테이션을 사용할 수 있어요.
참고: argocd.argoproj.io/manifest-generate-paths 어노테이션은 웹훅과 함께 사용할 수 있어요. Argo CD v2.11부터 이 어노테이션은 웹훅을 구성하지 않고도 사용할 수 있어요. 웹훅은 이 기능의 전제 조건이 아니에요. 모든 애플리케이션에 대해 매니페스트 생성을 최적화하려면 어노테이션만 사용하면 돼요.
argocd.argoproj.io/manifest-generate-paths 어노테이션은 매니페스트 생성 중에 사용되는 Git 리포지토리 내 경로의 세미콜론으로 구분된 목록을 포함해요. 어노테이션에 지정된 경로를 사용해 마지막 캐시된 리비전을 최신 커밋과 비교해요. argocd.argoproj.io/manifest-generate-paths에 지정된 경로와 일치하는 수정된 파일이 없으면 애플리케이션 reconcile을 트리거하지 않고 기존 캐시가 새 커밋에 유효한 것으로 간주돼요.
각 애플리케이션에 다른 리포지토리를 사용하는 설치는 이 동작의 대상이 아니며 이 어노테이션 사용으로 이점을 얻지 못할 거예요.
마찬가지로 외부 Helm values 파일을 참조하는 애플리케이션은 외부 소스에서 무관한 변경이 발생할 때 이 기능의 이점을 얻지 못해요.
[!NOTE] 위에서 설명한 Git-히스토리 비교는 shallow cloning(
depth가0보다 큰)으로 구성된 리포지토리에 대해서는 건너뛰어져요. 이 경우 Argo CD는 이전에 동기화된 리비전을 새 리비전과 비교할 충분한 히스토리가 없을 수 있으므로, 애플리케이션을 잠재적으로 변경된 것으로 취급하고 정상적인 새로고침과 매니페스트 생성으로 진행해요. 이것은 웹훅 이벤트가 보고한 변경된 파일을 사용하는 웹훅 payload 필터링에는 영향을 주지 않아요. 또한 이 어노테이션은--plugin-use-manifest-generate-paths가 활성화될 때 공통 루트 경로를 계산하고 Config Management Plugin 사이드카로 보내지는 리포지토리 내용을 줄이는 데도 여전히 사용할 수 있어요.
웹훅의 경우 비교는 대신 웹훅 이벤트 payload에 지정된 파일을 사용해 수행돼요.
[!NOTE] 웹훅용 애플리케이션 manifest paths 어노테이션 지원은 Application에 사용되는 git 제공자에 따라 달라요. 현재 GitHub, GitLab, Gogs 기반 repo에만 지원돼요.
- 상대 경로 (Relative path) 어노테이션은 상대 경로를 포함할 수 있어요. 이 경우 경로는 애플리케이션 소스에 지정된 경로를 기준으로 간주돼요:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
namespace: argocd
annotations:
# resolves to the 'guestbook' directory
argocd.argoproj.io/manifest-generate-paths: .
spec:
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: guestbook
# ...
- 절대 경로 (Absolute path) 어노테이션 값은 '/'로 시작하는 절대 경로일 수 있어요. 이 경우 경로는 Git 리포지토리 안의 절대 경로로 간주돼요:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
annotations:
argocd.argoproj.io/manifest-generate-paths: /guestbook
spec:
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: guestbook
# ...
- 여러 경로 (Multiple paths) 어노테이션에 여러 경로를 넣는 것이 가능해요. 경로는 세미콜론(
;)으로 구분해야 해요:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
annotations:
# resolves to 'my-application' and 'shared'
argocd.argoproj.io/manifest-generate-paths: .;../shared
spec:
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: my-application
# ...
- Glob 경로 (Glob paths) 어노테이션은 Go filepath Match 함수가 지원하는 어떤 패턴이든 될 수 있는 glob 패턴 경로를 포함할 수 있어요:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
namespace: argocd
annotations:
# resolves to any file matching the pattern of *-secret.yaml in the top level shared folder
argocd.argoproj.io/manifest-generate-paths: "/shared/*-secret.yaml"
spec:
source:
repoURL: https://github.com/argoproj/argocd-example-apps.git
targetRevision: HEAD
path: guestbook
# ...
[!NOTE]
argocd.argoproj.io/manifest-generate-paths어노테이션 기능을 사용한 애플리케이션 매니페스트 생성이 활성화되면, 전체 리포지토리가 아니라 이 어노테이션으로 지정된 리소스만 매니페스트 생성을 위해 CMP 서버로 보내져요. 적절한 리소스를 결정하기 위해 어노테이션에 제공된 경로를 기반으로 공통 루트 경로가 계산돼요. 애플리케이션 경로는 루트로 선택될 수 있는 가장 깊은 경로 역할을 해요.
어노테이션 효율 측정 (Measuring Annotation Efficiency)
다음 메트릭을 사용해 argocd.argoproj.io/manifest-generate-paths 어노테이션이 불필요한 매니페스트 재생성을 얼마나 효과적으로 줄이는지 평가할 수 있어요:
- argocd_webhook_requests_total (라벨:
repo) — 리포지토리별로 수신되는 웹훅 이벤트를 계산. Argo CD가 받는 push 이벤트 수의 기준선으로 사용하세요. - argocd_webhook_store_cache_attempts_total (라벨:
repo,successful) — 애플리케이션의 새로고침 경로가 변경되지 않은 경우 새 커밋 SHA에 대해 이전에 캐시된 매니페스트를 재사용하려는 시도를 계산.successful=true결과는 매니페스트를 재생성하지 않고 새 리비전에 대해 캐시가 warm되었다는 뜻이며, 이것이 원하는 결과예요.
효율을 평가하려면 전체 웹훅 비율에 대해 successful=true 시도의 비율을 비교하세요. 높은 비율은 어노테이션이 잘 작동하고 불필요한 매니페스트 재생성을 방지하고 있음을 나타내요.
일부 successful=false 결과는 예상되며 우려할 사항이 아니에요 — Argo CD가 아직 애플리케이션의 매니페스트를 캐시하지 않았을 때(예: 재시작 후 또는 첫 sync) 발생하며, 새 리비전으로 이어갈 것이 없기 때문이에요.
웹훅에서 매니페스트 캐시 Warming 비활성화 (Disabling Manifest Cache Warming in Webhooks)
어떤 경우에는 웹훅 핸들러가 수행하는 매니페스트 캐시 warming이 성능을 돕기보다 해칠 수 있어요:
- 순수 YAML 리포지토리: 애플리케이션이 순수 YAML 매니페스트(Helm이나 Kustomize 렌더링 없음)를 사용하면 매니페스트 생성이 빠르고 캐싱이 거의 이점을 주지 않아요. 매 커밋마다 수천 개의 영향받지 않는 애플리케이션에 대한 캐시를 warming하려 하면 상당한 오버헤드가 추가돼요.
- 큰 monorepo: 많은 애플리케이션이 단일 리포지토리를 공유하는 경우, 각 웹훅 이벤트는 경로가 변경되지 않은 모든 애플리케이션에 대한 캐시 warm 시도를 트리거해요. 수천 개의 애플리케이션이 있으면 웹훅 핸들러가 Redis 작업에 상당한 시간을 쓰게 되어, 영향받는 애플리케이션에 대한 실제 reconcile 트리거를 지연시킬 수 있어요.
비활성화하면 웹훅 핸들러는 파일이 변경된 애플리케이션에 대해서만 reconcile을 트리거하고 영향받지 않는 애플리케이션에 대한 모든 Redis 캐시 작업을 건너뛰어요. 이것은 순수 YAML 매니페스트가 있는 큰 monorepo에 권장되는 설정이에요.
리포지토리별 설정 (권장): ArgoCD CLI 또는 UI로 리포지토리에 webhookManifestCacheWarmDisabled: true를 설정하세요:
argocd repo edit https://github.com/org/repo.git --webhook-manifest-cache-warm-disabled
전역 설정: 모든 리포지토리에 대한 캐시 warming을 비활성화하려면 argocd-server에 다음 환경 변수를 설정하세요:
ARGOCD_WEBHOOK_MANIFEST_CACHE_WARM_DISABLED=true
애플리케이션 Sync 타임아웃과 Jitter (Application Sync Timeout & Jitter)
Argo CD에는 애플리케이션 sync를 위한 타임아웃이 있어요. 타임아웃이 만료되면 각 애플리케이션에 대해 주기적으로 새로고침을 트리거해요. 애플리케이션이 많으면 새로고침 큐에 스파이크가 생기고 repo-server 컴포넌트에 스파이크가 발생할 수 있어요. 이를 피하려면 sync 타임아웃에 jitter를 설정해 새로고침을 분산시키고 repo-server가 따라잡을 시간을 줄 수 있어요.
jitter는 sync 타임아웃에 추가할 수 있는 최대 지속 시간이에요. sync 타임아웃이 5분이고 jitter가 1분이면 실제 타임아웃은 5분에서 6분 사이가 돼요.
jitter를 구성하려면 다음 환경 변수를 설정할 수 있어요:
ARGOCD_RECONCILIATION_JITTER- sync 타임아웃에 적용할 jitter. 값이 0이면 비활성화. 기본값 60.
웹훅 Reconcile Jitter (Webhook Reconciliation Jitter)
웹훅 이벤트가 도착하면(예: monorepo에 대한 대량 merge 후) Argo CD는 많은 수의 애플리케이션에 대한 새로고침을 동시에 큐에 넣어 repo-server에 부하 스파이크를 일으킬 수 있어요. 이런 새로고침을 시간에 걸쳐 분산시키려면 각 웹훅 트리거 새로고침이 처리되기 전에 적용되는 무작위 jitter를 구성할 수 있어요.
다음 argocd-cm ConfigMap 키가 이 동작을 제어해요:
webhook.refresh.jitter– 각 웹훅 트리거 애플리케이션 새로고침 전에 추가되는 무작위 지연의 최대 지속 시간. 예를 들어60s로 설정하면 각 새로고침은 처리되기 전에 0에서 60초 사이를 기다려요. 값이0이면 비활성화(기본값).webhook.refresh.jitter.threshold– jitter가 적용되기 전에 단일 웹훅 이벤트가 영향줘야 하는 최소 애플리케이션 수. 작은 이벤트에 불필요한 지연이 생기지 않게 해줘요. 예를 들어10(기본값)으로 설정하면 10개가 넘는 애플리케이션이 영향받을 때만 jitter가 적용돼요.
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
data:
# Apply up to 60s of jitter when more than 10 applications are affected
webhook.refresh.jitter: "60s"
webhook.refresh.jitter.threshold: "10"
argocd-cmd-params-cm의 server.webhook.refresh.workers 키로 새로고침 큐를 처리하는 동시 워커 수를 조정할 수도 있어요(기본: 20). 높은 웹훅 부하에서는 jitter 설정과 함께 이 값을 올려 jitter 지연이 만료된 후 큐를 더 빨리 비우는 것이 유리할 수 있어요.
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cmd-params-cm
data:
server.webhook.refresh.workers: "40"
애플리케이션 Reconcile 레이트 리밋 (Rate Limiting Application Reconciliations)
잘못 동작하는 앱이나 다른 환경 특정 요인 때문에 발생하는 높은 컨트롤러 리소스 사용 또는 sync 루프를 막기 위해, 애플리케이션 컨트롤러가 사용하는 워크큐에 레이트 리밋을 구성할 수 있어요. 구성할 수 있는 레이트 리밋은 두 가지 유형이 있어요:
- 전역 레이트 리밋
- 항목별(Per item) 레이트 리밋
최종 레이트 리미터는 둘 다의 조합을 사용해 최종 백오프를 max(globalBackoff, perItemBackoff)로 계산해요.
전역 레이트 리밋 (Global rate limits)
기본적으로 비활성화되어 있으며, 초당 큐에 넣을 수 있는 항목 수를 제한하는 간단한 bucket 기반 레이트 리미터예요. 많은 수의 앱이 동시에 큐에 들어가는 것을 막는 데 유용해요.
bucket 리미터를 구성하려면 다음 환경 변수를 설정할 수 있어요:
WORKQUEUE_BUCKET_SIZE- 단일 burst에 큐에 넣을 수 있는 항목 수. 기본값 500.WORKQUEUE_BUCKET_QPS- 초당 큐에 넣을 수 있는 항목 수. 기본값 MaxFloat64로, 리미터를 비활성화해요.
항목별 레이트 리밋 (Per item rate limits)
기본적으로 고정된 기본 지연/백오프 값을 반환하지만 지수 값을 반환하도록 구성할 수 있어요. 항목별 레이트 리미터는 특정 항목이 큐에 넣어질 수 있는 횟수를 제한해요. 이것은 지수 백오프에 기반하며, 항목이 짧은 기간에 여러 번 큐에 들어가면 항목의 백오프 시간이 지수적으로 계속 증가하지만, 항목이 마지막으로 큐에 들어간 이후 구성된 cool down 기간이 경과하면 백오프가 자동으로 재설정돼요.
항목별 리미터를 구성하려면 다음 환경 변수를 설정할 수 있어요:
WORKQUEUE_FAILURE_COOLDOWN_NS: 나노초 단위의 cool down 기간. 항목에 대해 기간이 경과하면 백오프가 재설정돼요. 0(기본값)으로 설정하면 지수 백오프가 비활성화돼요. 예시 값: 10 * 10^9 (=10s)WORKQUEUE_BASE_DELAY_NS: 나노초 단위의 기본 지연. 지수 백오프 공식에서 사용되는 초기 백오프예요. 기본값 1000 (=1μs)WORKQUEUE_MAX_DELAY_NS: 나노초 단위의 최대 지연. 최대 백오프 제한이에요. 기본값 3 * 10^9 (=3s)WORKQUEUE_BACKOFF_FACTOR: 백오프 계수. 각 재시도마다 백오프가 증가하는 계수예요. 기본값 1.5
항목에 대한 백오프 시간을 계산하는 공식이며, numRequeue는 항목이 큐에 들어간 횟수, lastRequeueTime은 항목이 마지막으로 큐에 들어간 시각이에요:
WORKQUEUE_FAILURE_COOLDOWN_NS!= 0 일 때:
backoff = time.Since(lastRequeueTime) >= WORKQUEUE_FAILURE_COOLDOWN_NS ?
WORKQUEUE_BASE_DELAY_NS :
min(
WORKQUEUE_MAX_DELAY_NS,
WORKQUEUE_BASE_DELAY_NS * WORKQUEUE_BACKOFF_FACTOR ^ (numRequeue)
)
WORKQUEUE_FAILURE_COOLDOWN_NS= 0 일 때:
backoff = WORKQUEUE_BASE_DELAY_NS
HTTP 요청 재시도 전략 (HTTP Request Retry Strategy)
네트워크 불안정이나 일시적 서버 오류가 발생하는 시나리오에서 재시도 전략은 실패한 요청을 자동으로 다시 보내 HTTP 통신의 견고성을 보장해요. 최대 재시도 수와 백오프 간격을 조합해 서버를 압도하거나 네트워크를 과도하게 사용하는 것을 방지해요.
재시도 구성 (Configuring Retries)
재시도 로직은 다음 환경 변수로 미세 조정할 수 있어요:
ARGOCD_K8SCLIENT_RETRY_MAX- 각 요청의 최대 재시도 수. 이 수에 도달하면 요청이 중단돼요. 기본값 0(재시도 없음).ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF- 첫 번째 재시도 시도의 초기 백오프 지연(ms). 후속 재시도는 최대 임계값까지 이 백오프 시간을 두 배로 늘려요. 기본값 100ms.
백오프 전략 (Backoff Strategy)
사용되는 백오프 전략은 jitter가 없는 간단한 지수 백오프예요. 백오프 시간은 최대 백오프 지속 시간에 도달할 때까지 각 재시도 시도마다 지수적으로 증가해요.
백오프 시간 계산 공식:
backoff = min(retryWaitMax, baseRetryBackoff * (2 ^ retryAttempt))
여기서 retryAttempt는 0에서 시작하고 각 후속 재시도마다 1씩 증가해요.
최대 대기 시간 (Maximum Wait Time)
재시도 사이의 과도한 대기 시간을 막기 위한 백오프 시간 상한이 있어요. 이 상한은 다음으로 정의돼요:
retryWaitMax- 재시도 전에 기다리는 최대 지속 시간. 재시도가 합리적인 시간 범위 안에 일어나도록 보장해요. 기본값 10초.
재시도 불가 조건 (Non-Retriable Conditions)
모든 HTTP 응답이 재시도 대상이 되는 것은 아니에요. 다음 조건은 재시도를 트리거하지 않아요:
- 429 Too Many Requests를 제외한 클라이언트 오류(4xx)를 나타내는 상태 코드의 응답.
- 501 Not Implemented 상태 코드의 응답.
CPU/메모리 프로파일링 (CPU/Memory Profiling)
Argo CD는 선택적으로 Argo CD 컴포넌트의 CPU와 메모리 사용량을 프로파일링하는 데 사용할 수 있는 프로파일링 엔드포인트를 노출해요. 프로파일링 엔드포인트는 각 컴포넌트의 메트릭 포트에서 사용할 수 있어요. 포트에 대한 자세한 내용은 metrics를 참고하세요. 보안상의 이유로 프로파일링 엔드포인트는 기본적으로 비활성화되어 있어요. 엔드포인트는 argocd-cmd-params-cm ConfigMap의 server.profile.enabled, applicationsetcontroller.profile.enabled, reposerver.profile.enabled 또는 controller.profile.enabled 키를 true로 설정해 활성화할 수 있어요. 엔드포인트가 활성화되면 go profile 도구를 사용해 CPU와 메모리 프로파일을 수집할 수 있어요. 예:
$ kubectl port-forward svc/argocd-metrics 8082:8082
$ go tool pprof http://localhost:8082/debug/pprof/heap
메모리 스파이크로 인한 OOMKilled 이벤트 완화 (Mitigating OOMKilled Events from Memory Spikes)
갑작스러운 메모리 스파이크로 인한 OOMKilled 이벤트를 리소스를 과도하게 프로비저닝하지 않고 완화하려면 관련 Argo CD 컨테이너에 GOMEMLIMIT 환경 변수를 구성할 수 있어요(Argo CD 버전 >= 2.7.0에서 지원). GOMEMLIMIT을 컨테이너 총 메모리 제한의 80%–90% 로 설정하면 Go 런타임이 Kubernetes 하드 제한에 도달하기 전에 가비지 컬렉션을 트리거하도록 강제해요. 자세한 내용은 Go GC 가이드와 환경 변수 참조를 참고하세요.
containers:
- name: argocd-application-controller
resources:
limits:
memory: "2Gi"
env:
- name: GOMEMLIMIT
value: "1800MiB" # ~90% of the 2Gi memory limit above; GOMEMLIMIT uses MiB/GiB units
알려진 사용 사례 (Known Use Cases)
- 애플리케이션 컨트롤러 콜드 스타트 메모리 스파이크
- argocd-server의 요청당 비싼 메모리 스파이크
트레이드오프와 튜닝 (Trade-Offs & Tuning)
[!WARNING]
GOMEMLIMIT을 애플리케이션의 실제 작업 세트(working set)에 너무 가깝게 설정하면 **GC 쓰래싱(GC thrashing)**이 발생할 수 있어요. Go 런타임이 메모리를 회수하려고 계속 시도하며 과도한 CPU 사이클을 소비하고, 애플리케이션 성능이 크게 저하돼요.
빈번한 GC 활동이나 지속적인 OOMKilled 이벤트와 함께 지속적인 높은 CPU 사용률을 관찰한다면, 컨테이너의 총 메모리 제한을 늘리고 런타임에 여유 공간을 주도록 GOMEMLIMIT을 비례적으로 다시 계산하세요.
Shallow Clone
과거 리비전에 큰 히스토리나 큰 파일이 있는 리포지토리는 복제·업데이트가 느릴 수 있어요. 복제 과정을 빠르게 하려면 depth: "1" 리포지토리 옵션을 사용할 수 있어요:
apiVersion: v1
stringData:
depth: "1"
type: "git"
url: "https://github.com/argoproj/argocd-example-apps.git"
kind: Secret
metadata:
annotations:
managed-by: argocd.argoproj.io
labels:
argocd.argoproj.io/secret-type: repository
name: my-repo
namespace: argocd
type: Opaque
[!NOTE]
argocd repo add <repo-url> --depth명령을 사용해 shallow cloning이 활성화된 리포지토리를 추가할 수 있어요.
shallow cloning 시 리포지토리는 depth 1로 복제되며, 즉 전체 히스토리가 아닌 필요한 커밋만 복제돼요. 이 접근 방식은 리포지토리에 큰 히스토리가 있을 때 합리적이에요.
[!NOTE] shallow cloning은
argocd.argoproj.io/manifest-generate-paths어노테이션이 제공하는 비-웹훅 Git-히스토리 비교 최적화를 비활성화해요. 웹훅 없이 그 어노테이션에 의존해 불필요한 새로고침을 피한다면 그 리포지토리에 대해 전체 복제(depth: "0"또는depth생략)를 사용하세요. 웹훅 payload 필터링과 Config Management Plugin 사이드카 경로 좁히기는 shallow clone과 함께 어노테이션을 여전히 사용할 수 있어요.