클라우드시스템 팀프로젝트 7조 | 임소정 · 남민서 · 위지우
기존 코딩 실습 채점 프로세스는 학생과 조교 모두가 로컬 PC와 Snowboard를 오가며 코드를 수동으로 업로드·다운로드·실행해야 하는 6단계의 비효율적인 구조였습니다.
Cloudemy는 이를 Kubernetes 위에서 2단계로 단축합니다.
| AS-IS (6단계) | TO-BE (2단계) |
|---|---|
| 로컬 PC 작성 → Snowboard 제출 → 코드 다운 → 로컬 실행·채점 → 결과 입력 → 피드백 확인 | 코드 작성·테스트·제출 → 점수·피드백·대시보드 확인 |
학생이 코드를 제출하면 Kubernetes Job이 자동으로 생성되어 채점을 수행하고, 결과를 즉시 학생과 조교에게 전달합니다. 모든 컴포넌트(Backend, Scheduler, Runner, DB, Cache)는 K8s 클러스터 위에서 선언적으로 관리됩니다.
- 온라인 코드 에디터 — 브라우저에서 코드 작성 및 실행
- K8s Job 기반 자동 채점 — 제출마다 독립된 Runner Pod가 Job으로 생성되어 채점 수행
- Scheduler — Redis 큐를 감시하며 K8s API로 Job을 동적으로 생성·관리
- HPA 자동 스케일링 — CPU/Memory 임계치 초과 시 Backend Pod 자동 확장 (min 1 / max 10)
- RBAC — Scheduler에 Job 생성 최소 권한만 부여
- Secret 관리 — API Key·인증 토큰을 K8s Secret으로 분리하여 보안 관리
- 실시간 피드백 — 채점 완료 후 학생에게 즉시 점수·피드백 제공
- 조교 대시보드 — 전체 제출 현황 및 채점 결과 한눈에 확인
User
|
Ingress (cloudemy.local)
/ \
Frontend (React) Backend (FastAPI)
:3000 :8000
/ | \
Redis MongoDB Scheduler
:6379 :27017 |
K8s Job
|
Runner Pod → OpenAI
- 노드 3개 — Master / Worker1 / Worker2로 Pod 분산 배치
- Frontend Pod → Backend Service를 호출하여 통신
- MongoDB — 영구 데이터 저장 (프로토타입: emptyDir, 이후 PVC 전환 예정)
- Redis — 인메모리 제출 큐 (
queue:submissions) - Scheduler — Redis 큐를 감시하고 Kubernetes Job 생성·관리
- Runner Pod — Job으로 생성되어 OpenAI API 호출 후 채점 결과를 Backend에 콜백
학생 코드 제출
→ Backend가 Redis 큐(queue:submissions)에 submission_id 적재
→ Scheduler가 큐를 감시하다 submission_id 수신
→ create_runner_job()으로 Kubernetes Job 스펙 생성
→ Runner Pod 자동 생성 (runner.py 실행)
→ OpenAI API로 코드 채점
→ Backend(http://backend:8000/internal)에 결과 콜백
→ 학생 화면에 점수·피드백 표시
| 레이어 | 기술 |
|---|---|
| Backend | FastAPI (Python 3.11), Docker Hub: withya61/cloudemy-backend |
| Scheduler | Python 3.11, Docker Hub: withya61/cloudemy-scheduler |
| Runner | Python 3.11, Docker Hub: withya61/cloudemy-runner |
| Database | MongoDB 6 (port 27017) |
| Cache / Queue | Redis 7 (port 6379) |
| Orchestration | Kubernetes (K8s) — Deployment, Service, Job, HPA, Secret, RBAC, Ingress |
| AI | OpenAI API (LLM 기반 채점) |
Backend-Cloudemy/
├── backend/ # FastAPI 서버
│ ├── app/
│ ├── dockerfile
│ └── requirements.txt
├── scheduler/ # Redis 큐 감시 + K8s Job 생성
│ ├── scheduler.py
│ ├── dockerfile
│ └── requirements.txt
├── runner/ # 채점 실행 (K8s Job으로 동작)
│ ├── runner.py
│ ├── dockerfile
│ └── requirements.txt
├── k8s/ # Kubernetes 매니페스트
│ ├── backend.yaml # Backend Deployment + Service + HPA
│ ├── mongo.yaml # MongoDB Deployment + Service
│ ├── redis.yaml # Redis Deployment + Service
│ ├── scheduler.yaml # Scheduler Deployment
│ ├── secret.yaml # LLM API Key + 내부 인증 토큰
│ └── rbac-scheduler.yaml
└── docker-compose.db.yml
| 리소스 | 내용 |
|---|---|
| kind: Deployment | replicas: 1, 포트 8000 |
| kind: Service | ClusterIP, 포트 8000 |
| kind: HPA | CPU 70% / Memory 80% 초과 시 자동 스케일 (min: 1, max: 10) |
환경 변수로 MongoDB URI, Redis URL, K8s Namespace, Runner 이미지, Backend 내부 URL 주입.
cloudemy-secret에서 LLM_API_KEY, INTERNAL_RESULT_TOKEN 참조.
backend-deploy를 대상으로 Pod 수 자동 조절- CPU 사용률 70% 또는 메모리 사용률 80% 초과 시 자동으로 Pod 확장
- 최소 1개 ~ 최대 10개까지 자동 스케일 아웃
- 도메인:
cloudemy.local(nginx Ingress Controller) /→frontend-service:80/api→backend-service:8000
- 공식 이미지
mongo:6, 포트 27017 - ClusterIP Service로 내부 통신 (
mongodb://mongo:27017) - 현재 emptyDir 볼륨 사용 (향후 PVC 전환 예정)
- 공식 이미지
redis:7, 포트 6379 - ClusterIP Service (
redis://redis:6379)
- Redis 큐
queue:submissions감시 - K8s API 호출로 Runner Job 동적 생성
cloudemy-secret에서 LLM_API_KEY, INTERNAL_RESULT_TOKEN 참조
# secret.yaml
LLM_API_KEY: <base64>
INTERNAL_RESULT_TOKEN: <base64>Backend / Scheduler / Runner에 envFrom으로 주입.
| 컴포넌트 | 이미지 |
|---|---|
| Backend | withya61/cloudemy-backend:latest |
| Scheduler | withya61/cloudemy-scheduler:latest |
| Runner | withya61/cloudemy-runner:latest |
kubectl apply -f k8s/secret.yamlkubectl apply -f k8s/rbac-scheduler.yamlkubectl apply -f k8s/mongo.yaml
kubectl apply -f k8s/redis.yaml
kubectl apply -f k8s/backend.yaml
kubectl apply -f k8s/scheduler.yaml/etc/hosts에 다음 추가 후 cloudemy.local로 접속:
<NODE_IP> cloudemy.local



