LabHub
배우기 러닝패스 코스

CAPA — Argo Project Associate

The values file said 2, but 3 pods came up

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

진짜 Argo CD 에서 Helm 차트와 Kustomize 오버레이를 소스로 쓰고, 값이 어디서 정해지는지, 동기화 단계·웨이브·훅이 적용 순서를 어떻게 바꾸는지, selfHeal 이 무엇을 되돌리지 않게 할 수 있는지를 클러스터에 생긴 결과로 확인합니다.

왜 중요한가

Argo CD 는 Helm 을 패키지 관리자로 쓰지 않고 템플릿 엔진으로만 씁니다. 그래서 helm list 에 아무것도 없고, 롤백도 Helm 이 아니라 Git 과 Argo CD 가 맡습니다. 대신 값이 네 군데(차트 기본값, 값 파일, Application 의 valuesObject, parameters)에서 올 수 있어 "Git 의 values 파일을 고쳤는데 왜 안 바뀌지" 가 흔한 장애가 됩니다. Kustomize 덮어쓰기도 같아서 Application 에 적은 이미지는 Git 저장소에 없는 원하는 상태입니다. 동기화는 한 번에 모두 적용하는 것이 아니라 PreSync·Sync·PostSync 단계와 웨이브로 나뉘고, 앞 웨이브가 Healthy 가 될 때까지 기다리며, 훅이 실패하면 뒤 단계는 시작되지 않습니다. 마지막으로 HPA 처럼 다른 조정기가 소유한 필드는 ignoreDifferences 로 비교와 동기화에서 빼야 selfHeal 과 싸우지 않습니다.

단계

  1. 베어 저장소 /srv/bare/src.git 을 만들고 /root/capa-src/repo 로 복제해 charts/web 에 Helm 차트를 커밋·push 하세요. Chart.yaml(name web, version 0.1.0), values.yaml(replicaCount: 1, greeting: chart-default), values-prod.yaml(replicaCount: 2, greeting: from-values-file), 템플릿 두 개({{ .Release.Name }}-greeting ConfigMap 의 data.greeting, {{ .Release.Name }}-web Deployment 의 replicas·이미지 nginx:1.27-alpine)를 둡니다. /root/capa-src/app-src-helm.yaml 의 Application src-helm(저장소 git://gitd.gitsrv.svc.cluster.local:9418/src.git main·charts/web, 대상 네임스페이스 src-helm, 자동 동기화·CreateNamespace)에 helm.valueFiles: [values-prod.yaml] 를 주고 적용해 Synced·Healthy 를 확인하세요.
  2. src-helm 의 source.helm 에 valuesObject(replicaCount: 3, greeting: from-values-object)와 parameters(greeting = from-parameter)를 더해 다시 적용하세요. 동기화가 끝나면 /root/capa-src/precedence.jsonreplicas(src-helm 네임스페이스 Deployment src-helm-web 의 spec.replicas, 숫자)와 greeting(ConfigMap src-helm-greeting 의 값)을 적습니다.
  3. Argo CD 는 차트를 렌더링해 적용할 뿐 Helm 릴리스를 만들지 않습니다. src-helm 네임스페이스의 Secret 중 타입이 helm.sh/release.v1 인 것의 개수와, ConfigMap src-helm-greeting 에 Argo CD 가 남긴 추적 표식을 확인해 /root/capa-src/tracking.jsonhelm_release_secrets(숫자), tracking_annotation(그 ConfigMap 의 argocd.argoproj.io/tracking-id 값), instance_label(라벨 app.kubernetes.io/instance 가 있으면 그 값, 없으면 null)을 적으세요.
  4. /root/capa-src/repo/kust 에 Kustomize 구조를 커밋·push 하세요. base 에 Deployment api(replicas 1, 라벨 app: api, 이미지 nginx:1.27-alpine)와 kustomization, overlays/prod 에 base 를 가리키고 namePrefix: prod-, replicas 로 api 를 2 로 바꾸는 kustomization 을 둡니다. Application src-kust(경로 kust/overlays/prod, 대상 네임스페이스 src-kust, 자동 동기화·CreateNamespace)를 /root/capa-src/app-src-kust.yaml 에 쓰고, source.kustomize.images 로 nginx=nginx:1.28-alpine 을 지정해 적용하세요. Deployment prod-api 가 2개 파드·이미지 1.28 로 Healthy 여야 합니다.
  5. /root/capa-src/repo/waves 에 네 파일을 커밋·push 하세요. ConfigMap settings(sync-wave -1), readinessProbe 가 있는 Deployment app(sync-wave 0, 이미지 nginx:1.27-alpine), Job smoke(sync-wave 1, busybox:1.36 이 echo smoke ok), PreSync 훅 Job(generateName migrate-, hook-delete-policy BeforeHookCreation, busybox:1.36 이 echo migrate ok)입니다. Application src-waves(경로 waves, 대상 네임스페이스 src-waves, 자동 동기화·CreateNamespace)를 /root/capa-src/app-src-waves.yaml 로 적용하고 Synced·Healthy·작업 Succeeded 를 확인하세요. 그 시점의 관찰을 /root/capa-src/waves.jsonhook_job(성공한 PreSync 훅 Job 이름), hook_created(그 Job 의 creationTimestamp), settings_created(ConfigMap settings 의 creationTimestamp)로 남깁니다.
  6. 한 커밋에서 waves/config.yaml 의 mode 를 green 으로, waves/migrate.yaml 의 명령을 echo migrate failed; exit 1 로 바꿔 push 하고 src-waves 를 hard refresh 하세요. 작업이 실패한 것을 보고 /root/capa-src/failed-hook.jsoncommit(그 커밋 SHA), phase(status.operationState.phase), live_mode(src-waves 의 ConfigMap settings 의 mode)를 적습니다. 그다음 migrate 명령만 원래대로 되돌린 새 커밋을 push 하고(mode 는 green 유지), 필요하면 실패한 작업을 끝낸 뒤 src-waves 가 새 커밋에 Synced·Healthy·Succeeded 가 되어 mode 가 green 으로 바뀌게 하세요.
  7. src-kust 에 ignoreDifferences(group apps, kind Deployment, jsonPointers /spec/replicas)와 syncOptions RespectIgnoreDifferences=true 를 더해 다시 적용하세요(자동 동기화·selfHeal 은 유지). 그다음 kubectl scaleprod-api 를 4 로 늘리고 40초 이상 기다린 뒤에도 replicas 가 4 이고 src-kust 가 Synced 인 것을 확인해 /root/capa-src/ignore.jsonscaled_at(scale 직후 유닉스 초), checked_at, replicas(확인 시점 값, 숫자), sync_status 를 적으세요.
  8. /root/capa-src/report.jsonhelm_winner(greeting 을 정한 곳: chart·valueFiles·valuesObject·parameters 중 하나), replicas_winner(replicaCount 를 정한 곳, 같은 선택지), helm_installed(Helm 릴리스가 만들어졌는지, 불리언), image_source(prod-api 이미지 1.28 이 정의된 곳: git 또는 application), hook_blocked_sync(6단계 실패 때 mode 가 바뀌지 않았는지, 불리언), replicas_owner(prod-api 의 spec.replicas 필드를 지금 소유한 managedFields 관리자 이름)를 적으세요.

참고

차트를 Git 에 두고 Application 으로 가리킨다

베어 저장소 /srv/bare/src.git 을 만들고 /root/capa-src/repo 로 복제해 charts/web 에 Helm 차트를 커밋·push 하세요. Chart.yaml(name web, version 0.1.0), values.yaml(replicaCount: 1, greeting: chart-default), values-prod.yaml(replicaCount: 2, greeting: from-values-file), 템플릿 두 개({{ .Release.Name }}-greeting ConfigMap 의 data.greeting, {{ .Release.Name }}-web Deployment 의 replicas·이미지 nginx:1.27-alpine)를 둡니다. /root/capa-src/app-src-helm.yaml 의 Application src-helm(저장소 git://gitd.gitsrv.svc.cluster.local:9418/src.git main·charts/web, 대상 네임스페이스 src-helm, 자동 동기화·CreateNamespace)에 helm.valueFiles: [values-prod.yaml] 를 주고 적용해 Synced·Healthy 를 확인하세요.

Argo CD 는 경로에 Chart.yaml 이 있으면 Helm 소스로 봅니다. 릴리스 이름을 따로 주지 않으면 Application 이름이 쓰입니다. 값 파일 경로는 차트 디렉터리 기준입니다.

values 파일은 2 인데 파드는 3개였다

src-helm 의 source.helm 에 valuesObject(replicaCount: 3, greeting: from-values-object)와 parameters(greeting = from-parameter)를 더해 다시 적용하세요. 동기화가 끝나면 /root/capa-src/precedence.jsonreplicas(src-helm 네임스페이스 Deployment src-helm-web 의 spec.replicas, 숫자)와 greeting(ConfigMap src-helm-greeting 의 값)을 적습니다.

같은 키가 차트 기본값·valueFiles·valuesObject·parameters 에 모두 있습니다. 어느 것이 이기는지는 추측하지 말고 클러스터에 실제로 만들어진 값을 읽으세요.

helm list 에는 아무것도 없다

Argo CD 는 차트를 렌더링해 적용할 뿐 Helm 릴리스를 만들지 않습니다. src-helm 네임스페이스의 Secret 중 타입이 helm.sh/release.v1 인 것의 개수와, ConfigMap src-helm-greeting 에 Argo CD 가 남긴 추적 표식을 확인해 /root/capa-src/tracking.jsonhelm_release_secrets(숫자), tracking_annotation(그 ConfigMap 의 argocd.argoproj.io/tracking-id 값), instance_label(라벨 app.kubernetes.io/instance 가 있으면 그 값, 없으면 null)을 적으세요.

helm install 은 네임스페이스에 릴리스 기록 Secret 을 남깁니다. Argo CD 가 자기 리소스를 알아보는 방법(tracking method)은 argocd-cm 의 application.resourceTrackingMethod 로 정해지며 이 판의 기본값을 직접 확인하세요.

Git 에는 1.27 인데 클러스터에는 1.28

/root/capa-src/repo/kust 에 Kustomize 구조를 커밋·push 하세요. base 에 Deployment api(replicas 1, 라벨 app: api, 이미지 nginx:1.27-alpine)와 kustomization, overlays/prod 에 base 를 가리키고 namePrefix: prod-, replicas 로 api 를 2 로 바꾸는 kustomization 을 둡니다. Application src-kust(경로 kust/overlays/prod, 대상 네임스페이스 src-kust, 자동 동기화·CreateNamespace)를 /root/capa-src/app-src-kust.yaml 에 쓰고, source.kustomize.images 로 nginx=nginx:1.28-alpine 을 지정해 적용하세요. Deployment prod-api 가 2개 파드·이미지 1.28 로 Healthy 여야 합니다.

Application 의 kustomize 필드는 Argo CD 가 kustomize edit 로 렌더링 직전에 덧씌웁니다. 이 값은 Git 이 아니라 Application 객체에 있다는 점을 기억해 두세요.

스모크 Job 은 앱이 준비된 뒤에야 생겼다

/root/capa-src/repo/waves 에 네 파일을 커밋·push 하세요. ConfigMap settings(sync-wave -1), readinessProbe 가 있는 Deployment app(sync-wave 0, 이미지 nginx:1.27-alpine), Job smoke(sync-wave 1, busybox:1.36 이 echo smoke ok), PreSync 훅 Job(generateName migrate-, hook-delete-policy BeforeHookCreation, busybox:1.36 이 echo migrate ok)입니다. Application src-waves(경로 waves, 대상 네임스페이스 src-waves, 자동 동기화·CreateNamespace)를 /root/capa-src/app-src-waves.yaml 로 적용하고 Synced·Healthy·작업 Succeeded 를 확인하세요. 그 시점의 관찰을 /root/capa-src/waves.jsonhook_job(성공한 PreSync 훅 Job 이름), hook_created(그 Job 의 creationTimestamp), settings_created(ConfigMap settings 의 creationTimestamp)로 남깁니다.

Argo CD 는 PreSync → Sync → PostSync 단계로 나누고, 한 단계 안에서는 웨이브 번호 순서로 적용하며 다음 웨이브로 가기 전에 앞 웨이브의 리소스가 Healthy 가 되기를 기다립니다. 채점기는 생성 시각과 Deployment 가 Available 이 된 시각을 비교합니다. BeforeHookCreation 훅 Job 은 다음 동기화 때 지워지므로 지금 이름과 시각을 기록해 두어야 나중에도 증거가 남습니다.

훅이 실패하자 바꾼 설정은 적용되지 않았다

한 커밋에서 waves/config.yaml 의 mode 를 green 으로, waves/migrate.yaml 의 명령을 echo migrate failed; exit 1 로 바꿔 push 하고 src-waves 를 hard refresh 하세요. 작업이 실패한 것을 보고 /root/capa-src/failed-hook.jsoncommit(그 커밋 SHA), phase(status.operationState.phase), live_mode(src-waves 의 ConfigMap settings 의 mode)를 적습니다. 그다음 migrate 명령만 원래대로 되돌린 새 커밋을 push 하고(mode 는 green 유지), 필요하면 실패한 작업을 끝낸 뒤 src-waves 가 새 커밋에 Synced·Healthy·Succeeded 가 되어 mode 가 green 으로 바뀌게 하세요.

PreSync 훅이 실패하면 그 동기화 작업은 Sync 단계로 넘어가지 않습니다. 자동 동기화는 실패한 revision 으로 재시도하며 다음 커밋을 막을 수 있으니 status.operationState.operation.sync.revision 을 보세요. core 모드 명령(argocd app terminate-op --core)은 현재 네임스페이스가 argocd 인 kubeconfig 가 필요합니다.

손으로 늘린 레플리카를 selfHeal 이 두고 본다

src-kust 에 ignoreDifferences(group apps, kind Deployment, jsonPointers /spec/replicas)와 syncOptions RespectIgnoreDifferences=true 를 더해 다시 적용하세요(자동 동기화·selfHeal 은 유지). 그다음 kubectl scaleprod-api 를 4 로 늘리고 40초 이상 기다린 뒤에도 replicas 가 4 이고 src-kust 가 Synced 인 것을 확인해 /root/capa-src/ignore.jsonscaled_at(scale 직후 유닉스 초), checked_at, replicas(확인 시점 값, 숫자), sync_status 를 적으세요.

ignoreDifferences 만 두면 비교에서만 빠지고, 다른 이유로 동기화가 일어날 때 Git 의 값으로 덮일 수 있습니다. RespectIgnoreDifferences 는 동기화 때도 그 필드를 건드리지 않게 합니다. HPA 가 레플리카를 관리하는 앱의 흔한 설정입니다.

Git·Application·클러스터 중 누가 값을 정했나

/root/capa-src/report.jsonhelm_winner(greeting 을 정한 곳: chart·valueFiles·valuesObject·parameters 중 하나), replicas_winner(replicaCount 를 정한 곳, 같은 선택지), helm_installed(Helm 릴리스가 만들어졌는지, 불리언), image_source(prod-api 이미지 1.28 이 정의된 곳: git 또는 application), hook_blocked_sync(6단계 실패 때 mode 가 바뀌지 않았는지, 불리언), replicas_owner(prod-api 의 spec.replicas 필드를 지금 소유한 managedFields 관리자 이름)를 적으세요.

앞 단계에서 남긴 JSON 과 클러스터의 managedFields 를 근거로 합니다. kubectl get --show-managed-fields -o json 에서 f:spec 아래에 f:replicas 를 가진 항목을 찾으세요. status 의 replicas 는 컨트롤러가 씁니다.