Shakedown 초기에는 사용자가 배포 구성을 추천받아 저장하는 기능과 고정 설정을 쓰는 AWS 실험이 분리돼 있었습니다. large를 선택해도 그 선택이 실제 태스크 수나 메모리로 이어진다는 보장이 없었습니다. 저는 저장한 계획을 서버의 실행 설정에 연결하고, 생성된 자원과 장애 뒤 상태까지 확인하는 작업을 맡았습니다.
연결 과정에서 설정값만 맞추면 끝나지 않는 문제도 드러났습니다. Spring은 약 41초 뒤 기동하는데 health 유예는 30초였고, 중지는 외부 엔진이 120초에 포기했습니다. 준비된 앱만 공개하고 실제 중지가 끝난 뒤 응답하려면, 각 단계의 시간 예산부터 맞춰야 했습니다.
이 작업은 SoftBank Hackathon의 Emerald 팀에서 진행했습니다. 초기 AWS 어댑터는 팀원이 만든 기반이며, 제 기여는 ECR·계획 적용 연결과 기동·공개·중지 조건의 수정·검증입니다. 구현과 실험 실행에는 AI를 활용했습니다. 변경은 PR #12에 포함됐습니다.
저장된 계획을 다시 검증한 뒤 실행했습니다
클라이언트가 보낸 CPU나 태스크 수를 그대로 실행하면 추천과 실행의 계약을 우회할 수 있습니다. architecture_plan_id로 최신 선택인지, 같은 프로젝트와 분석 근거를 가리키는지 다시 확인한 뒤 서버 카탈로그를 적용하도록 연결했습니다. 선택을 저장하는 요청만으로 자원이 생성되는 구조도 아니었습니다. 이 검증은 사전에 준비한 기반 스택을 사용하며, 빈 AWS 계정에서 모든 기반 자원을 자동 구성한 결과는 아닙니다.
계획을 전달한 다음에는 자원이 생성되는 순서를 맞춰야 했습니다. 준비 전 접근을 막으려고 ALB 기본 동작을 403으로 바꾸면 ECS 생성에 필요한 target group 연결도 깨졌습니다. 저는 기본 forward 연결은 유지하고 별도의 우선순위 1 규칙으로 공개를 제어하는 쪽을 택했습니다. 준비 중 접근 차단과 ECS가 요구하는 연결을 동시에 만족시키기 위해서입니다.
기동과 중지도 같은 방식으로 실제 상태를 기준으로 다시 맞췄습니다.
| 만난 문제 | 바꾼 부분 | 지킨 조건 |
|---|---|---|
| 준비 전 ALB 403 차단이 ECS 생성 실패로 연결 | 기본 forward 연결 유지, 우선순위 1 규칙에서 403·공개 제어 | 준비 중 차단과 target group 연결을 함께 유지 |
| Spring 기동 약 41초, health 유예 30초 | 유예를 120초로 조정 | 건강 검사를 끄지 않음 |
| 중지 차단은 됐지만 120초 뒤 502 | 어댑터 600초, 외부 엔진 630초로 조정 | 상태 수렴을 기다린 뒤 응답 |
Spring의 기동 시간을 보고 health 검사를 끄는 대신 유예만 120초로 늘렸습니다. 공개 역시 요청 성공 직후가 아니라 실제 healthy 태스크와 AZ를 확인한 뒤 허용했습니다.
중지에서는 내부 어댑터보다 외부 엔진이 먼저 기다리기를 포기하지 않게 600초·630초로 순서를 맞췄습니다. 수정 뒤 large 중지는 189.70초에 HTTP 204, 서비스 INACTIVE, running/pending 0으로 끝났습니다. 이 관측값만 봐도 앞의 120초 제한으로는 해당 작업을 끝까지 기다릴 수 없었습니다. 다만 앞선 medium의 502와 수정 뒤 large 성공은 서로 다른 실행 기록입니다. 실제 배포 보고서에 당시 결과가 있습니다.
설정값과 실제 상태를 대조했습니다
2026년 10월 9일 검증은 FastAPI TestClient에서 이미지·ECR·AWS로 이어지는 경로였고, use_ai=false로 실행했습니다. 브라우저부터 LLM까지 모두 포함한 시험은 아닙니다.
| 항목 | medium | large |
|---|---|---|
| 태스크당 CPU | 1 vCPU | 2 vCPU |
| 태스크당 메모리 | 2GiB | 4GiB |
| 정상 태스크 / AZ | 2개 / 2개 | 3개 / 3개 |
| RDS | Single→Multi-AZ | Single→Multi-AZ |
| CPU 60% 확장 범위 | 2–4개 | 3–12개 |
| 세션·쓰기·조회 | 교차 인스턴스 통과 | 세 인스턴스 통과 |
이 표는 카탈로그대로 실제 자원이 설정되고 샘플의 세션·데이터 경로가 동작했는지의 확인입니다. large의 DB도 db.t3.micro였으며, 최대 12태스크나 대표 운영 부하를 시험한 결과는 아닙니다.
복구 시간에는 무엇이 포함됐는가
태스크 3개가 서로 다른 AZ에 있다는 사실만으로 장애 뒤에도 세션과 데이터가 유지된다고 말할 수는 없습니다. 그래서 태스크 강제 종료, CPU 부하, RDS 강제 AZ 전환을 나눠 별도 장애·확장 시험을 진행했습니다.
| 시험 | 관측 결과 | 읽을 때의 제한 |
|---|---|---|
| large 태스크 강제 종료 | 58.69초 뒤 healthy 3개·3 AZ, 세션·데이터 유지 | 요청부터 관측까지 폴링·API 지연 포함 |
| CPU 자동 확장 | desired/running 2→4, 96.53초에 healthy ≥3, 이후 4개 | 확장 확인이며 축소 검증은 별개 |
| RDS 강제 AZ 전환 | 71.57초 뒤 기존 데이터 조회·같은 세션 추가 쓰기 | 실패 폴링과 healthy 0 구간 존재 |
태스크 장애 뒤에는 3개 AZ의 healthy 상태로 돌아왔고, RDS 전환 뒤에는 같은 세션으로 기존 데이터를 읽고 새로 쓸 수 있었습니다. 다만 RDS 시험에는 요청 실패와 healthy 0 구간이 있었으므로 무중단 결과는 아닙니다. 58.69초와 71.57초도 폴링·API 시간을 포함한 관측값으로, 정밀 RTO나 운영 SLA와 구분해야 합니다.
자동 확장은 2→4를 확인했지만 축소는 남았습니다. 처음 16분 동안 축소되지 않았고, 추가 관측에서는 자원 정리가 시작돼 유효한 재시험이 아니었습니다. 확장 성공을 근거로 축소까지 완료 처리하지 않았습니다.
앱 중지는 기반 자원 삭제와 달랐습니다
앱이 중지됐다고 RDS·ALB 등의 기반 스택이 삭제되는 것은 아닙니다. DB 변경의 자동 롤백도 제공하는 결과가 아닙니다. 시간 예산 역시 해당 샘플의 실제 기동·중지 관측을 토대로 정한 값입니다. 최소 IAM이나 전체 브라우저 E2E는 이번 확인 범위 밖에 남겼습니다.
처음의 공백은 사용자의 선택과 실제 AWS 실행이 떨어져 있다는 점이었습니다. 계획 ID를 서버 카탈로그에 연결한 뒤에는 생성된 자원으로 그 선택을 확인했고, 배포·공개·중지마다 기다려야 할 상태를 따로 정했습니다. 장애 시험은 그다음 질문이었습니다. 설정이 적용되는 것, 앱이 준비되는 것, 장애 뒤 데이터를 다시 쓸 수 있는 것을 각각 확인해야 배포 기능의 완료 범위를 설명할 수 있었습니다.