Dev pod
A dev pod is an ephemeral interactive environment — spin it up with kubectl apply, connect via port-forward, do your work, and tear it down when you are done. No GitOps ceremony, no Ingress, no Service. This is the explicit exception to the “commit everything to your repo” rule: dev pods are throwaway by design, and managing them through ArgoCD is ceremonial overhead.
Preconditions
Section titled “Preconditions”Before using this recipe, confirm:
- Your tenant is provisioned and you have completed Your first deployment end-to-end.
- You have
kubectlaccess to your tenant namespaces. - You know your tenant name (the
<your-tenant>prefix used in namespace names).
Use case
Section titled “Use case”Use this recipe when you need:
- A short-lived interactive environment (JupyterLab, RStudio, a debug shell).
- Quick prototyping or data exploration without committing manifests to your repo.
- A sandbox that you will delete within hours or days — not a persistent service.
If your workload runs continuously and serves traffic, see Long-running service. If your workload runs to completion and exits, see Jobs & CronJobs.
Save this manifest locally (not in your workload repo). Replace <your-tenant> with your real tenant name.
Pod — JupyterLab notebook
Section titled “Pod — JupyterLab notebook”apiVersion: v1kind: Podmetadata: name: jupyter namespace: <your-tenant>-dev labels: app: jupyterspec: priorityClassName: uber-user-significant securityContext: runAsNonRoot: true runAsUser: 1000 seccompProfile: type: RuntimeDefault containers: - name: notebook image: quay.io/jupyter/minimal-notebook:2024-08-19 ports: - containerPort: 8888 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: [ALL] resources: requests: cpu: 500m memory: 1Gi limits: cpu: 2 memory: 4Gi volumeMounts: - name: home mountPath: /home/jovyan - name: tmp mountPath: /tmp volumes: - name: home emptyDir: {} - name: tmp emptyDir: {}Dry-run
Section titled “Dry-run”Before applying, validate the manifest locally:
kubectl apply --dry-run=client -f dev-pod.yamlThis should render without errors. It catches YAML syntax issues and missing required fields before the cluster tries to create the pod.
Launch and connect
Section titled “Launch and connect”Apply the pod directly — no commit, no ArgoCD:
kubectl apply -f dev-pod.yamlWait for the pod to start:
kubectl get pod jupyter -n <your-tenant>-dev --watchOnce the status shows Running, read the Jupyter access token from the logs:
kubectl logs jupyter -n <your-tenant>-devLook for a line like:
http://127.0.0.1:8888/lab?token=abc123...Copy the token value. Then start port-forwarding:
kubectl port-forward -n <your-tenant>-dev pod/jupyter 8888:8888Open your browser to http://localhost:8888/?token=<token> (paste the token from the logs). The JupyterLab interface should load.
Cleanup
Section titled “Cleanup”When you are done, delete the pod:
kubectl delete pod jupyter -n <your-tenant>-devEverything in the emptyDir volumes is deleted with the pod. If you created notebooks or data you want to keep, download them from JupyterLab before deleting.
If something goes wrong
Section titled “If something goes wrong”- Pod rejected by Kyverno with PSS admission error. You modified the
securityContextblock. Revert to the verbatim YAML above. See Known limitations for the full PSS rule. - Namespace rejected with
forceTenantPrefix. The namespace name does not start with your tenant name. All namespaces must be<your-tenant>-<suffix>. See Known limitations. - Pod stuck in
Pending. Checkkubectl describe pod -n <your-tenant>-dev jupyter— the Events section shows the reason. Common cause: quota exceeded. Request more via RCS ticket, or delete other workloads in your tenant to free capacity. - Jupyter shows
Permission deniederrors. TheemptyDirmount at/home/jovyanmay be missing. Verify thevolumeMountsandvolumessections match the YAML above exactly. - Port-forward disconnects or hangs. This is a known
kubectlbehavior — it drops idle connections. Re-run thekubectl port-forwardcommand. Your Jupyter session state persists as long as the pod is still running. - Want this notebook to persist long-term? Promote it to a Long-running service — commit a Deployment manifest to your workload repo with the same image and resource requests, add a Service and Ingress for stable access, and let ArgoCD manage the lifecycle.