Kubernetes deployment¶
Deploy FCC on any Kubernetes cluster using the Helm chart at
charts/fcc/.
This doc walks through a concrete end-to-end deployment. For reference material, see helm.md. For security defaults, see security.md.
Prerequisites¶
- Kubernetes 1.25+ (tested against 1.28, 1.29, 1.30, 1.31)
- Helm 3.14+
kubectlconfigured for your cluster- (Optional) an Ingress controller (nginx-ingress, Traefik, etc.)
- (Optional) cert-manager for automatic TLS certificates
Quick install (default values)¶
Or from a local clone:
git clone https://github.com/rollingthunderfourtytwo-afk/l2_fcc_agent_team_ext.git
cd l2_fcc_agent_team_ext
helm install fcc ./charts/fcc
This deploys the full 4-service stack (backend, frontend, streamlit, jupyter) into the current namespace using the default mock AI provider. Every pod runs as non-root with a restricted PodSecurityContext.
Watch the pods come up:
You should see 4 pods reach Running status within 30-60 seconds
(assuming images are already cached).
Access the stack¶
Without ingress, use port-forwarding:
# Frontend SPA
kubectl port-forward svc/fcc-frontend 8080:80
# Open http://localhost:8080
# Backend health
kubectl port-forward svc/fcc-backend 8765:8765
curl http://localhost:8765/health
# Streamlit explorer
kubectl port-forward svc/fcc-streamlit 8501:8501
# JupyterLab
kubectl port-forward svc/fcc-jupyter 8888:8888
Production install¶
The values-prod.yaml
overlay adds:
restart: alwaysequivalent (Deployment/StatefulSet default)- CPU + memory limits sized for real workloads
- 2 replicas for backend, frontend, streamlit (horizontal scaling)
- Ingress enabled on the frontend with cert-manager annotations
- Required
jupyter.token(install fails if unset)
kubectl create namespace fcc
# Pre-create the secret out-of-band
kubectl create secret generic fcc-secrets \
--namespace fcc \
--from-literal=anthropic-api-key="$ANTHROPIC_API_KEY" \
--from-literal=jupyter-token="$(openssl rand -hex 32)"
# Install with production overlay
helm install fcc ./charts/fcc \
--namespace fcc \
--values ./charts/fcc/values-prod.yaml \
--set-string global.ai.anthropicApiKey="$ANTHROPIC_API_KEY" \
--set-string jupyter.token="$(kubectl -n fcc get secret fcc-secrets -o jsonpath='{.data.jupyter-token}' | base64 -d)" \
--set frontend.ingress.hosts[0].host=fcc.example.com
Scaling¶
Backend, frontend, and streamlit are all horizontally scalable. Scale
via helm upgrade:
Note: the jupyter StatefulSet stays at replicas: 1 because its PVC
is ReadWriteOnce. If you need multiple concurrent users, deploy
multiple Helm releases with different release names:
helm install fcc-alice ./charts/fcc --set jupyter.token=... -n fcc-alice
helm install fcc-bob ./charts/fcc --set jupyter.token=... -n fcc-bob
Health and monitoring¶
The backend's /health endpoint is probed by Kubernetes via a TCP
socket probe (the WS bridge uses the websockets library's
process_request callback to serve HTTP 200 on /health):
kubectl exec -it deploy/fcc-backend -- curl -s http://localhost:8765/health
# {"status":"ok","service":"fcc-ws-bridge"}
For production observability, enable the observability stack:
helm upgrade fcc ./charts/fcc \
--namespace fcc \
--reuse-values \
--set backend.env.OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:4318
See observability.md for the full tracing / metrics setup.
AI provider configuration¶
Set the default provider globally:
# Hosted Anthropic
helm upgrade fcc ./charts/fcc \
--namespace fcc \
--reuse-values \
--set global.ai.defaultProvider=anthropic \
--set-string global.ai.anthropicApiKey="$ANTHROPIC_API_KEY"
# Self-hosted vLLM (requires vLLM pods in the same cluster)
helm upgrade fcc ./charts/fcc \
--namespace fcc \
--reuse-values \
--set global.ai.defaultProvider=vllm \
--set global.ai.vllmBaseUrl=http://vllm-server.vllm.svc.cluster.local:8000/v1
# Local Ollama (requires Ollama pod or external Ollama service)
helm upgrade fcc ./charts/fcc \
--namespace fcc \
--reuse-values \
--set global.ai.defaultProvider=ollama \
--set global.ai.ollamaBaseUrl=http://ollama.ollama.svc.cluster.local:11434/v1
Upgrade¶
See upgrade.md for the full rolling-upgrade procedure.
Quick version:
Uninstall¶
The jupyter PVC is not automatically deleted (to preserve notebook content). To remove completely:
Troubleshooting¶
ImagePullBackOff- Verify your cluster can reach ghcr.io:
kubectl run --rm -it test --image=ghcr.io/rollingthunderfourtytwo-afk/fcc-backend:1.1.1 --command -- /bin/true - Backend pod
CrashLoopBackOffon first install - Check logs:
kubectl logs deploy/fcc-backend. Most common cause: thewebsocketslibrary version is too old. The v1.1.1 image pinswebsockets>=12.0. - Frontend shows empty page or WebSocket errors
- The React app proxies
/wstofcc-backend:8765. Verify the backend Service DNS works:kubectl exec deploy/fcc-frontend -- wget -qO- http://fcc-backend:8765/health - StatefulSet stuck at 0/1 ready (jupyter)
- Check the PVC status:
kubectl get pvc -l app.kubernetes.io/component=jupyter. If pending, your cluster likely has no default StorageClass — setjupyter.persistence.storageClassNameexplicitly.
See also¶
- Helm chart reference — values.yaml deep dive
- Security defaults — hardening guide
- Observability — tracing + metrics
- Upgrade procedure — rolling upgrades
- Container images — registry + tags
charts/fcc/README.md— chart-specific docs