Skip to content

DevPod Developer Workspaces

DevPod 개발자 워크스페이스 (DevPod Developer Workspaces)

Section titled “DevPod 개발자 워크스페이스 (DevPod Developer Workspaces)”

회사 개발자가 본인 로컬 VS Code에서 Microsoft 계정으로 프로젝트 워크스페이스에 연결하는 방법을 설명합니다. 워크스페이스는 당신 개인 네임스페이스 안의 파드로 뜨고, 안에는 claude / codex / agy CLI와 매칭 VS Code 익스텐션이 들어 있으며, 모델 트래픽은 per-employee 계측을 거쳐 cliproxy로 라우팅됩니다.

Portal launch -> workspace record -> controller devpod up -> Keycloak(Microsoft 로그인) -> kube-api.yamon.io -> 내 네임스페이스의 워크스페이스 파드
  • DevPod: OIDC 게이트가 걸린, 레포 바인딩된 개발 환경입니다. 컨트롤러가 공식 loft-sh devpod CLI와 kubernetes provider로 workspace pod를 materialize하고, 사용자는 준비된 workspace에 attach합니다.
  • 워크스페이스는 당신 전용 네임스페이스(fops-dev-default-<project>-<employee>-<hash>)의 파드로 실행됩니다. 같은 프로젝트/레포/브랜치라도 직원별 workspace_name, provider_name, namespace가 분리됩니다.
  • Daytona와의 경계: Daytona는 에이전트 샌드박스와 자동 작업 실행면입니다. DevPod는 사람이 본인 OIDC 신원으로 들어가는 개발 워크스페이스입니다.

로컬에 다음을 설치하세요.

  • DevPod Desktop (또는 devpod CLI) — 공식 배포본 (https://devpod.sh)
  • DevPod VS Code 익스텐션
  • kubectl + oidc-login (kubelogin) 플러그인 — Keycloak/Microsoft 토큰으로 kube-apiserver에 인증하는 데 필요합니다.
  1. Portal에서 본인 프로젝트를 열고 DevPod connect 액션을 사용합니다. 백엔드는 principal을 확인한 뒤 SpiceDB CheckPermission으로 프로젝트/직원/워크스페이스 권한을 판정하고, 허용된 요청만 Proposal/Temporal queue에 workspace lease로 기록합니다. 컨트롤러는 pending lease를 공식 DevPod CLI로 materialize합니다. 백엔드는 연결/진단용 material도 제공합니다.

    • provider.yaml (kubernetes driver, cliproxy 라우팅 env)
    • OIDC exec(oidc-login) kubeconfig
    • 수동 재현이 필요할 때만 실행할 devpod up 명령
    • 발급 경로: GET /v1/portal/launches/devpod/provider.yaml?workspace_scope=..., GET /v1/portal/launches/devpod/kubeconfig?workspace_scope=... (공유 launch 경로 GET /v1/portal/launches/{solution_id} 에서 provider=devpod 로 연결 자료를 받습니다). 두 material endpoint는 Pomerium/Portal principal 뒤에서 tenant + workspace owner를 확인하고, SpiceDB가 허용한 lease scope만 반환합니다.
    • 관리 경로: GET /v1/portal/launches/devpod/workspaces는 본인 DevPod workspace record만 나열하고, 각 item의 reconnect_material에 provider/kubeconfig URL, devpod provider add, devpod up, MCP loadout, 사용량 링크를 함께 싣습니다. DELETE /v1/portal/launches/devpod/workspaces/{workspace_scope}는 본인 record를 release_requested로 전환하고 같은 workspace shape을 반환합니다. 컨트롤러가 공식 devpod stop을 실행하고 성공하면 suspended가 됩니다. 다시 launch하면 같은 프로젝트/레포/브랜치/직원 identity로 재큐됩니다.
    • Portal 프로젝트 저장소 launch 패널은 같은 경로를 사용해 DevPod workspace 생성, refresh, stop, provider/kubeconfig, 사용량 링크를 한 화면에 보여줍니다.
  2. 워크스페이스 상태가 ready가 되면 제공된 material로 접속합니다. 일반 사용자 흐름은 이미 떠 있는 workspace에 attach하는 것이고, 로컬에서 수동 재현이 필요할 때만 같은 명령을 실행합니다.

    Terminal window
    # Portal이 제공하는 provider.yaml URL로 provider 추가
    devpod provider add <provider_yaml_url> --name <provider_name>
    # 프로젝트@브랜치로 워크스페이스 up
    devpod up <project>@<branch> --provider <provider_name> --ide openvscode
  3. 브라우저가 열립니다 → Keycloak → “Sign in with Microsoft”(Entra federation) → kube-apiserver(https://kube-api.yamon.io)가 토큰을 검증 → Kubernetes RBAC가 이미 SpiceDB에서 허용된 본인 네임스페이스로 실행면을 스코핑합니다.

    • kubeconfig의 oidc-login client는 Headlamp와 같은 kube-access client(headlamp)입니다. Pomerium/웹 IDE용 devpod client와 섞지 않습니다.
  4. DevPod가 워크스페이스 파드(FractalOps 골든 devcontainer)를 만들고, 로컬 VS Code가 거기에 연결됩니다.

flowchart LR
  vscode["로컬 VS Code\n+ DevPod 익스텐션"] -->|Portal command| launch["Portal launch\nemployee-scoped workspace"]
  launch --> lease["Proposal/Temporal queue\nworkspace lease"]
  lease --> controller["DevPod controller\nofficial devpod CLI"]
  controller --> ns["fops-dev-default-<project>-<employee>-<hash>\n워크스페이스 파드 (골든 devcontainer)"]
  launch --> material["provider.yaml\n+ oidc-login kubeconfig"]
  material -->|attach/manual fallback| vscode
  vscode --> kc["Keycloak\nSign in with Microsoft (Entra)"]
  kc --> api["kube-api.yamon.io\n(apiserver: 토큰 검증)"]
  api -->|RBAC scope| ns
  ns --> vscode

워크스페이스 안에는 무엇이 있나 (What is inside)

Section titled “워크스페이스 안에는 무엇이 있나 (What is inside)”
  • claude / codex / agy(Antigravity) CLI + 매칭 VS Code 익스텐션(Claude Code, Codex/ChatGPT). agy binary는 워크스페이스 로드아웃에 포함되지만, DevPod smoke와 중앙 계측은 native agy OAuth가 아니라 CLIProxy의 Antigravity 채널을 검증합니다.
  • 모델 트래픽은 전부 중앙 cliproxy로 라우팅되며, per-employee 계측기(<meter>/u/<employee-slug>)를 거칩니다 — 사용량이 당신에게 귀속됩니다(fops_devpod_tokens{fops_employee} / fops_devpod_requests{fops_employee} 메트릭).
  • Launch payload와 workspace list payload는 usage_observability를 포함합니다. 여기에는 employee_slug, meter path, Grafana dashboard UID(devpod-token-spend), dashboard path, dashboard URL, metric names, employee label이 들어 있습니다. workspace list item은 같은 값을 reconnect_material.usage_observability에도 싣습니다. 프론트엔드는 이 값을 그대로 사용하고 metric 이름/label을 재합성하지 않습니다.
  • claudeANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN, codexOPENAI_BASE_URL + OPENAI_API_KEY + 실행 시 --config openai_base_url=...를 사용합니다. Antigravity는 DevPod smoke에서 agy binary 존재를 확인한 뒤 fractalops-antigravity alias를 per-employee meter의 CLIProxy Anthropic-compatible API로 호출합니다. native agy OAuth bundle을 워크스페이스에 주입하지 않으므로 사용자별 meter URL/token은 DevPod provider env에서 런타임 바인딩되고, 에이전트나 사용자가 바뀔 때 이미지를 다시 빌드하지 않습니다. 이미지의 fractalops-cli-wrapper도 같은 계약을 한 번 더 보정합니다. CLIPROXY_CLIENT_API_KEY가 없으면 provider material 생성이 devpod_cliproxy_client_token_missing으로 실패합니다. base URL만 있는 워크스페이스를 띄워 CLI가 나중에 인증 실패하는 상태를 허용하지 않습니다.
  • 중앙 cliproxy는 OSS CLIProxyAPI plane입니다. OAuth 계정, load balancing, oauth-model-alias, excluded model, quota-exceeded reroute, /v1/models, log/management는 중앙 plane이 맡습니다. DevPod는 모델 목록, quota, upstream account 상태를 추론하지 않고, 그 plane을 향한 사용자별 endpoint/token/Armory 설정만 reconcile합니다.
  • CLIProxyAPI Web UI는 본체가 제공하는 /management.html을 우선 사용하고, Management API(/v0/management)를 통해 config/credentials/logs를 다룹니다. 중앙 plane의 config/auth state는 공식 PGSTORE_DSN으로 CNPG에 저장되므로 사용자/계정 바인딩 때문에 DevPod나 agent 이미지를 다시 빌드하지 않습니다.
  • 모델 / reasoning-effort / 속도는 cliproxy와 CLI가 결정합니다. 익스텐션 UI나 CLI 플래그가 요청을 보내면 cliproxy가 현재 등록된 계정/alias/quota 기준으로 라우팅합니다. DevPod 이미지와 provider material은 모델을 핀하지 않습니다.
  • Armory MCP 서버가 런타임 바인딩됩니다(FRACTALOPS_DEVPOD_MCP_CONFIG_JSON -> .mcp.json + codex/agy 등가 설정). launch 때 선택된 서버 목록과 config가 workspace metadata에 저장되므로 controller reconcile이 같은 Armory loadout을 재생합니다. MCP 인증은 per-user OIDC로 Armory 게이트웨이/ContextForge 엣지에서 수행됩니다 — 베이크된 토큰 없음(당신이 본인 신원으로 OIDC 플로우를 탑니다).
  • DevPod controller/workspace image pin은 base chart가 아니라 platform/k8s/environments/lxc-pve-lab/runtime.cue와 generated values(values/devpod-developer-workspaces.yaml)가 소유합니다. Runtime GitOps bump도 같은 CUE source와 generated overlay만 갱신하므로 직원/agent/model 바인딩 변경 때문에 이미지를 다시 빌드하지 않습니다.
  • DevPod devcontainer startup은 공식 prebuild consumer 경로를 씁니다. Portal launch material과 controller reconcile은 FRACTALOPS_DEVPOD_PREBUILD_REPOSITORYdevpod up --prebuild-repository로 전달합니다. DevPod는 devpod-<hash> 태그가 있으면 그 이미지를 사용하고, 없으면 기존처럼 빌드로 degrade합니다. prebuild producer는 같은 repository에 공식 devpod build ... --repository <repo>로 태그를 채워야 합니다.
  • openvscode IDE는 golden workspace image 안의 /home/devuser/.openvscode-server/bin/openvscode-server를 사용합니다. workspace startup 중 GitHub release tarball을 받지 않습니다.
  • 워크스페이스 scratch disk는 FRACTALOPS_DEVPOD_WORKSPACE_DISK_SIZE, FRACTALOPS_DEVPOD_WORKSPACE_STORAGE_CLASS, FRACTALOPS_DEVPOD_WORKSPACE_DISK_ACCESS_MODE / chart provider.workspaceDisk*가 소유합니다. provider.yaml 경계에서만 공식 DevPod agent.kubernetes.diskSize, storageClass, pvcAccessMode로 렌더링됩니다. 이전 persistentVolumeSize 명칭은 쓰지 않습니다.
  • ops-runtime-control.ymldevpod-launch-proof는 launch/provider/workspace list를 지나 실제 workspace PVC까지 검사합니다. provider material과 live PVC가 10Gi, fractalops-scratch, RWO를 만족하지 않으면 workspace_scratch_disk_ready=true가 나오지 않고 proof가 실패합니다. Proof용 임시 workspace는 준비 완료와 scratch disk 검증 뒤 DELETE /v1/portal/launches/devpod/workspaces/{workspace_scope}를 호출해 release_requested로 돌려 찌꺼기를 남기지 않습니다.
  • 유휴 워크스페이스는 비활성 타임아웃(공식 DevPod INACTIVITY_TIMEOUT, 기본 약 30분) 이후 자동 정지됩니다. 이것은 커스텀 reaper가 아니라 DevPod kubernetes provider의 공식 auto-stop입니다.
  • DevPod kubernetes provider는 workspace disk를 Kubernetes PVC 필드로 구현하지만, FractalOps 내부 언어에서는 이를 scratch workspace disk로만 취급합니다. 기본값은 10Gi, fractalops-scratch, RWO이며 durable state는 Git/Nexus/CNPG/object storage에 둡니다.
  • 컨트롤러는 ready workspace record도 가볍게 관찰합니다. 같은 DEVPOD_WORKSPACE_ID를 가진 DevPod pod/PVC가 여러 개 남으면 최신 ready pod와 그 PVC만 보존하고, older sibling pod/PVC를 정리합니다. 이것은 user home 보존 정책을 바꾸지 않는 duplicate-resource janitor입니다.
  • 컨트롤러 상태는 https://devpod.yamon.io/healthz에서 확인합니다. 응답에는 reconcile_enabled, reconcile_interval_seconds, reconcile_in_progress, last_reconcile_started_at, last_reconcile_at, last_reconcile_error, last_reconcile.processed/ready/stopped/errored/stale_provisioning/cleaned_workspace_resources/workspace_cleanup_errors, pending_sample_scopes, release_sample_scopes, provisioning_sample_scopes가 포함됩니다. HTTP 200만으로 완료 판단하지 말고 reconcile_in_progress, last_reconcile_error, errored, stale_provisioning, workspace_cleanup_errors를 같이 봅니다.
  • 공식 DevPod CLI 호출은 컨트롤러에서 FRACTALOPS_DEVPOD_CLI_TIMEOUT_SECONDS(기본 300초)로 제한합니다. 컨트롤러는 공식 devpod up--open-ide=false를 붙여 서버 reconcile이 로컬 IDE open까지 시도하지 않게 합니다. 컨트롤러 재시작이나 kill 때문에 provisioning이 남으면 FRACTALOPS_DEVPOD_PROVISIONING_STALE_SECONDS(기본 420초) 이후 error로 회수합니다.

워크스페이스는 SpiceDB 관계 그래프의 프로젝트 역할에 따라 제공됩니다.

역할워크스페이스
owner제공
maintainer제공
contributor제공
viewer제공 안 함

접근 SSOT는 SpiceDB입니다(devpod_viewer_only / devpod_project_access_denied). Keycloak과 Pomerium은 신원/세션을 제공하고, Kubernetes RBAC는 이미 허용된 네임스페이스 실행면을 강제합니다. viewer는 프로젝트를 볼 수는 있어도 개발자 워크스페이스는 받지 못합니다.

  • 로그인/토큰 문제: kubectl oidc-login 토큰을 다시 받거나(kubectl oidc-login get-token ... 재실행) 캐시된 토큰을 지우세요. 그래도 안 되면 브라우저에서 Microsoft 로그인을 다시 완료하세요.
  • 이미지 풀 실패 / 네임스페이스 미준비: 컨트롤러가 당신의 네임스페이스 + 풀 시크릿을 프로비저닝하는 중일 수 있습니다. 잠시 후 devpod up을 재시도하세요.
  • 워크스페이스가 아직 안 뜸: Portal launch 직후 상태는 pending입니다. 컨트롤러가 공식 DevPod CLI로 provisioningready까지 진행합니다. provisioning_sample_scopes에 보이면 실제 작업 중이고, timeout/stale window를 넘으면 errorlast_error로 확정됩니다. 실패한 error 상태는 다시 launch하면 pending으로 재큐됩니다.
  • 워크스페이스 정지가 안 끝남: stop 요청 직후 상태는 release_requested입니다. 컨트롤러가 releasing으로 바꾸고 공식 devpod stop 성공 시 suspended로 닫습니다. release_sample_scopes에 계속 남아 있으면 컨트롤러 reconcile이 아직 명령을 잡지 못한 상태입니다.
  • resume 지연: 자동 정지 후 resume은 보통 약 90초가 걸립니다(파드 재시작 + PVC 재연결). 정상입니다.
  • connect가 계속 실패: 롤아웃 중일 수 있습니다 — 플랫폼 팀에 문의하세요.