Skip to content

Build & Package Cache Topology

FractalOps는 패키지와 Docker Hub pull-through 캐시를 Nexus에, 재사용 가능한 OCI 빌드 레이어를 GHCR registry cache에 둡니다. 독립 registry-cache LXC(CT113 @ 10.10.10.150)는 2026-06-18에 해체됐으며 더 이상 별도 캐시 VM/LXC가 없습니다.

Nexus가 다음 패키지·pull-through 캐시를 소유합니다.

  • npm: Nexus npm-group
  • pip: Nexus pypi-group
  • apt: Nexus apt-debian (ubuntu 미러를 풀 거면 apt-ubuntu를 먼저 추가)
  • docker.io pull-through: Nexus docker-group
  • ghcr.io: direct authenticated path; never use the anonymous Nexus upstream proxy
  • OCI 빌드 캐시 레지스트리(플랫폼 CI 이미지 빌드): HTTPS GHCR registry cache. Nexus docker-internal은 내부 TLS/Gateway 경로가 생길 때만 명시적으로 writer가 될 수 있음.

한 장으로 보는 단일 Nexus 캐시 평면

Section titled “한 장으로 보는 단일 Nexus 캐시 평면”
flowchart TB
  subgraph nexus["Nexus (ns nexus, nexus.nexus.svc)\npackage + pull-through cache"]
    npm[":8081 npm-group / pypi-group / apt-debian / web API"]
    grp[":8083 docker-group\n(docker.io pull-through, V2)"]
    internal[":8082 docker-internal (hosted)\nreserved for HTTPS/Gateway writer"]
  end
  k3s["K3s 노드\n/etc/rancher/k3s/registries.yaml\nmirror -> 127.0.0.1:30083"] --> grp
  ws["Daytona 워크스페이스\n(container runtime 없음)\nFRACTALOPS_*_MIRROR_ENDPOINT"] --> grp
  cf["Cloudflare Tunnel\nnexus-buildcache.yamon.io\nexternal projection only"] --> internal
  ws --> npm
  ci["플랫폼 CI 이미지 빌드\ncache_to/from"] --> ghcrcache["GHCR HTTPS registry cache"]
  ci --> grp
  up1["docker.io"] -. 업스트림 .-> grp
  ci --> ghcr["ghcr.io direct authenticated path"]
  • 서비스: nexus (네임스페이스 nexus, nexus.nexus.svc); 공개 https://nexus.yamon.io
  • npm / pypi / web API: :8081 (/repository/<repo>/)
  • docker-group (docker.io pull-through, V2): :8083
  • docker-internal (hosted; 현재 CI writer 아님): :8082
  • CI buildcache writer: GHCR HTTPS registry cache (ghcr.io/<owner>/fractalops-api:*buildcache 등)
  • External buildcache projection: nexus-buildcache.yamon.io → Cloudflare Tunnel → Traefik nexus-buildcache-edge → Nexus docker-internal:8082; do not use this for large CI layer cache pushes.
  • 노드 접근 docker 미러: NodePort 30083 -> 8083 (선호), 또는 kube-proxy 경유 Nexus Service ClusterIP :8083.

토폴로지는 이를 registry_cache 키로 모델링합니다(역사적 이름; 값은 이제 Nexus를 가리킴 — host_ip는 Nexus ClusterIP, buildcache_ref: "", docker_proxy_port: 8083). render_env가 거기서 대응하는 FRACTALOPS_* env를 emit합니다. 이 Cloudflare projection은 topology evidence일 뿐 BuildKit registry cache writer가 아닙니다.

모든 K3s 노드의 /etc/rancher/k3s/registries.yaml는 docker.io만 Nexus docker-group으로 미러합니다. GHCR은 각 런타임이 직접 인증합니다.

mirrors:
docker.io:
endpoint: ["http://127.0.0.1:30083"]
configs:
"127.0.0.1:30083":
auth:
username: "workspace-tools-puller"
password: "<FRACTALOPS_NEXUS_PULL_PASSWORD from OpenBao runtime scope>"

미러 자격증명은 OpenBao(runtime scope)에서 옵니다 — 손으로 편집하지 마세요. 노드별 cutover 절차 + 롤백은 Nexus Docker Mirror Cutover를 보세요.

비공개 GHCR 이미지는 Kubernetes imagePullSecret 또는 CI registry login으로 직접 인증합니다. Nexus의 인증 없는 GHCR upstream proxy는 token 401을 반복하므로 금지합니다.

캐시 평면은 두 소비자를 서빙합니다: 개발자 워크스페이스(pull-through 미러)와 플랫폼 자신의 CI 이미지 릴리스 파이프라인(런타임 이미지 빌드 캐시). 프로젝트별 빌드 파이프라인도, in-sandbox 빌드/ship 평면도 없습니다 — 그 표면 전체가 삭제됐습니다. 개발 프리뷰는 bare 프로세스입니다. Dev Preview Plane 참고.

FractalOps API/worker 이미지는 CI-빌드 + GitOps-pinned입니다. CI는 Nexus pull-through 미러로 base 레이어를 pull하고, registry cache push/pull은 HTTPS GHCR로 유지합니다. plain HTTP nexus.nexus.svc.cluster.local:8082는 BuildKit registry cache exporter가 HTTPS로 붙어 실패할 수 있어 기본 writer가 아닙니다. Nexus를 writer로 쓰려면 내부 HTTPS/TLS 경로(예: Gateway API/HTTPRoute)와 명시적 FRACTALOPS_BUILDCACHE_REGISTRY가 먼저 필요합니다. Cloudflare nexus-buildcache.yamon.io는 외부 projection일 뿐 CI writer가 아닙니다. 빌드 시간/캐시 가용성/실패율 신호는 Build Plane Event 레코드입니다 — Build Plane Observability 참고. Temporal은 잡을 스케줄/실행할 뿐 메트릭 웨어하우스가 되지 않습니다.

Kubernetes BuildKit은 cleanup: false, replicas=1인 공유·경계형 실행면입니다. Pod가 유지되는 동안 작업 간 node-local cache를 재사용하지만 Longhorn/local-path PVC를 만들거나 확장하지 않습니다. Pod 교체 후에도 필요한 레이어는 GHCR registry cache가 소유합니다. 세부 계약은 BuildKit Kubernetes Driver를 보세요.

Harbor publish가 필요한 runner는 Buildx setup 전에 비밀값이 아닌 daytona/daytona-harbor-ca ConfigMap의 ca.crt/tmp/fractalops-buildkit-daytona-harbor-ca.crt로 준비합니다. BuildKit은 이 CA를 harbor.daytona.svc.cluster.local에만 적용하며 TLS 검증을 끄지 않습니다.

Portal 릴리스는 yamonco/fractalops-frontend에 있습니다. 현재 생산 경로는 Cloudflare Worker 배포라서 FractalOps API/worker처럼 OCI image pin을 만들지 않습니다. 이 컨트롤-플레인 저장소가 아니라 프론트엔드 저장소의 Cloudflare release workflow를 보세요.

Terminal window
gh workflow run "Cloudflare Portal Release" --repo yamonco/fractalops-frontend

FractalOps API/worker 런타임 스모크 빌드는 의도적으로 한 최종 이미지를 승격하는 경우가 아니라면 GitOps를 불변으로 유지하세요.

Terminal window
FRACTALOPS_ALLOW_LOCAL_RUNTIME_RELEASE=1 \
FRACTALOPS_RUNTIME_RELEASE_UPDATE_GITOPS=0 \
./ops/containers/fractalops/release.sh

출력된 image_ref=...로 명시적 스모크를 돌리세요. 최종 승격만이 platform/k8s/apps/fractalops-api/values.yamlplatform/k8s/apps/fractalops-worker/values.yaml을 갱신해야 합니다.

개발자 워크스페이스 (컨테이너 런타임 없음)

Section titled “개발자 워크스페이스 (컨테이너 런타임 없음)”

개발자 워크스페이스용으로, 기본 Daytona 템플릿은 토폴로지-파생 캐시 값을 export합니다.

  • FRACTALOPS_GHCR_REGISTRY_CACHE=ghcr.io/<owner>/<image>:<scope>-buildcache
  • FRACTALOPS_DOCKER_IO_MIRROR_ENDPOINT=<nexus-docker-group-url>
  • FRACTALOPS_APT_CACHE_URL=<nexus-apt-debian-url>

샌드박스에는 컨테이너 런타임이 없습니다.

  • docker는 baked exit-127 stub으로 하드-월입니다(in-session에서도 stub 유지). in-sandbox compose/build 평면이 없습니다.
  • 라이브 프리뷰는 bare 개발 서버(vite / next / uvicorn, 0.0.0.0 바인드)이며, dev-preview MCP(dev_preview_start / dev_preview_url / dev_preview_stop)로 daytona-proxy 서명 프리뷰 URL을 통해 노출됩니다. Dev Preview Plane 참고.
  • 프로젝트별 영구 호스팅(DB, 정적 사이트, big-facility compose)은 프로젝트의 Dokploy 평면이지 샌드박스가 아닙니다.
  • gh는 런처이며, GitHub App 프록시가 에이전트 issue/PR 쓰기를 워크스페이스에 토큰을 저장하지 않고 FractalOps GitHub App 브로커로 라우팅합니다.
  • 패키지·Docker Hub pull-through 캐시는 Nexus, OCI 빌드 레이어 캐시는 GHCR가 소유합니다. 독립 registry-cache VM/LXC를 다시 도입하지 말고 주소를 프로젝트 코드에 박지 마세요.
  • 테스트/CI는 Test Execution Policy를 따릅니다. 먼저 덜 실행하고, 그 다음 병렬화하며, 마지막으로 캐시/환경 재사용을 적용합니다.
  • 플랫폼 CI 이미지 빌드의 registry cache writer는 HTTPS GHCR입니다. Nexus hosted docker endpoint(nexus.nexus.svc.cluster.local:8082)는 plain HTTP라 기본 writer로 쓰지 않습니다. 내부 TLS/Gateway 경로를 만든 뒤에만 FRACTALOPS_BUILDCACHE_REGISTRY로 명시하세요. cache_to/fromignore-error=true를 달고 있어 buildcache 오설정은 캐시 미스로 degrade하지 빌드 실패가 되지 않습니다.
  • Daytona 워크스페이스 이미지는 Docker 데몬을 설치/요구하면 안 됩니다. in-sandbox 빌드/ship 평면이 없고, 개발 프리뷰는 bare 프로세스입니다.
  • 개발자는 기본 루프용으로 프로젝트별 DevSpace/watch/sync 규칙을 쓰면 안 됩니다. Daytona가 Kubernetes 런타임 모양을 숨깁니다.
  • 빠른 Daytona 워크스페이스와 로컬 스크래치는 pve-worker0을, 메모리-무거운 작업은 pve-worker3을 선호하세요.
  • Nexus는 자체 blob store + 스케줄된 cleanup/compaction을 소유합니다(외부 registry-gc.timer 없음).
  • Nexus nexus-data PVC는 60Gi durable Longhorn 볼륨입니다. 축소하거나 삭제하지 마세요.
  • Kubernetes BuildKit 로컬 상태는 공유 Pod의 bounded node-local ephemeral storage입니다. 컨테이너는 8Gi를 요청하고 64Gi로 제한되며, /var/lib/buildkit64Gi emptyDir에 명시적으로 마운트됩니다. GC는 12GB를 보존하고 최대 56GB 사용과 8GB 여유를 유지합니다. BuildKit compute/cache는 kubernetes.io/os=linux capability를 선택하며 특정 hostname에 고정되지 않습니다. BuildKit은 일반 worker가 포화되면 sandbox=true worker를 bounded fallback으로 사용할 수 있습니다. CLI-only build runner는 노드 지역성이 필요 없어 스케줄러 배치를 사용하며, 둘 다 control-plane/etcd toleration을 갖지 않습니다. BuildKit은 2 CPU, 3Gi memory, max-parallelism = 2로 제한됩니다. 정상 replica와 Pod quota는 정확히 하나이며 Recreate가 교체 중 중복 Pod를 막습니다. durable layer cache는 GHCR가 소유합니다. 과거의 detached BuildKit PVC는 활성 빌드가 없음을 확인한 뒤 삭제 대상이지 확장 대상이 아닙니다.
  • Nexus nexus-data는 durable blob store입니다. CNPG 용량 사고를 풀려고 Nexus PVC를 삭제하지 마세요. 필요한 정리는 Nexus cleanup task와 blob compaction으로 합니다.