CNPE — 클라우드 네이티브 플랫폼 엔지니어 (전문가) · Synced인데 서비스는 왜 멈췄을까 · 실습
Synced인 장애를 만들고 Git으로 복구하기
목표
실제 k3s·Argo CD에서 정상 배포 → readiness 고장 → Git revert 복구를 수행합니다.
이후 새 배포를 승인할 때 무엇을 확인해야 하는지 코드로 만듭니다.
왜 중요한가
GitOps는 잘못된 선언도 충실하게 반영합니다. Synced와 서비스 가용성을 분리하지 않으면
고장을 성공으로 승인하게 됩니다. 이번에는 실제 프로세스·EndpointSlice·Service HTTP를
관측합니다. Recreate·레플리카 1은 일부러 장애를 명확하게 보기 위한 실험 조건이며
운영 가용성 권장 구성이 아닙니다. stateless 웹 설정 복구이지 DB 복구나 무중단 카나리
검증은 아닙니다. 이 VM 밖의 클러스터나 Git 저장소에는 명령을 실행하지 마세요.
준비된 것
- 개인 VM 안의 k3s v1.36.4+k3s1, Argo CD v3.5.2, nginx 이미지, cnpe-shop 네임스페이스
- Git 작업 사본
/srv/gitops, 푸시 대상/srv/bare/app.git - Argo가 읽는 URL
git://gitd.gitsrv.svc.cluster.local:9418/app.git - 읽기 전용 관측 도구
python3 /opt/fixtures/cnpe-gitops-lab/evidence.py
첫 준비는 수분이 걸릴 수 있습니다. 학습 예상 시간은 55분이며, 더 필요하면 만료 전에
시간을 연장하세요. 세션 종료 후 VM과 파일은 회수되므로 필요한 기록은 미리 내려받습니다.
단계
1. /srv/gitops/app/release.json에 cnpe-shop/web Deployment와 Service를 v1 List로 작성합니다. 레플리카 1, Recreate, 진행 기한 20초, 컨테이너 web, 이미지 docker.io/library/nginx:1.27-alpine, 라벨·선택자 app=web, Service 80→80을 사용하세요. 컨테이너 시작 시 nginx index.html에 줄바꿈 없이 labhub-cnpe-v1을 쓰고 nginx를 실행합니다. readiness는 /·80, 주기 2초·실패 임계 1, request는 25m/32Mi, limit은 200m/128Mi입니다. 커밋·푸시하고 전체 SHA를 /root/cnpe/baseline.sha에 저장하세요.
2. /root/cnpe/project.json에 argocd 네임스페이스의 AppProject cnpe-delivery를, /root/cnpe/application.json에 Application cnpe-shop을 작성하고 적용하세요. 프로젝트는 준비된 Git URL 하나·cnpe-shop 목적지·Deployment/Service만 허용하고 클러스터 범위 허용 목록은 비웁니다. Application은 이 프로젝트, Git의 app 경로, 최초 전체 SHA, in-cluster 목적지, 자동 동기화·prune·selfHeal을 사용합니다.
3. 관측 도구로 최초 SHA의 Synced·Healthy·레플리카/엔드포인트 1·HTTP 200과 정확한 본문을 확인하고 /root/cnpe/baseline.json에 저장하세요. 이 파일은 이후에도 최초 성공의 기록으로 유지합니다.
4. Git 매니페스트의 readiness 경로만 /not-ready로 바꿔 새 커밋을 푸시하고 전체 SHA를 /root/cnpe/bad.sha에 저장하세요. Application targetRevision도 이 SHA로 갱신하고 새 Git을 읽도록 refresh합니다. Deployment를 직접 patch하지 않습니다.
5. Synced지만 Degraded, ProgressDeadlineExceeded, ready/available/엔드포인트 0, HTTP 실패가 된 것을 관측하고 /root/cnpe/failed.json에 저장하세요. 내용을 추측해 쓰지 말고 실제 API·요청 결과를 수집합니다.
6. 고장 커밋을 git revert하여 최초 매니페스트와 같은 내용을 가진 새 복구 커밋을 만드세요. 푸시하고 전체 SHA를 /root/cnpe/recovered.sha에 저장한 뒤 Application도 이 새 SHA로 갱신하세요. 과거 이력을 지우거나 최초 SHA로 강제 되감지 않습니다.
7. 새 복구 SHA에서 다시 Synced·Healthy·레플리카/엔드포인트 1·정확한 HTTP 응답을 확인해 /root/cnpe/recovered.json에 저장하세요. 채점은 저장 파일과 현재 서비스 양쪽을 확인합니다.
8. /root/cnpe/release-gate.py를 작성하세요. 인자는 상태 JSON 경로·기대한 전체 SHA·기대한 HTTP 본문입니다. 아래 승인 계약이 모두 맞으면 종료 코드 0, 아니면 0이 아닌 값으로 종료합니다. 상태 파일은 수정하지 마세요. 현재 정상 상태와 필드별 오류·누락 반례를 모두 검사합니다.
8단계 승인 계약
- 기대 SHA는 40자리 소문자 16진수이며 target_revision·observed_revision 양쪽과 일치
- sync=Synced, health=Healthy
- replicas·updated·available·ready·ready_endpoints가 각각 정수 1 (불리언·문자열은 거절)
- generation은 양의 정수, observed_generation도 정수이고 서로 일치
- http_code=200이고 http_body가 기대 본문과 정확히 일치
- 위 필수 필드가 하나라도 없거나 다르면 거절. progress_deadline_exceeded는 이 승인 계약의 필수 필드가 아님
참고
관측은 .../evidence.py observe, 조건 대기는 .../evidence.py wait healthy 전체SHA
또는 .../evidence.py wait failed 전체SHA입니다. >로 해당 단계의 JSON 파일에 저장합니다.
최대 45초 내에 조건이 안 맞으면 오류를 보여 주므로, API·프로브·이벤트를 확인한 뒤 다시
실행하세요. 대기 명령은 배포를 대신하거나 상태를 고치지 않습니다.
1·3·4·5·6단계는 Git 이력과 보존한 관측 기록을 검사합니다. 복구했다고 과거 장애
기록을 지우지 마세요. 2단계는 현재 배선·권한도, 7·8단계는 현재 서비스도 재검사합니다.
따라서 전체 채점은 복구 후에도 통과할 수 있습니다. 기록 JSON은 학습 기록이며 위조
방지 증명은 아닙니다. 8단계 채점은 임시 복사본으로 반례를 넣고 학생 파일을 수정하지 않습니다.
- [자동 동기화·selfHeal](https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/)
- [Git 추적 전략](https://argo-cd.readthedocs.io/en/stable/user-guide/tracking_strategies/)
- [Deployment 상태·진행 기한](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
단계 8개
- Git에 정상 릴리스 남기기
- 허용 범위를 좁혀 Application 연결
- 최초 성공의 증거 수집
- 유효하지만 잘못된 배포 만들기
- Synced인 장애를 관측
- Git 이력을 보존하며 복구
- 새 커밋과 실제 응답 대조
- 빈 증거를 승인하지 않는 게이트