mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 20:14:16 +00:00
deployment/k8s/deployments/sandbox-deploy.yaml pulls arc53/docsgpt-sandbox, which has never been pushed anywhere: Compose builds the runner from the checkout (`build: ./sandbox`), but Kubernetes cannot build, so enabling code execution on a cluster failed on an image that does not exist. Build and push it like the other two images: `develop` on a push to main that touches deployment/sandbox, and `<version>` plus `latest` when the release workflow calls it. Release and develop live in one file here rather than two, because the runner changes rarely and the only difference is which tags move. The tag comes from the inputs and the release payload, not from `github.event_name`, which is `push` when backend-release calls this.
119 lines
4.7 KiB
YAML
119 lines
4.7 KiB
YAML
# docsgpt-sandbox runner (Jupyter Kernel Gateway). OPT-IN: this manifest and its
|
|
# NetworkPolicy are NOT in kustomization.yaml; apply them only when enabling
|
|
# code execution. Sessions are in-process kernels, never child containers; the
|
|
# Docker socket is NOT mounted. Network egress is constrained by the NetworkPolicy
|
|
# under deployment/k8s/network-policies/sandbox-egress-policy.yaml -- apply both.
|
|
#
|
|
# REQUIRED before enabling: create the shared gateway-token Secret and add the
|
|
# runner env to the app pods (docsgpt-api / docsgpt-worker), which the default
|
|
# docsgpt-deploy.yaml intentionally omits (sandbox is off by default):
|
|
# kubectl create secret generic docsgpt-sandbox-gateway \
|
|
# --from-literal=token="$(openssl rand -hex 32)"
|
|
# # on docsgpt-api and docsgpt-worker containers, add:
|
|
# # - name: SANDBOX_GATEWAY_URL
|
|
# # value: "http://docsgpt-sandbox:8888"
|
|
# # - name: SANDBOX_KERNEL_NAME
|
|
# # value: "docsgpt-python"
|
|
# # - name: SANDBOX_GATEWAY_AUTH_TOKEN
|
|
# # valueFrom: { secretKeyRef: { name: docsgpt-sandbox-gateway, key: token } }
|
|
# The gateway authenticates every HTTP + WebSocket request with the token, so
|
|
# kernel code cannot reach the gateway control API over loopback (enumerate/kill
|
|
# sibling kernels or bypass the session cap). The gateway fails closed if the
|
|
# token is unset.
|
|
#
|
|
# The image is built from deployment/sandbox and published as
|
|
# arc53/docsgpt-sandbox (also ghcr.io/arc53/docsgpt-sandbox) by the release
|
|
# workflow, with `develop` tracking main. It is pulled here by the floating
|
|
# `latest` tag: pin it to a release tag if you would rather not pick up a new
|
|
# runner runtime on a pod restart.
|
|
#
|
|
# On Linux prod, schedule this onto a gVisor `runsc` RuntimeClass for kernel
|
|
# isolation (uncomment `runtimeClassName` once the node has it installed).
|
|
#
|
|
# SINGLE TRUST DOMAIN: all sessions in this pod share one container/uid and are
|
|
# isolated by working directory only (per-session cwd) — not by a kernel/OS
|
|
# boundary. This image ships an env-scrubbing kernelspec under the distinct name
|
|
# "docsgpt-python"; the app (docsgpt-api / docsgpt-worker) MUST select it via
|
|
# SANDBOX_KERNEL_NAME=docsgpt-python (already set in docsgpt-deploy.yaml) so the
|
|
# scrubber runs. The stock "python3" spec stays untouched, so it can never
|
|
# shadow the scrubbing kernel. Sibling workspaces are still readable under the
|
|
# shared uid and kernels share one address space. Do NOT inject app secrets
|
|
# (DB/LLM creds) into this pod's env; the runner needs none. For cross-tenant /
|
|
# untrusted multi-tenant workloads use a per-session VM via
|
|
# SANDBOX_BACKEND=daytona instead.
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: docsgpt-sandbox
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: docsgpt-sandbox
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: docsgpt-sandbox
|
|
spec:
|
|
# runtimeClassName: gvisor
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
# Numeric UID the kubelet can verify as non-root; MUST match the sandbox
|
|
# image's `USER` (deployment/sandbox/Dockerfile). Without it the pod
|
|
# fails to start with CreateContainerConfigError.
|
|
runAsUser: 10001
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
containers:
|
|
- name: docsgpt-sandbox
|
|
image: arc53/docsgpt-sandbox
|
|
ports:
|
|
- containerPort: 8888
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
env:
|
|
# Shared gateway token; the launcher fails closed if it is unset.
|
|
# Must match SANDBOX_GATEWAY_AUTH_TOKEN on the app pods.
|
|
- name: SANDBOX_GATEWAY_AUTH_TOKEN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: docsgpt-sandbox-gateway
|
|
key: token
|
|
- name: JUPYTER_RUNTIME_DIR
|
|
value: /tmp/jupyter-runtime
|
|
- name: JUPYTER_DATA_DIR
|
|
value: /tmp/jupyter-data
|
|
resources:
|
|
limits:
|
|
memory: "1Gi"
|
|
cpu: "1"
|
|
requests:
|
|
memory: "256Mi"
|
|
cpu: "250m"
|
|
volumeMounts:
|
|
# Per-session workspaces + Jupyter runtime files on an emptyDir;
|
|
# the root FS stays read-only everywhere else.
|
|
- name: scratch
|
|
mountPath: /tmp
|
|
volumes:
|
|
- name: scratch
|
|
emptyDir: {}
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: docsgpt-sandbox
|
|
spec:
|
|
selector:
|
|
app: docsgpt-sandbox
|
|
ports:
|
|
- protocol: TCP
|
|
port: 8888
|
|
targetPort: 8888
|
|
# Cluster-internal only: the runner must never be exposed outside the cluster.
|
|
type: ClusterIP
|