개념
웹 서비스 QA의 감각이 어디서 어긋나는가
웹 서비스 QA에서 결함은 대개 요청 한 번의 응답 에서 드러난다. 버튼을 누르면 화면이 틀리거나, API를 부르면 응답이 틀린다. 인프라
플랫폼에서는 응답이 맞아도 결함일 수 있다. 서버 생성 API는 202 Accepted 를 돌려주고 끝난다. 결함은 그 뒤 몇 초에서 몇 분 사이, 사용자가
보지 않는 곳에서 일어난다.
[웹 서비스] [인프라 플랫폼]
요청 → 응답 (결과가 응답에 있다) 요청 → 202 → ... 스케줄링 → 이미지 복사 → 네트워크 연결 → ACTIVE
↑ 어느 단계에서든 멈추거나, 되돌려지지 않거나,
다른 테넌트의 자원을 건드릴 수 있다여기서부터 이 모듈이 계속 쓰는 말들이 나온다. 지금 외울 필요는 없고, 읽다가 막히면 이 표로 돌아오면 된다.
| 말 | 무엇인가 |
|---|---|
| 클라우드 | 서버·저장소를 사서 두지 않고 남의 것을 빌려 쓰는 방식 |
| Private Cloud | 그 빌려 쓰는 구조를 회사가 자기 장비로 직접 만들어 쓰는 것 |
| Kubernetes(쿠버네티스) | 컨테이너 수천 개를 어디에 띄우고 언제 다시 띄울지 자동으로 관리하는 도구 |
| OpenStack | 서버·네트워크·저장소를 빌려 주는 기능을 직접 운영할 수 있게 만든 공개 소프트웨어 |
| GPUaaS | 그래픽처리장치를 시간 단위로 빌려 주는 서비스 |
| 워크로드 | 그 위에서 실제로 돌아가는 일거리 — 학습 작업, 서비스, 배치 처리 |
| 쿼터 | "이 고객은 여기까지만" 하고 걸어 둔 사용 한도 |
| 수렴 | 요청한 상태에 실제로 도달해 더 이상 바뀌지 않는 것 |
202 Accepted 라는 응답 코드도 위 그림에 나온다. "요청은 접수했다, 다 됐다는 뜻은
아니다" 라는 뜻이다. 이 모듈의 결함이 거의 다 이 말 뒤에서 생긴다.
Private Cloud 관리 플랫폼, GPUaaS, AI 학습·추론 플랫폼은 모두 이 구조다. 이 모듈의 첫 문장은 이것이다. 인프라 플랫폼의 결함은 응답이 아니라 수렴하지 않는 상태와 남은 리소스로 드러난다.
제어 평면과 데이터 평면
인프라 플랫폼은 두 평면으로 나눠 보면 검증 대상이 정리된다.
| 제어 평면(control plane) | 데이터 평면(data plane) | |
|---|---|---|
| 하는 일 | 리소스를 만들고·바꾸고·지우라는 의도 를 받아 기록하고 조정한다 | 실제로 연산·저장·통신을 수행 한다 |
| 예 | 콘솔·API 서버, 스케줄러, 쿼터 서비스, Kubernetes API 서버와 컨트롤러, OpenStack Nova API | VM·컨테이너 안의 워크로드, GPU 연산, 스토리지 I/O, 테넌트 네트워크 트래픽 |
| 결함 모습 | 잘못된 상태 전이, 쿼터 계산 오류, 권한 누락, 정리되지 않은 리소스 | 성능 저하, 데이터 손상, 격리 실패, 장치 오류 |
| 주 검증 방법 | API·상태 검증 (이 모듈 레슨 2~4) | 성능·장애·장치 진단 (레슨 5~7) |
중요한 성질이 하나 있다. 제어 평면이 멈춰도 데이터 평면은 계속 돌아야 한다. API 서버가 재시작되는 동안 이미 실행 중인 학습 작업이나 추론 엔드포인트가 멈추면 안 된다. 이것 자체가 핵심 검증 기준이고, 레슨 7의 장애 주입에서 다시 본다.
요청이 아니라 상태를 검증한다 — 비동기 수렴
선언형 시스템(Kubernetes)이든 명령형 API(OpenStack)든, 인프라 리소스는 원하는 상태 와 현재 상태 를 갖고, 컨트롤러가 현재 상태를 원하는 상태로 끌고 간다. QA가 검증할 것은 "요청이 받아들여졌다"가 아니라 "정해진 시간 안에 원하는 상태로 수렴했고, 그 과정의 중간 상태가 허용된 것뿐이었다" 이다.
[서버 생성 상태 모델 — 검증 기준으로 쓴 것]
허용 경로: BUILD → ACTIVE
허용 경로: BUILD → ERROR (단, error 필드에 원인 코드 필수)
금지: ACTIVE → BUILD (사용자 조작 없이)
금지: BUILD 상태로 15분 초과 체류
수렴 시간: p95 90초 이하 (플레이버 gpu.a100.1, 이미지 캐시 적중 기준)
종료 후: ERROR 로 끝나면 포트·볼륨·예약된 GPU 가 60초 안에 반환이 기준을 테스트 코드로 옮길 때 가장 흔한 실수는 sleep(60) 한 뒤 상태를 한 번 보는 것이다. 모듈 13 레슨 5의 대기 전략이 인프라 검증에서
더 중요해진다.
def wait_for_status(get_status, target, allowed, timeout_s, interval_s=2):
"""상태를 폴링하며 전이 경로 전체를 기록한다."""
history = []
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
status = get_status()
if not history or history[-1] != status:
history.append(status)
if status not in allowed:
raise AssertionError(f"허용되지 않은 상태 {status}, 경로 {history}")
if status == target:
return history
time.sleep(interval_s)
raise AssertionError(f"{timeout_s}초 안에 {target} 미도달, 경로 {history}")이 함수가 하는 일은 셋이다. 경로를 기록 해서 실패 시 어디서 멈췄는지 보여준다. 허용되지 않은 중간 상태 를 즉시 실패로 잡는다. 타임아웃을 기준에서 가져온다(임의 값이 아니라). 폴링 간격이 너무 짧으면 API에 부하를 주고, 너무 길면 짧게 스쳐 간 금지 상태를 놓친다. 상태 변경 이벤트(Kubernetes watch, 알림 큐)를 구독할 수 있으면 폴링보다 정확하다.
부분 생성 누수와 부수 효과
인프라 리소스는 여러 하위 리소스로 조립된다. GPU 서버 하나에 포트·볼륨·보안 그룹 연결·GPU 예약·과금 이벤트가 따라온다. 생성이 중간에 실패하거나 삭제가 중간에 멈추면 일부만 남는다. 이것이 인프라 플랫폼에서 가장 자주, 가장 조용히 쌓이는 결함이다.
| 부수 효과 | 결함 모습 | 검증 방법 |
|---|---|---|
| 하위 리소스 | 생성 실패 후 포트·볼륨 잔존 | 요청 전후 하위 리소스 목록 차이 |
| 쿼터 카운터 | 실패했는데 사용량이 올라간 채 | 요청 전후 사용량 조회 |
| 과금·계량 | 삭제 후에도 사용량 이벤트 발생 | 삭제 후 일정 시간 계량 이벤트 없음 |
| 스케줄러 예약 | GPU가 예약된 채 반환 안 됨 | 노드의 할당 가능 GPU 수 |
| 감사 로그 | 거부·실패가 로그에 없음 | 이벤트 존재와 필드 |
실무에서 효과가 큰 방식이 테스트 전후 스냅샷 비교 다. 테스트 프로젝트의 리소스·사용량·할당량을 테스트 시작 전에 찍고, 테스트가 정리까지 끝낸 뒤 다시 찍어 비교한다. 차이가 있으면 제품 결함이거나 테스트의 정리 결함이다. 둘 다 기록할 가치가 있다. 테스트의 정리 결함도 결국 스테이징을 오염시켜 다른 테스트를 플래키하게 만든다.
멀티테넌시와 격리
Private Cloud 플랫폼은 여러 조직·팀·프로젝트가 같은 물리 자원을 나눠 쓴다. 격리 실패는 보안 사고다. 격리는 층마다 따로 검증한다.
| 층 | 검증 질문 |
|---|---|
| API 권한 | 다른 프로젝트 토큰으로 리소스를 조회·수정·삭제할 수 있는가. 존재 여부를 응답 코드 차이로 알아낼 수 있는가 |
| 쿼터 | 한 프로젝트가 다른 프로젝트의 쿼터를 소모시킬 수 있는가 |
| 네트워크 | 테넌트 네트워크 간 트래픽이 정책 없이 통하는가 |
| 스토리지 | 삭제된 볼륨의 블록이 다른 테넌트의 새 볼륨에서 읽히는가 |
| GPU | 공유 GPU(MIG·시분할)에서 다른 테넌트의 메모리·프로세스가 보이는가 (레슨 5) |
| 로그·메트릭 | 관측 화면에서 다른 테넌트의 이름·지표가 노출되는가 |
API 권한 검증에서 자주 놓치는 것이 존재 은닉 이다. 다른 프로젝트의 서버 ID로 조회했을 때 403 Forbidden 을 주면, 공격자는 그 ID의
리소스가 존재한다 는 것을 안다. 정책에 따라 404 로 통일하는 경우가 많다. 어느 쪽이 정책인지 확인하고 기준으로 쓴다(모듈 38 레슨 1의
"명세에 없어서 QA가 더해야 하는 기준").
소버린·에어갭 환경이 더하는 제약
데이터 주권을 보장하는 소버린 클라우드, 공공·금융·연구기관의 폐쇄망 설치형 플랫폼은 검증에 고유한 조건을 더한다.
| 제약 | 검증 영향 |
|---|---|
| 외부 인터넷 차단 | 설치·업그레이드가 외부 저장소 없이 완료되는가. 이미지·패키지·모델 가중치를 내부 레지스트리에서만 가져오는가 |
| 외부 SaaS 금지 | 테스트 도구·AI 판정자·관측 도구도 내부에서 돌아야 한다. 외부 LLM API를 쓰는 판정자는 이 환경에서 못 쓴다 |
| 데이터 반출 금지 | 테스트 증거(로그·스크린샷)에 고객 데이터가 섞이면 밖으로 가져올 수 없다. 증거 설계가 달라진다 |
| 버전 고정 | 고객이 몇 분기 뒤처진 버전을 쓴다. 여러 버전의 업그레이드 경로를 동시에 검증해야 한다 |
| 인증 요건 | CSAP·CC 등 인증 범위의 설정이 바뀌지 않았는가 (레슨 9) |
"외부 인터넷 차단 상태에서 설치가 끝나는가"는 의외로 자주 깨진다. 개발 환경에서는 누군가의 스크립트가 공용 저장소에서 헬름 차트나 파이썬 패키지를 조용히 받아 오기 때문이다. 네트워크를 실제로 끊은 환경에서의 설치 검증 을 릴리스 전 층에 둔다.
인프라 플랫폼 검증 기준의 뼈대
이 레슨의 내용을 기준 체크리스트 뼈대로 묶으면 모든 리소스 유형에 반복 적용할 수 있다.
리소스 유형 X 에 대해
[ ] 생성: 정상 수렴 시간, 허용 중간 상태, 실패 시 원인 코드
[ ] 생성 실패: 하위 리소스·쿼터·예약·과금 원상 복구
[ ] 수정: 실행 중 리소스에 대한 영향 (재시작 여부 명시)
[ ] 삭제: 하위 리소스 정리, 과금 중단, 삭제 중 실패 시 재시도 가능성
[ ] 동시성: 같은 리소스에 동시 수정·삭제, 멱등성 키
[ ] 격리: 다른 프로젝트 권한·쿼터·네트워크·스토리지·관측
[ ] 제어 평면 장애: 데이터 평면 워크로드 지속
[ ] 업그레이드: 이전 버전에서 만든 리소스 유지·조작 가능
[ ] 폐쇄망: 외부 의존 없음실무에서 왜 필요한가
GPU 클라우드에서 부분 생성 누수 하나가 남기는 비용은 웹 서비스의 화면 결함과 차원이 다르다. GPU 예약이 반환되지 않으면 수천만 원짜리 장비가 아무도 쓰지 않는데 가득 찬 상태 로 보인다. 과금 이벤트가 삭제 후에도 나가면 고객 신뢰와 정산 분쟁으로 이어진다. 이런 결함은 응답만 보는 테스트로는 절대 잡히지 않는다.
채용 공고의 "Private Cloud 관리·AI 학습·추론·AI 에이전트 플랫폼의 기능 검증"과 우대사항의 "Kubernetes/OpenStack, GPU·AI 워크로드 등 인프라 플랫폼 도메인에서 QA를 해 본 경험"이 요구하는 것은 도구 이름보다 이 감각이다. 면접에서 "API 테스트를 자동화했다"보다 "202 이후의 상태 경로를 기록하는 대기 함수로 BUILD 체류 결함을 잡았다", "테스트 전후 스냅샷 비교로 포트 누수를 찾았다"가 도메인 경험을 증명한다.