본문으로 건너뛰기

코드스페이스 — 통합 개발환경

GenD 코드스페이스는 브라우저에서 바로 쓰는 개인 개발환경입니다. 하나의 코드스페이스가 JupyterLab 과 VS Code 를 동시에 제공하며 — 두 IDE 는 같은 컨테이너, 같은 홈 디렉토리를 공유하므로 노트북에서 만든 파일을 VS Code 에서 즉시 이어서 편집할 수 있습니다.

본 가이드는 Epic #2614 (M1) 의 산출물입니다. IDE 별 활용 시나리오는 IDE 선택 가이드 를 참조하세요.

사용 자격 — codespace-users 그룹

코드스페이스는 사용자마다 전용 컨테이너와 볼륨을 점유하므로, 명시적으로 자격을 부여받은 사용자만 생성할 수 있습니다 (#2659).

  • 자격은 Keycloak codespace-users 그룹 멤버십으로 관리됩니다.

  • 데이터 접근 역할(analyst 등)과는 별개입니다 — 데이터를 조회할 수 있어도 코드스페이스 자격이 없으면 생성되지 않습니다.

  • 자격이 없는 상태로 [시작]을 누르면 다음 안내가 표시됩니다:

    코드스페이스 사용 권한이 없습니다 — 'codespace-users' 그룹 소속이 필요합니다.

    이 경우 플랫폼 관리자에게 그룹 추가를 요청하세요.

자격 없는 계정의 코드스페이스 시작 거부 화면

자격이 없는 계정(analyst 역할 보유, codespace-users 미소속)으로 [시작]을 눌렀을 때의 실제 prod 화면입니다. 안내가 토스트와 상단 배너로 표시되고, 카드는 "시작 전" 상태로 되돌아가 재시도할 수 있습니다.

관리자 안내

자격 통제는 JupyterHub 인증자와 GenD API 양쪽에서 이중 시행됩니다. /jupyter 로 직접 로그인하는 경로와 GenD UI 경로가 각각 검사되므로 한쪽만 우회할 수 없습니다. 그룹 추가는 Keycloak 관리 콘솔 → 그룹 → codespace-users → Members 에서 수행합니다.

시작하기 — 단계별 가이드

아래 스크린샷은 prod 환경 E2E 로 캡처한 실제 화면입니다 (Epic #2614 검증). 아래 절차는 codespace-users 자격이 있는 사용자 기준입니다.

1. 코드스페이스 탭 이동

ML 허브 → 개발 → 코드스페이스 탭으로 이동합니다. 내 코드스페이스 카드에 현재 상태(중지됨/실행 중)와 마지막 활동 시각이 표시됩니다. 중지 상태여도 워크스페이스 (파일)는 보존되어 있습니다.

코드스페이스 카드 — 중지 상태

2. 프로필 선택

프로필 셀렉트에서 리소스 크기를 고릅니다 — Basic(1 CPU/2G) · Standard(2/4) · Large(4/8) · JupyterLab 경량(노트북 전용). 실행 중에는 변경할 수 없고, 중지 후 다시 시작할 때 바꿀 수 있습니다.

프로필 선택 드롭다운 — 4종

3. 시작

시작을 누르면 카드가 "시작 중"으로 바뀝니다. 첫 시작(이미지 풀)은 수 분 걸릴 수 있으며, 지연되면 카드에 사유(스케줄링 대기 등)가 표시됩니다.

시작 중 상태

준비가 끝나면 [JupyterLab 열기]·[VS Code 열기]·[중지] 버튼이 활성화됩니다.

실행 중 — 양 IDE 열기 버튼 활성

4. IDE 열기 — JupyterLab / VS Code

버튼을 누르면 각 IDE 가 새 탭에서 열립니다. 인증은 GenD SSO 세션을 그대로 사용합니다(별도 로그인 불필요). 두 IDE 는 같은 홈 디렉토리를 공유하므로 동시에 열어 오가며 작업할 수 있습니다.

JupyterLab

VS Code 첫 진입 시 워크스페이스 신뢰 확인("Do you trust the authors…")이 뜹니다 — 본인 홈 디렉토리이므로 Yes, I trust the authors 를 선택하면 됩니다.

VS Code — 첫 진입 신뢰 확인

5. 중지

중지를 누르면 확인 다이얼로그가 뜹니다. 중지해도 파일은 보존되며(커널 메모리는 휘발), 다시 시작하면 그대로 복원됩니다.

중지 확인 다이얼로그

중지 완료 — 워크스페이스 보존 안내

프로필

프로필리소스 (limit)IDE용도
코드스페이스 Basic (기본)1 CPU / 2GJupyterLab + VS Code일반 분석·개발
코드스페이스 Standard2 CPU / 4GJupyterLab + VS Code데이터 분석
코드스페이스 Large4 CPU / 8GJupyterLab + VS CodeML 실험
JupyterLab (경량)1 CPU / 2GJupyterLab 전용노트북만 필요할 때
  • limit 은 상한이며, 클러스터가 한가하면 그 이하 자원으로도 즉시 시작됩니다.
  • 실행 중에는 프로필을 바꿀 수 없습니다 — 중지 후 다른 프로필로 다시 시작하세요. 홈 디렉토리(PVC)는 프로필과 무관하게 보존됩니다.

자동 종료 (idle culling)

  • 1시간 무활동 시 코드스페이스가 자동 중지됩니다 (파일은 보존, 커널 상태는 휘발).
  • 최대 수명은 8시간입니다 — 장시간 학습·배치 작업은 코드스페이스가 아니라 파이프라인 또는 서빙으로 옮기세요.
  • 중지된 코드스페이스는 카드에서 다시 시작하면 홈 디렉토리 그대로 재개됩니다.

스토리지

  • 사용자마다 개인 볼륨(PVC)이 홈 디렉토리(/home/jovyan)에 마운트됩니다. 신규 사용자는 10Gi 로 생성됩니다.
  • 코드스페이스 간(프로필 변경·재시작·IDE 전환)에도 볼륨은 항상 동일합니다.

터미널에서 GenD 사용하기 — gend CLI

코드스페이스 이미지에는 gend CLI 가 사전 설치되어 있습니다. 터미널을 열고 한 번만 gend init 을 실행하면 인증과 git 자격증명이 함께 준비됩니다:

gend init

gend init 이 하는 일 (각 단계는 실패해도 나머지를 계속 진행):

  1. 로그인 — 브라우저가 없는 환경이므로 자동으로 디바이스 플로우(RFC 8628)로 전환합니다. 출력된 URL·코드로 인증하면 토큰이 ~/.gend/ 에 저장됩니다.
  2. Gitea 사용자 동기화 + 60분 PAT 발급~/.gitconfig(author) 와 ~/.git-credentials(0600) 시드. 이후 git push/pull 이 자격증명 입력 없이 동작합니다.

로그인 후에는 데이터셋을 CLI 로 바로 다룰 수 있습니다:

gend dataset create my-set --modality text # 데이터셋 생성 (v1.2+)
gend dataset upload <id> data/ # 배치 업로드 — 100MB 초과 parquet 는 청크 자동 전환 (v1.2+)
gend dataset list # 데이터셋 목록
gend dataset show <id> # 상세(버전 수·행 수)
gend dataset rows <id> --version 3 # 특정 버전 행 조회
gend dataset rows <id> --json > data.jsonl # JSONL 로 파이프 (학습 스크립트 입력)
gend dataset versions <id> # 버전 이력
gend dataset export <id> --version 3 --wait # Gold export 생성 + 완료 대기
gend dataset download <id> --version 3 -o data/ # export 내려받기 — S3 자격 불필요 (v1.2+)
gend dataset usage # 워크스페이스 스토리지 사용량 + 쿼터 (v1.2+)
gend dataset request-quota --hard-gb 10 --reason "..." # 쿼터 증설 신청 → 관리자 승인 (v1.2+)

CLI 는 여러분의 신원으로 호출하므로 워크스페이스 접근 권한이 그대로 적용됩니다 (권한 없는 데이터셋은 목록·조회에서 제외). export 산출물은 gend dataset download 로 API 를 경유해 내려받습니다 — S3 자격이 필요 없습니다 (v1.2+).

git 형상관리

gend init 이 시드한 자격증명으로 사내 Gitea 를 바로 쓸 수 있습니다. jupyterlab-git· nbdime·pre-commit 도 함께 준비되어 있습니다 — 자세한 내용은 Notebook ↔ Git 가이드 참조.


보안 — 터미널 격리 모델

코드스페이스 터미널에서 사용자는 임의 셸 명령을 실행할 수 있습니다. 영향 범위(blast radius)는 본인 컨테이너로 봉쇄되며, 네 겹으로 격리됩니다 (Epic #2649 에서 리포에 명시 pin):

계층설정차단하는 것
컨테이너 권한uid 1000(비루트) · allowPrivilegeEscalation: false · capabilities drop [ALL]루트 탈취·권한상승·커널 capability 남용
ServiceAccount네임스페이스 default SA(rolebinding 없음)팟의 SA 토큰으로 kubectl/kube-apiserver 호출 → 전부 거부
클라우드 메타데이터cloudMetadata.blockWithIptables: true노드 관리 ID(IMDS 169.254.169.254) 탈취 → 클라우드 계정 공격
Egress NetworkPolicynetworkPolicy.enabled: true, egressAllowRules.privateIPs: falsepostgres·trino·vault·gend-api 내부 ClusterIP 직결 (사설 IP 전대역 차단)
  • 노트북은 hub/proxy/DNS 와 공용 인터넷(pip install 등) 만 도달합니다. 데이터 쿼리는 내부 Trino 직결이 아니라 공용 ingress 의 gend-api /query(SqlGuard + DataGrant) 경유로만 가능합니다 — 이는 의도된 설계입니다.
  • 자원은 프로필별 CPU/메모리 limit + PVC 10Gi 로 상한이 있어, 폭주해도 본인 팟에 국한됩니다.
고객사 보안 요구사항 대응

규제·표준(ISMS-P·전자금융감독규정·ISO 27001 등) 항목별 대응 현황, 실제 사고 사례, 미충족 항목의 정직한 공개, 고객이 직접 실행하는 검증 절차는 코드스페이스 보안 — 고객사 요구사항 대응 가이드 를 참조하세요.

enforcer 전제 — 단독 배포 시 확인

NetworkPolicy 는 클러스터에 네트워크 정책 enforcer 가 있어야 실효합니다. prod AKS 는 Calico(kubernetes.azure.com/network-policy=calico)로 강제되지만, enforcer 가 없는 클러스터(예: kind 의 kindnet)에 배포하면 위 Egress 격리가 inert(무효) 가 됩니다. GenD 를 단독으로 온프레미스 배포하는 경우, 클러스터 CNI 가 NetworkPolicy 를 강제하는지 반드시 확인하세요. 이 격리 값들의 회귀는 CI(scripts/test_cross_pr_consistency.py)가 머지 차단합니다.

운영 (관리자)

helm 반영 절차 — API 토큰 주의

JupyterHub 의 hub.services.gend-api.apiToken 정본은 K8s Secret jupyterhub-api-token 입니다. values-azure.yaml 은 placeholder 만 담고 있으므로 helm upgrade 시 반드시 --set 으로 라이브 토큰을 주입해야 합니다 (placeholder 그대로 적용되면 gend-api 의 노트북 관리 API 가 401):

HUB_TOKEN=$(kubectl --context aks-genos-prod -n gend get secret jupyterhub-api-token \
-o jsonpath='{.data.token}' | base64 -d)
# 적용 전 라이브 값과 리포 values 의 diff 확인 (드리프트 되밀림 방지)
helm --kube-context aks-genos-prod get values jupyterhub -n gend > /tmp/live-values.yaml
diff /tmp/live-values.yaml infra/jupyterhub/values-azure.yaml # 차이 검토 후
helm --kube-context aks-genos-prod upgrade jupyterhub jupyterhub/jupyterhub -n gend \
--version 4.3.3 -f infra/jupyterhub/values-azure.yaml \
--set hub.services.gend-api.apiToken="$HUB_TOKEN" \
--set singleuser.image.name=genosprodacr.azurecr.io/gend-singleuser \
--timeout 180s

토큰 로테이션: 새 랜덤 값 생성 → Secret patch → 위 절차로 helm upgrade → kubectl rollout restart deploy/gend-api.

기존 사용자 PVC 확장 (2Gi → 10Gi)

managed-csi-tagged(StandardSSD) 는 allowVolumeExpansion: true 이므로 온라인 확장이 가능합니다. 신규 사용자만 10Gi 로 생성되며, 기존 클레임은 필요 시 개별 확장합니다:

kubectl --context aks-genos-prod -n gend patch pvc claim-<username> \
-p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
# 파일시스템 확장은 다음 코드스페이스 시작(팟 마운트) 시 자동 반영

사용 자격 부여·회수 (codespace-users)

# 그룹 ID 조회
GID=$(kubectl --context aks-genos-prod -n gend exec deploy/gend-api -c gend-api -- \
python3 -c "print('<Keycloak 관리 콘솔에서 확인>')")

# 부여: Keycloak 관리 콘솔 → Groups → codespace-users → Members → Add member
# 회수: 같은 화면에서 Leave
  • 회수해도 기존 볼륨(PVC)은 삭제되지 않습니다 — 실행 중 코드스페이스는 계속 동작하며, 중지 후 재시작 시점부터 차단됩니다. 즉시 차단이 필요하면 회수 후 해당 사용자의 코드스페이스를 관리자가 중지시키세요.
  • 자격 그룹명을 바꾸려면 infra/jupyterhub/values*.yamlgend-codespace-entry-gateapps/api/.../config.pycodespace_required_group함께 갱신해야 합니다(CI 가 정합을 검사).

프로필 변경 시 함께 갱신할 것

profileList 의 slug 는 gend-api settings.jupyterhub_profiles 와 문자열 계약입니다. values.yaml·values-azure.yaml·apps/api/src/gend_api/config.py 세 곳을 함께 바꾸지 않으면 tests/test_notebook.py 의 values 정합 테스트가 머지를 차단합니다.