LabHub
学习 学习路径 课程

CAPA — Argo 项目认证助理

values 文件写的是 2,却起了 3 个 Pod

在 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 는 컨트롤러가 씁니다.