OVERVIEW
JPU-Share는 전북대학교 지능형 연산 자원 공유 플랫폼입니다. GPU 서버에 직접 접속하지 않고, 코드를 업로드하면 자동으로 GPU에서 실행되고 결과를 받아볼 수 있습니다.
유휴 GPU에서는 LLM 추론 서비스가 상시 운영되어, OpenAI 호환 API로 다양한 오픈소스 모델을 활용할 수 있습니다.
| GPU | VRAM | 수량 |
|---|---|---|
| NVIDIA RTX 3080 Ti | 12 GB | 6장 |
| NVIDIA RTX 4090 | 24 GB | 2장 |
| NVIDIA RTX Pro 6000 | 96 GB | 2장 |
ACCOUNT
관리자가 생성한 계정으로 로그인합니다. 계정이 없으면 관리자에게 요청하세요.
계정에는 세 가지 역할이 있으며, 역할은 조직 관리 권한에만 적용됩니다 — 연구실 관리, 멤버 추가/제거, 시스템 운영 등.
| 역할 | 범위 | 주요 기능 |
|---|---|---|
| Admin | 전체 시스템 | 모든 연구실/계정/GPU/작업 운영 관리 |
| Professor | 자기 연구실 | 멤버 작업 조회, 멤버 추가/제거, 사용량 확인 |
| Student | 본인 | 작업 제출/조회/취소, 연구실 정보 읽기 |
콘솔 사이드바의 "내 정보" 페이지에서 본인의 학번, 이름, 이메일, 역할, 소속 연구실 등을 확인할 수 있습니다.
같은 페이지에서 "비밀번호 변경" 버튼을 눌러 비밀번호를 변경할 수 있습니다. 현재 비밀번호를 입력한 후 새 비밀번호를 설정합니다.
교수(Professor) 이상의 역할은 콘솔 사이드바에 "연구실 관리" 탭이 표시됩니다.
멤버를 클릭하면 해당 멤버의 작업 목록을 모달로 확인할 수 있습니다.
JOB SUBMISSION
코드를 제출하는 방법은 두 가지입니다:
코드를 zip으로 묶어서 업로드합니다. main.py가 zip 루트에 위치해야 합니다.
my-project/ ├── main.py ← 엔트리포인트 ├── model.py ├── utils/ │ └── data.py └── config.yaml $ cd my-project $ zip -r ../my-project.zip .
제한: zip 최대 500 MB, 해제 후 10 GB, 파일 수 10,000 개
공개 Git 저장소 URL을 입력하면 시스템이 자동으로 clone합니다.
https://github.com/user/my-training.git
branch/tag를 지정할 수 있습니다 (기본: main).
| 항목 | 필수 | 설명 |
|---|---|---|
| 소스 코드 | 필수 | zip 파일 또는 Git URL |
| 실행 명령 | 선택 | 비워두면 python main.py 실행 |
| 인자 (args) | 선택 | 실행 명령에 추가할 인자 |
| 환경변수 | 선택 | KEY=VALUE 형식, 줄바꿈으로 구분 |
| GPU 수 | 선택 | 기본 1장, 최대 8장 (tier 제한 있음) |
| 워크스페이스 | 선택 | 자동 선택 또는 직접 지정 |
| 명령 | 설명 |
|---|---|
| (비워두기) | python main.py 실행 |
python train.py | 다른 파이썬 파일 실행 |
bash run.sh | 쉘 스크립트 실행 |
torchrun --nproc_per_node=2 train.py | Multi-GPU 분산 학습 |
시스템이 아래 환경변수를 자동으로 주입합니다. 값은 고정되어 있으므로 수정하지 말고 그대로 읽어서 사용하면 됩니다.
| 변수 | 설명 | 예시 |
|---|---|---|
JOB_OUTPUT_DIR | 결과물 저장 경로 — 여기에 저장해야 다운로드 가능 | /output |
JOB_SCRATCH_DIR | 임시 작업 공간 (노드 로컬 스토리지) | /scratch |
JOB_INPUT_PATH | 공유 입력 데이터 경로 | /data/shared |
JOB_ID | 작업 고유 ID | 01abc... |
JOB_ATTEMPT | 현재 시도 번호 (OOM 재시도 시 증가) | 1 |
NUM_GPUS | 할당된 GPU 수 — Multi-GPU 학습 시 활용 | 1 |
import os, json, torch
from pathlib import Path
output_dir = Path(os.getenv("JOB_OUTPUT_DIR", "."))
output_dir.mkdir(parents=True, exist_ok=True)
# 학습 후...
torch.save(model.state_dict(), output_dir / "model.pt")
with open(output_dir / "metrics.json", "w") as f:
json.dump({"loss": 0.42, "accuracy": 0.91}, f)
pip install, wget, wandb 로깅 등은 사용할 수 없습니다. 필요한 패키지는 워크스페이스에서 미리 설치하세요.
WORKSPACE
워크스페이스는 작업이 실행되는 환경입니다. 기본 환경(PyTorch + CUDA)으로 바로 시작할 수도 있고, 필요한 패키지를 추가한 커스텀 환경을 만들 수도 있습니다.
워크스페이스를 만들지 않아도 기본 환경이 자동으로 적용됩니다:
# 패키지 입력 예시 (한 줄에 하나씩) transformers>=4.40 wandb scipy>=1.12 scikit-learn matplotlib
pip 패키지 외에 시스템 패키지가 필요하면 셋업 스크립트를 입력할 수 있습니다:
# 예: ffmpeg 설치 apt-get update && apt-get install -y ffmpeg
작업 제출 시 워크스페이스는 다음 순서로 결정됩니다:
다른 사용자의 워크스페이스를 사용하려면, 해당 사용자에게 workspace snapshot ID를 받아서 작업 제출 시 직접 지정하면 됩니다.
| 항목 | 제한 |
|---|---|
| 사용자당 워크스페이스 수 | 최대 5개 |
| 동시 빌드 수 (사용자당) | 최대 3개 |
| 이미지 크기 | 최대 20 GB |
| 빌드 시간 | 최대 10분 |
RESULTS
| 상태 | 설명 |
|---|---|
USER_QUEUE_WAIT | 개인 대기열에서 차례를 기다리는 중 |
GLOBAL_QUEUE_WAIT | GPU 배정을 기다리는 중 |
ASSIGNED | GPU가 배정됨, 실행 준비 중 |
RUNNING | GPU에서 실행 중 |
SUCCEEDED | 정상 완료 |
FAILED_RUNTIME | 코드 오류로 실패 (exit code != 0) |
FAILED_ENV | 환경 오류 (패키지 누락 등) |
FAILED_OOM_CONFIRMED | GPU 메모리 부족 (OOM) 확인됨 |
FAILED_OOM_SUSPECT | OOM 의심 (정확한 확인 불가) |
ESCALATION_WAIT | OOM 후 더 큰 GPU 대기 중 (자동으로 대기열 재진입) |
CANCELLED | 사용자가 취소함 |
CANCEL_REQUESTED | 취소 요청됨, 처리 중 |
TIMED_OUT | 제한 시간 초과 |
FAILED_SUBMISSION | 제출 실패 (Slurm 오류 등) |
KILLED_BY_ADMIN | 관리자가 강제 종료함 |
콘솔의 "결과" 페이지에서 완료된 작업의 출력 파일을 확인하고 다운로드할 수 있습니다.
JOB_OUTPUT_DIR에 저장한 파일들"내 작업" 페이지에서 실행 중이거나 대기 중인 작업을 취소할 수 있습니다.
GPU MANAGEMENT
작업을 제출하면 시스템이 가장 좋은 GPU부터 가용 여부를 확인하고 배정합니다.
GPU 메모리가 부족하면(OOM) 해당 GPU는 "이 작업에 부족하다"고 판단하고, 더 큰 GPU에서만 재시도합니다:
재시도 시 JOB_ATTEMPT 환경변수가 증가합니다. 체크포인트 복원에 활용할 수 있습니다.
분산 학습이 필요하면 제출 시 GPU 수를 지정합니다 (기본 1장, 최대 8장). tier별로 최대 GPU 수가 다를 수 있습니다.
# Multi-GPU DDP 실행 예시 torchrun --nproc_per_node=2 train.py --epochs 50
GPU 배정은 연구실(Lab) 단위 사용량을 기반으로 우선순위가 결정됩니다.
콘솔의 "모니터" 페이지에서 GPU 사용률, 온도, 메모리 등을 실시간으로 확인할 수 있습니다. Grafana 대시보드가 임베드되어 있습니다.
플랫폼은 Prometheus 기반 알림 시스템을 운영하며, 다음 상황을 자동으로 감지합니다:
LLM SERVICE
유휴 GPU에 오픈소스 LLM이 자동으로 배포됩니다. 연구 작업이 들어오면 LLM이 자동으로 양보하고, 작업이 끝나면 다시 배포됩니다.
OpenAI Python SDK를 그대로 사용할 수 있습니다:
from openai import OpenAI
client = OpenAI(
base_url="https://jota.jbnu.ac.kr/v1/llm",
api_key="sk-xxxxxxxx" # 콘솔에서 발급
)
response = client.chat.completions.create(
model="auto", # 또는 모델명 생략 (자동 선택)
messages=[
{"role": "user", "content": "양자역학의 기본 원리를 설명해주세요."}
]
)
print(response.choices[0].message.content)
stream = client.chat.completions.create(
model="auto",
messages=[{"role": "user", "content": "Hello!"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
curl -X POST https://jota.jbnu.ac.kr/v1/llm/chat/completions \
-H "Authorization: Bearer sk-xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-3-8b",
"messages": [{"role": "user", "content": "Hello!"}]
}'
sk-...)를 복사합니다. 이 키는 한 번만 표시됩니다.사용자당 30 req/min으로 제한됩니다. 초과 시 429 응답을 받습니다.
| 엔드포인트 | 설명 |
|---|---|
POST /v1/llm/chat/completions | 자동 라우팅 — 최적 모델 선택 |
POST /v1/llm/models/{name}/chat/completions | 특정 모델 지정 |
GET /v1/llm/models | 현재 사용 가능한 모델 목록 |
GET /v1/llm/models/{name}/health | 모델 상태 확인 |
GET /v1/llm/status | GPU별 LLM 상태 |
REST API
콘솔 웹 UI의 모든 기능은 REST API로도 사용할 수 있습니다. 스크립트, CI/CD, 자동화 파이프라인에서 직접 작업을 제출하고 결과를 가져올 수 있습니다.
API 호출에는 JWT 토큰이 필요합니다. 콘솔 로그인과 동일한 계정을 사용합니다.
# 토큰 발급 TOKEN=$(curl -s -X POST https://jota.jbnu.ac.kr/v1/auth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password&client_id=gpu-platform-api&username=YOUR_ID&password=YOUR_PW" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") # 이후 모든 API 호출에 사용 curl -H "Authorization: Bearer $TOKEN" https://jota.jbnu.ac.kr/v1/jobs
# zip 파일로 작업 제출 curl -X POST https://jota.jbnu.ac.kr/v1/jobs \ -H "Authorization: Bearer $TOKEN" \ -F "artifact=@my-project.zip" # 실행 명령과 환경변수 지정 curl -X POST https://jota.jbnu.ac.kr/v1/jobs \ -H "Authorization: Bearer $TOKEN" \ -F "artifact=@my-project.zip" \ -F "command=python train.py" \ -F "args=--epochs 50 --lr 0.001" \ -F "env=WANDB_MODE=offline"
curl -X POST https://jota.jbnu.ac.kr/v1/jobs \ -H "Authorization: Bearer $TOKEN" \ -F "git_url=https://github.com/user/my-training.git" \ -F "git_ref=main"
curl -H "Authorization: Bearer $TOKEN" \ https://jota.jbnu.ac.kr/v1/jobs
curl -H "Authorization: Bearer $TOKEN" \
https://jota.jbnu.ac.kr/v1/jobs/{job_id}
curl -X POST -H "Authorization: Bearer $TOKEN" \
https://jota.jbnu.ac.kr/v1/jobs/{job_id}/cancel
# 출력 파일 목록
curl -H "Authorization: Bearer $TOKEN" \
https://jota.jbnu.ac.kr/v1/jobs/{job_id}/outputs
# 전체 출력을 zip으로 다운로드
curl -H "Authorization: Bearer $TOKEN" -o output.zip \
https://jota.jbnu.ac.kr/v1/jobs/{job_id}/outputs-zip
# 개별 파일 다운로드
curl -H "Authorization: Bearer $TOKEN" -o model.pt \
https://jota.jbnu.ac.kr/v1/jobs/{job_id}/outputs/model.pt
import requests
BASE = "https://jota.jbnu.ac.kr"
# 토큰 발급
token = requests.post(f"{BASE}/v1/auth/token", data={
"grant_type": "password",
"client_id": "gpu-platform-api",
"username": "YOUR_ID",
"password": "YOUR_PW",
}).json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
# 작업 제출
with open("my-project.zip", "rb") as f:
resp = requests.post(f"{BASE}/v1/jobs",
headers=headers,
files={"artifact": f},
data={"command": "python train.py"},
)
job_id = resp.json()["job_id"]
print(f"Submitted: {job_id}")
# 상태 확인
status = requests.get(f"{BASE}/v1/jobs/{job_id}",
headers=headers).json()
print(f"State: {status['state']}")
# 결과 다운로드
resp = requests.get(f"{BASE}/v1/jobs/{job_id}/outputs-zip",
headers=headers)
with open("output.zip", "wb") as f:
f.write(resp.content)
| Method | Path | 설명 | 인증 |
|---|---|---|---|
| POST | /v1/auth/token | JWT 토큰 발급 | - |
| POST | /v1/jobs | 작업 제출 | JWT |
| GET | /v1/jobs | 내 작업 목록 | JWT |
| GET | /v1/jobs/{id} | 작업 상세 | JWT |
| POST | /v1/jobs/{id}/cancel | 작업 취소 | JWT |
| GET | /v1/jobs/{id}/outputs | 출력 파일 목록 | JWT |
| GET | /v1/jobs/{id}/outputs-zip | 출력 zip 다운로드 | JWT |
| GET | /v1/jobs/{id}/outputs/{path} | 개별 파일 다운로드 | JWT |
| POST | /v1/workspaces | 워크스페이스 생성 | JWT |
| GET | /v1/workspaces | 내 워크스페이스 목록 | JWT |
| PUT | /v1/workspaces/{id} | 워크스페이스 수정 | JWT |
| DELETE | /v1/workspaces/{id} | 워크스페이스 삭제 | JWT |
| POST | /v1/workspaces/{id}/activate | 기본 환경 설정 | JWT |
| POST | /v1/llm/chat/completions | LLM 채팅 | JWT / API 키 |
| GET | /v1/llm/models | 모델 목록 | JWT / API 키 |
| POST | /v1/llm/api-keys | API 키 생성 | JWT |
| GET | /v1/llm/api-keys | API 키 목록 | JWT |
| DELETE | /v1/llm/api-keys/{id} | API 키 폐기 | JWT |
| GET | /v1/labs/me | 내 연구실 정보 | JWT |
| GET | /v1/labs/me/members | 연구실 멤버 목록 | JWT |
| GET | /v1/labs/me/jobs | 연구실 멤버 작업 목록 (교수+) | JWT |
| GET | /v1/labs/me/usage | 연구실 사용량 | JWT |
| POST | /v1/labs/me/members | 멤버 추가 (PI/관리자) | JWT |
| DELETE | /v1/labs/me/members/{username} | 멤버 제거 (PI/관리자) | JWT |
| GET | /v1/auth/me | 내 프로필 및 역할 | JWT |
| POST | /v1/auth/change-password | 비밀번호 변경 | JWT |
FAQ
보안을 위해 작업 실행 중에는 외부 네트워크가 차단됩니다. 데이터는 /data/shared에 사전 배치하거나, 관리자에게 데이터 배치를 요청하세요. 사전학습 모델(YOLOv8 등)이 필요한 경우에도 관리자에게 문의하면 /data/shared/models/에 배치해 드립니다 (jedutools@gmail.com).
실행 중에는 네트워크가 차단되므로 pip install이 실패합니다. 워크스페이스에서 미리 패키지를 설치하세요. 워크스페이스 빌드 시에만 네트워크가 열립니다.
OOM 발생 시 더 큰 GPU에서 자동 재시도는 시스템 기본 동작입니다. 더 큰 GPU가 없으면 최종 실패합니다. 배치 크기를 줄이거나 모델을 경량화해 주세요. OOM 재시도는 사용량에 산정되지 않습니다.
기본 제한 시간은 워크스페이스 설정에 따르며, 최소 60초 ~ 최대 72시간입니다.
현재 작업 실행 중 외부 네트워크가 차단되어 wandb/mlflow 원격 로깅이 불가합니다. 로컬 파일로 기록한 뒤 JOB_OUTPUT_DIR에 저장하세요.
대기 시간은 현재 실행 중인 작업들에 따라 다릅니다. 연구실별 누적 사용량이 적을수록 우선 배정됩니다. "모니터" 페이지에서 GPU 사용 현황을 확인할 수 있습니다.
모든 GPU가 연구 작업에 사용 중이면 LLM 서비스가 일시 중단됩니다. 연구 작업이 완료되면 자동으로 복구됩니다.
추가 질문이나 계정 발급 요청: jedutools@gmail.com