Overview
This guide covers the full local development workflow for k8s-scheduler using kind (Kubernetes IN Docker). You’ll learn how to:- Set up a complete local environment with all dependencies
- Iterate on Go and React code with fast rebuild cycles
- Debug the server and operator with logs
- Test multi-service deployments locally
- Work without cloud dependencies (no AWS, Vault, or DNS required)
Local development uses simplified configuration to avoid external dependencies. For production deployment, see the Production Deployment Guide.
Prerequisites
Install these tools before proceeding:Required
-
Docker (Docker Desktop or equivalent)
- macOS: Docker Desktop for Mac
- Linux: Docker Engine
- Windows: Docker Desktop for Windows
-
kind (Kubernetes IN Docker)
-
kubectl (Kubernetes CLI)
-
Helm (Kubernetes package manager)
Optional (for UI development)
-
Node.js 20+ and npm (for running the React dev server)
-
Go 1.24+ (for running the Go server directly)
You don’t need Node.js or Go if you’re just running the full stack in Docker via
make dev-local. They’re only needed for local iteration outside of Kubernetes.Quick Start
Clone the repository and start the local environment:dev@localhost.
What make dev-local Does
The setup script (scripts/dev-setup.sh) performs these steps:
Create kind cluster
Creates a cluster named This maps
k8s-scheduler-dev with custom configuration:localhost:8080 → Traefik and localhost:8081 → Server.Install PostgreSQL
Deploys PostgreSQL 15 via Helm chart to the Database is accessible at
postgres namespace:postgres-postgresql.postgres.svc.cluster.local:5432.Install Traefik
Deploys Traefik ingress controller to the Traefik routes
traefik namespace:*.localhost requests to the appropriate services.Build Docker images
Builds two images:
k8s-scheduler-server:dev(Go server + embedded React UI)k8s-scheduler-operator:dev(Kubernetes operator)
Dockerfile.server and Dockerfile.operator.Apply dev manifests
Deploys the application using Kustomize overlay:This creates:
scheduler-systemnamespaceUserDeploymentCRD- Server Deployment, Service, ConfigMap
- Operator Deployment, ServiceAccount, RBAC
- Dev-specific config patches
Development Workflows
Workflow 1: Full Stack in Kubernetes (Recommended)
Make changes to Go or React code, then rebuild and reload:- Testing operator logic (requires Kubernetes)
- Testing full integration (server + operator + CRDs)
- Verifying deployment creation end-to-end
Workflow 2: React Dev Server + Go Binary (Fastest Iteration)
For rapid UI development, run the React dev server locally: Terminal 1: Start Go serverhttp://localhost:8081.
Use this workflow when:
- Iterating on React components
- Testing API endpoints without Kubernetes
- Fast hot-reload of UI changes (Vite HMR)
Workflow 3: Operator Only (For Controller Logic)
Run the operator locally against a remote cluster:UserDeployment CRs:
- Debugging operator reconciliation logic
- Testing CRD changes
- Iterating on controller code without rebuilding images
Accessing Deployments
When you create a deployment through the UI, the operator creates a Traefik IngressRoute. Access deployments at:The
.localhost domain is a special reserved domain that doesn’t require DNS resolution. Your browser and curl will route it to 127.0.0.1 automatically.How Routing Works
- Request to
my-app.localhost:8080hits Traefik on port 8080 - Traefik inspects the
Host: my-app.localhostheader - Matches the IngressRoute rule:
Host(\my-app.localhost`)` - Routes traffic to the Service for
my-app - Service load-balances to the Pods
Viewing Logs
Server Logs
The server logs OAuth events, API requests, and database queries:Operator Logs
The operator logs reconciliation events, K8s resource creation, and errors:Deployment Logs (User Apps)
View logs for a specific deployment’s pods:/deployments/<name>/logs.
Configuration (Dev Mode)
Dev mode configuration is applied via Kustomize patches indeploy/dev/.
ConfigMap Patch (deploy/dev/configmap-patch.yaml)
Operator ConfigMap
Testing Multi-Service Deployments
The LibreChat template is a good test case for multi-service deployments:http://librechat.localhost:8080.
Database Access
Connect to PostgreSQL for debugging:Debugging Tips
Enable Verbose Logging
Edit the server deployment to addLOG_LEVEL=debug:
make dev-reload.
Inspect CRDs
View the UserDeployment CRD definition:Port Forwarding
Access services directly without going through Traefik:Reset Database
To start fresh without recreating the cluster:Teardown
Delete the entire kind cluster:scripts/dev-teardown.sh, which executes:
Troubleshooting
Server pod in CrashLoopBackOff
Symptom:kubectl get pods -n scheduler-system shows CrashLoopBackOff
Cause: Usually database connection failure
Fix:
- Check PostgreSQL is running:
kubectl get pods -n postgres - If PostgreSQL is pending, wait for it to start
- Check server logs:
kubectl logs -n scheduler-system deployment/k8s-scheduler-server - Verify DATABASE_DSN in ConfigMap:
kubectl get cm k8s-scheduler-config -n scheduler-system -o yaml
Deployment not accessible at *.localhost:8080
Symptom:curl http://my-app.localhost:8080 fails
Cause: Traefik not running or IngressRoute not created
Fix:
- Check Traefik:
kubectl get pods -n traefik - Check IngressRoute:
kubectl get ingressroutes -A - If missing, check operator logs for errors
- Verify the deployment status:
kubectl get userdeployment <name> -n scheduler-system -o yaml
Cannot create deployments — tier limit exceeded
Symptom: UI shows “You have reached the maximum deployments for your tier” Cause: Dev mode creates a user withfree tier (limit: 1 deployment)
Fix: Update the user’s tier in the database:
Port 8081 or 8080 already in use
Symptom:make dev-local fails with “port already allocated”
Cause: Another process is using the port
Fix:
Next Steps
Production Deployment
Deploy k8s-scheduler to a production Kubernetes cluster
API Reference
Explore the REST API endpoints and authentication