LabHub
배우기 러닝패스 코스

CAPA — Argo Project Associate

Trace missing files behind a green pipeline

LabHub 에서 이어서 보기

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

목표

업무 성공과 산출물 보존·정리 성공을 구분하고, 충돌 없는 키와 최소 권한으로 검증합니다.

왜 중요한가

업무가 성공해도 최종 파일이 사라지거나 중간 파일이 계속 쌓일 수 있습니다. 이 실습은 VM 안의 실제 Argo Workflows 4.1.3과 SeaweedFS 4.46을 사용합니다. 화면의 성공 표시가 아니라 실행 UID와 실제 파일 바이트, GC의 오류를 함께 확인합니다. 기본 클러스터와 저장소는 자동 준비되고, 학생은 정책을 수정하거나 비교 시나리오를 직접 실행합니다.

단계

  1. argo 네임스페이스의 artifact-repositories와 Service seaweed를 읽으세요. /root/capa-artifacts/inventory.json에 namespace=argo, endpoint=seaweed:8333, writer_bucket=artifacts, anonymous_allowed=false를 기록합니다. 채점은 실제 허용 계정의 파일 읽기, 익명 요청과 다른 팀 버킷 접근 거절도 대조합니다.
  2. 준비된 /root/capa-artifacts/isolated.yaml의 produce 출력 두 개에서 s3.key만 고칩니다. temporary는 runs/{{workflow.uid}}/temp.txt, final은 runs/{{workflow.uid}}/final.json입니다. 나머지 파이프라인과 최종 Never는 유지하고 실험 도우미로 isolated를 실행하세요. 서로 다른 두 Workflow의 UID와 최종 파일 내용을 비교합니다.
  3. isolated 두 실행의 완료 후 저장소를 확인합니다. /root/capa-artifacts/retention.json에 business=Succeeded, temporary=deleted, final=retained, final_policy=Never를 기록합니다. 두 최종 파일의 생산 UID가 다르고 A의 정리 시점에 B의 입력은 살아 있었는지 실험 기록도 확인하세요.
  4. 준비된 missing-retain.yaml은 최종 artifact의 Never를 일부러 뺐습니다. 도우미로 missing-retain을 실행한 뒤 /root/capa-artifacts/missing.json에 business=Succeeded, final_present=false, fix=Never를 기록하세요. 이 비교 실행의 YAML을 정상 정책으로 바꾸지 않습니다. 오류 원인과 고칠 필드를 설명하는 단계입니다.
  5. 준비된 gc-denied.yaml은 Role 없는 GC 계정 gc-denied를 사용합니다. 도우미로 gc-denied를 실행하고 /root/capa-artifacts/gc-error.json에 business=Succeeded, condition=ArtifactGCError, cause=RBAC, force_finalizer=false를 적습니다. 실제 forbidden 로그와 남은 두 파일을 읽고, finalizer를 지우지 않습니다.
  6. /root/capa-artifacts/gc-binding.yaml에 RoleBinding capa-gc-repair를 작성·적용하세요. 네임스페이스는 argo, roleRef는 apiGroup=rbac.authorization.k8s.io, kind=Role, name=artifact-gc이고 subjects는 argo의 ServiceAccount gc-denied 하나입니다. 기존 Role을 넓히지 말고 gc-repaired.yaml로 새 실행을 확인합니다. 원래 실패 Workflow의 기록과 finalizer는 보존합니다.
  7. collision.yaml의 shared/{{workflow.parameters.batch}} 키를 유지하고 도우미로 collision을 실행하세요. A의 입력이 B의 UID로 덮이고 A가 실패한 뒤, A의 GC가 B의 입력을 지워 B도 실패하는지 확인합니다. 두 Workflow의 Failed/Error는 이 비교의 기대 결과입니다. 단순히 파일을 지워 실패를 흉내 내지 않습니다.
  8. on-deletion.yaml은 OnWorkflowDeletion과 최종 Never를 함께 사용합니다. 도우미로 on-deletion을 실행하세요. 도우미는 성공 직후 파일을 관측하고, 정확한 Workflow UID를 확인해 그 Workflow만 삭제한 뒤 다시 관측합니다. 업무 완료 때는 두 파일이 있고 삭제 뒤에는 최종 파일만 남아야 합니다.
  9. /root/capa-artifacts/report.json에 lost_result_uid는 missing-retain의 실제 UID, gc_failure_uid는 gc-denied의 실제 UID를 적습니다. same_business_status=true, same_storage_result=false, status_is_retention_proof=false를 기록하세요. 두 Succeeded가 왜 다른 조치를 요구하는지 실제 파일 상태와 오류 계층을 근거로 설명합니다.

참고

정상 읽기와 거절할 읽기를 구분

argo 네임스페이스의 artifact-repositories와 Service seaweed를 읽으세요. /root/capa-artifacts/inventory.json에 namespace=argo, endpoint=seaweed:8333, writer_bucket=artifacts, anonymous_allowed=false를 기록합니다. 채점은 실제 허용 계정의 파일 읽기, 익명 요청과 다른 팀 버킷 접근 거절도 대조합니다.

저장소 참조의 endpoint와 bucket은 다른 필드입니다. 정상 요청이 성공하는지도 함께 확인합니다.

두 실행의 산출물 키를 분리

준비된 /root/capa-artifacts/isolated.yaml의 produce 출력 두 개에서 s3.key만 고칩니다. temporary는 runs/{{workflow.uid}}/temp.txt, final은 runs/{{workflow.uid}}/final.json입니다. 나머지 파이프라인과 최종 Never는 유지하고 실험 도우미로 isolated를 실행하세요. 서로 다른 두 Workflow의 UID와 최종 파일 내용을 비교합니다.

Kubernetes 이름이 달라도 저장소 key가 같으면 충돌합니다. UID를 로컬 파일명이 아니라 S3 key에 넣습니다.

중간 파일을 지우고 최종 결과는 보존

isolated 두 실행의 완료 후 저장소를 확인합니다. /root/capa-artifacts/retention.json에 business=Succeeded, temporary=deleted, final=retained, final_policy=Never를 기록합니다. 두 최종 파일의 생산 UID가 다르고 A의 정리 시점에 B의 입력은 살아 있었는지 실험 기록도 확인하세요.

OnWorkflowCompletion 기본 정책과 개별 final의 Never를 함께 봅니다. 관측 기록은 도우미 status에서 실행 이름을 찾은 뒤 확인할 수 있습니다.

최종 보존을 빠뜨린 성공 분석

준비된 missing-retain.yaml은 최종 artifact의 Never를 일부러 뺐습니다. 도우미로 missing-retain을 실행한 뒤 /root/capa-artifacts/missing.json에 business=Succeeded, final_present=false, fix=Never를 기록하세요. 이 비교 실행의 YAML을 정상 정책으로 바꾸지 않습니다. 오류 원인과 고칠 필드를 설명하는 단계입니다.

잘못된 설정이 업무 실패를 만들지 않을 수도 있습니다. 정상 isolated 결과와 이 실행의 최종 파일을 비교하세요.

업무 성공과 GC 권한 실패 분리

준비된 gc-denied.yaml은 Role 없는 GC 계정 gc-denied를 사용합니다. 도우미로 gc-denied를 실행하고 /root/capa-artifacts/gc-error.json에 business=Succeeded, condition=ArtifactGCError, cause=RBAC, force_finalizer=false를 적습니다. 실제 forbidden 로그와 남은 두 파일을 읽고, finalizer를 지우지 않습니다.

이 단계에서 실패해야 하는 것은 업무 컨테이너가 아니라 GC입니다. 권한을 붙이는 일은 다음 단계에서 합니다.

최소 GC 권한으로 새 실행 검증

/root/capa-artifacts/gc-binding.yaml에 RoleBinding capa-gc-repair를 작성·적용하세요. 네임스페이스는 argo, roleRef는 apiGroup=rbac.authorization.k8s.io, kind=Role, name=artifact-gc이고 subjects는 argo의 ServiceAccount gc-denied 하나입니다. 기존 Role을 넓히지 말고 gc-repaired.yaml로 새 실행을 확인합니다. 원래 실패 Workflow의 기록과 finalizer는 보존합니다.

GC에는 task list/watch와 task status patch만 필요합니다. status 권한은 --subresource=status로 확인합니다.

공유 키가 만드는 두 번의 실패

collision.yaml의 shared/{{workflow.parameters.batch}} 키를 유지하고 도우미로 collision을 실행하세요. A의 입력이 B의 UID로 덮이고 A가 실패한 뒤, A의 GC가 B의 입력을 지워 B도 실패하는지 확인합니다. 두 Workflow의 Failed/Error는 이 비교의 기대 결과입니다. 단순히 파일을 지워 실패를 흉내 내지 않습니다.

도우미는 같은 실험 시도의 두 실행에만 같은 batch를 줍니다. status에 나온 서로 다른 UID와 로그를 비교하세요.

완료 시점과 삭제 시점 비교

on-deletion.yaml은 OnWorkflowDeletion과 최종 Never를 함께 사용합니다. 도우미로 on-deletion을 실행하세요. 도우미는 성공 직후 파일을 관측하고, 정확한 Workflow UID를 확인해 그 Workflow만 삭제한 뒤 다시 관측합니다. 업무 완료 때는 두 파일이 있고 삭제 뒤에는 최종 파일만 남아야 합니다.

Workflow 삭제와 파드 삭제는 같은 사건이 아닙니다. finalizer 강제 제거 없이 삭제가 끝난 증거를 읽습니다.

같은 성공에 숨은 다른 저장 결과 보고

/root/capa-artifacts/report.json에 lost_result_uid는 missing-retain의 실제 UID, gc_failure_uid는 gc-denied의 실제 UID를 적습니다. same_business_status=true, same_storage_result=false, status_is_retention_proof=false를 기록하세요. 두 Succeeded가 왜 다른 조치를 요구하는지 실제 파일 상태와 오류 계층을 근거로 설명합니다.

도우미 status의 UID를 읽되 이름과 혼동하지 마세요. 최종 결과 유실과 임시 파일 정리 실패는 같은 장애가 아닙니다.