개념
선언형 시스템에서 "요청"은 원하는 상태를 적는 일이다
이 레슨에는 Kubernetes 고유의 말이 계속 나온다. 넷만 먼저 알아 두면 된다. 파드(Pod) 는 컨테이너 한두 개를 묶어 돌리는 가장 작은 단위, spec 은 "이렇게 되기를 원한다" 고 적는 칸, status 는 "지금 실제로 이렇다" 고 시스템이 적어 주는 칸, 컨트롤러 는 그 둘을 보고 현재를 원하는 쪽으로 끌고 가는 프로그램이다. 뒤에 나오는 CRD 는 Kubernetes 가 원래 모르는 새 종류의 자원을 직접 정의해 추가하는 장치이고, PVC 는 "이만큼의 저장 공간을 달라" 고 적어 두는 신청서다.
Kubernetes에서 사용자는 "파드를 만들어라"라고 명령하지 않는다. "이런 상태이기를 원한다"고 spec 에 적는다. 컨트롤러가 그것을 보고 현재 상태를 바꾼 뒤 status 에 결과를 적는다. 그래서 Kubernetes 위의 플랫폼 검증은 거의 모두 이 한 문장으로 요약된다.
spec에 적은 것이 status에 반영되었는가, 그리고 반영되는 과정이 허용된 방식이었는가.
레슨 1의 비동기 수렴 검증이 Kubernetes에서는 표준 필드로 제공된다. QA가 읽어야 할 필드는 정해져 있다.
| 필드 | 뜻 | 검증에서 쓰는 방법 |
|---|---|---|
metadata.generation | spec이 바뀔 때마다 올라가는 번호 | 내가 적용한 변경의 번호 |
status.observedGeneration | 컨트롤러가 마지막으로 처리한 spec 번호 | generation과 같아야 status를 믿을 수 있다 |
status.conditions[] | type·status(True/False/Unknown)·reason·message·lastTransitionTime | 판정의 1차 근거 |
| 이벤트 | 리소스에 대해 컨트롤러가 남긴 기록 | 실패 원인·경로 증거 |
observedGeneration을 확인하지 않으면 과거를 검증한다
가장 흔한 거짓 통과가 여기서 나온다.
1. 추론 엔드포인트 리소스의 replicas 를 2 → 4 로 수정 (generation 7 → 8)
2. 테스트가 곧바로 status 조회
3. status.conditions: Ready=True ← 하지만 observedGeneration 은 아직 7
4. 테스트 통과 판정3번의 Ready=True 는 replicas 2였던 과거 상태 의 판정이다. 컨트롤러는 아직 새 spec을 보지도 않았다. 판정 기준을 이렇게 쓴다.
판정: observedGeneration == generation 이고 conditions[type=Ready].status == "True"
그리고 Ready 조건의 lastTransitionTime 이 변경 적용 시각 이후마지막 줄은 Ready 가 한 번도 False로 내려가지 않고 True로 남아 있는 경우를 걸러낸다. 롤링 업데이트가 아예 시작되지 않았는데 이전 Ready를
보고 통과하는 경우다. 커스텀 리소스가 observedGeneration 을 제공하지 않는다면 그 자체를 결함 후보 로 올린다. 관측 가능성이 없는
리소스는 운영자도, 자동 판정자도 믿을 수 없다.
conditions를 기준으로 쓰기
Kubernetes API 규약은 conditions를 관측 가능한 상태의 사실 로 쓰라고 권한다. 플랫폼이 제공하는 커스텀 리소스의 conditions 설계 자체가 QA의 검토 대상이다.
# 학습 작업 커스텀 리소스의 status 예시
status:
observedGeneration: 3
conditions:
- type: Admitted # 쿼터 큐에 입장했는가 (레슨 5 Kueue)
status: "True"
reason: QuotaReserved
lastTransitionTime: "2026-09-16T01:02:03Z"
- type: Running
status: "True"
reason: AllWorkersReady
- type: CheckpointHealthy
status: "False"
reason: CheckpointWriteTimeout
message: "step 12000 checkpoint write exceeded 300s"이 status에서 QA가 뽑는 기준은 이렇다.
| 기준 | 판정 |
|---|---|
| 조건 타입 목록이 문서와 일치 | 문서에 없는 조건 타입이 나오거나, 문서의 조건이 안 나오면 실패 |
| False 조건에는 reason과 message 필수 | 빈 reason은 운영자가 원인을 알 수 없다 |
| reason 값은 열거형 | 자유 문자열이 섞이면 알림 규칙·대시보드가 깨진다 |
| 조건 간 모순 없음 | Running=True 인데 Admitted=False 는 불가능 |
| 전이 시각 단조성 | lastTransitionTime 이 뒤로 가지 않음 |
"조건 간 모순 없음"은 결정 테이블(모듈 3 레슨 3)로 전수 검증할 수 있다. 조건 네 개면 조합 16개 중 허용 조합을 표로 정의하고, 장애 주입 중 관측된 조합이 모두 허용 목록 안에 있는지 본다.
오퍼레이터 검증 — 조정 루프의 성질
GPU 플랫폼은 대부분 오퍼레이터 로 구성된다. NVIDIA GPU Operator, 학습 작업 오퍼레이터, 추론 서빙 오퍼레이터, 스토리지 오퍼레이터. 오퍼레이터는 커스텀 리소스를 감시하며 현재 상태를 원하는 상태로 끌고 가는 조정 루프(reconcile loop) 다. 조정 루프가 가져야 할 성질이 곧 검증 기준이다.
| 성질 | 검증 방법 |
|---|---|
| 수렴 | spec을 적용하면 정해진 시간 안에 Ready |
| 멱등성 | 같은 spec을 여러 번 적용해도 하위 리소스가 늘지 않는다 |
| 자기 치유 | 하위 리소스(Deployment·Service·ConfigMap)를 수동으로 지우거나 바꾸면 되살린다 |
| 소유권 | 하위 리소스에 ownerReference가 있고, 상위 삭제 시 함께 정리 |
| 삭제 완료 | finalizer가 정리를 마치고 제거되어 리소스가 Terminating에 멈추지 않는다 |
| 재시작 내성 | 오퍼레이터 파드를 조정 도중 죽여도 재시작 후 이어서 수렴한다 |
| 드리프트 복구 | 누군가 하위 리소스를 직접 수정하면 원하는 상태로 되돌리거나, 의도적으로 두는 필드는 문서화 |
finalizer에 멈춘 리소스 는 운영에서 매우 흔하다. 삭제를 요청했는데 영원히 Terminating으로 남는다. 원인은 대개 오퍼레이터가 외부 리소스(스토리지·DNS·과금) 정리에 실패하고 재시도를 멈춘 것이다. 삭제 테스트의 판정 기준에 "리소스 객체가 API에서 사라짐" 까지 넣어야 이 결함이 잡힌다.
재시작 내성은 레슨 7의 장애 주입과 이어진다. 조정 도중(하위 리소스 일부만 만든 시점)에 오퍼레이터 파드를 죽이는 시험은 부분 생성 누수와 중복 생성을 가장 잘 드러낸다.
테스트 클러스터 — PR마다 클러스터를 만들 수 있는가
모듈 38 레슨 4의 PR 층을 Kubernetes 플랫폼에서 돌리려면 PR마다 격리된 환경이 필요하다. 선택지는 비용과 충실도의 교환이다.
| 방식 | 충실도 | 비용·속도 | 적합한 용도 |
|---|---|---|---|
| kind (Docker 컨테이너를 노드로 쓰는 로컬 클러스터) | 제어 평면 동작은 실제와 같음. GPU·실제 네트워크·스토리지 없음 | 1~2분, 무료 | 오퍼레이터·CRD·조정 루프·API 검증 (PR 층) |
| 가상 클러스터 (호스트 클러스터 안의 격리된 제어 평면) | 제어 평면 격리, 호스트의 노드·GPU를 빌려 씀 | 수십 초, 호스트 자원 공유 | 실제 노드가 필요하지만 클러스터 전체는 과한 검증 |
| 네임스페이스 격리 (공유 스테이징) | 실제와 같음. 클러스터 범위 리소스 충돌 가능 | 즉시, 저렴 | CRD 설치가 필요 없는 워크로드 검증 |
| 전용 스테이징 클러스터 | 가장 높음 | 비쌈, 공유 | 회귀·릴리스 전 층 |
GPU가 필요한 기준을 kind에서 흉내 낼 때는 노드에 확장 리소스 를 광고해 스케줄링과 쿼터까지만 검증한다. 모듈 38 레슨 4에서 말한 "흉내 검증과 실물 검증을 기준 문서에 적는다"가 여기서 구체화된다.
nvidia.com/gpu 를 노드 status.capacity 에 패치로 광고 → 스케줄러는 GPU 가 있는 것처럼 파드를 배치
검증 가능: 쿼터 입장, 스케줄링 제약(노드 셀렉터·톨러레이션), 상태 전이, 삭제 후 할당 반환
검증 불가: 장치 플러그인 동작, CUDA 실행, MIG 분할, DCGM 지표 → 회귀 층의 실물 GPU 노드로버전 호환과 적합성 시험
Kubernetes는 대략 4개월마다 새 마이너 버전이 나온다. 2026년 8월 26일 v1.37이 나왔고, 상류 프로젝트는 최신 세 개 마이너 버전 정도를 지원한다. 설치형 Private Cloud 플랫폼은 고객이 쓰는 여러 버전에서 동작해야 하므로 호환 매트릭스 가 검증 계획의 뼈대가 된다.
[호환 매트릭스 — 릴리스 2026.38 후보]
k8s 1.35 k8s 1.36 k8s 1.37
GPU Operator 25.x ✓ 회귀 ✓ 회귀 ✓ 릴리스 전
GPU Operator 26.x — ✓ 회귀 ✓ 회귀
업그레이드 1.35→1.36 ✓ 릴리스 전 (실행 중 학습 작업 유지 기준 포함)
업그레이드 1.36→1.37 ✓ 릴리스 전
제거 예정 API 사용 0건 (정적 검사, 매 PR)마지막 줄이 중요하다. Kubernetes는 버전마다 베타 API를 제거한다. 플랫폼의 매니페스트·헬름 차트·오퍼레이터가 제거 예정 API를 쓰는지 를 매 PR에서 정적으로 검사하면, 고객이 클러스터를 올린 날 플랫폼이 설치되지 않는 사고를 막는다.
플랫폼이 클러스터를 직접 만들어 제공한다면(관리형 Kubernetes 기능), 그 클러스터가 Kubernetes 적합성(conformance) 을 만족하는지도 검증 대상이다. CNCF의 공인 Kubernetes 프로그램은 상류 적합성 테스트 결과 제출로 인증하며, Sonobuoy나 hydrophone 같은 도구로 적합성 스위트를 돌린다. 적합성 스위트는 오래 걸리므로 릴리스 전 층에 둔다.
pytest로 Kubernetes 상태 판정하기
판정 코드는 모듈 38 레슨 4의 판정 레코드를 내도록 짠다.
def assert_reconciled(api, kind, name, ns, timeout_s):
"""observedGeneration 과 Ready 조건을 함께 확인한다."""
obj = api.get(kind, name, ns)
applied_gen = obj["metadata"]["generation"]
applied_at = now_utc()
history = []
def ready():
o = api.get(kind, name, ns)
st = o.get("status", {})
conds = {c["type"]: c for c in st.get("conditions", [])}
snapshot = (st.get("observedGeneration"), conds.get("Ready", {}).get("status"))
history.append(snapshot)
if st.get("observedGeneration") != applied_gen:
return False
r = conds.get("Ready")
return r is not None and r["status"] == "True" and parse(r["lastTransitionTime"]) >= applied_at
if not poll(ready, timeout_s):
raise ReconcileTimeout(kind, name, applied_gen, history, api.events(kind, name, ns))실패 시 상태 이력과 이벤트 를 함께 남기는 것이 핵심이다. "Ready가 안 됐다"만으로는 결함 리포트를 쓸 수 없다. 이벤트에 "0/4 nodes are available: 4 Insufficient nvidia.com/gpu" 가 있으면 제품 결함이 아니라 환경 용량 문제로 바로 분류된다.
실무에서 왜 필요한가
Kubernetes 기반 AI 플랫폼 QA에서 "kubectl을 쓸 줄 안다"는 출발선일 뿐이다. 실제로 차이를 만드는 것은 status를 믿어도 되는 시점 을 아는 것, conditions 설계의 결함을 짚는 것, 오퍼레이터의 조정 루프 성질을 기준으로 바꾸는 것이다. observedGeneration을 보지 않는 테스트 스위트는 매일 통과하면서 매일 과거를 검증한다.
설치형 플랫폼 기업에서 호환 매트릭스와 제거 예정 API 검사는 고객 사고 예방 과 직결된다. 고객이 클러스터를 올리는 날 플랫폼이 멈추면, 그 원인이 상류 변경이라도 고객에게는 플랫폼 결함이다.