Skip to main content

Prerequisites

Before you begin, make sure you have these tools installed:
No cloud account, Vault, or DNS configuration needed for local development. Everything runs in Docker.

One-Command Setup

Clone the repository and start the local environment:
git clone https://github.com/opsnorth/k8s-scheduler.git
cd k8s-scheduler

# Start everything (kind cluster, PostgreSQL, Traefik, app)
make dev-local
This command will:
1

Create a kind cluster

Sets up a local Kubernetes cluster with port mappings for localhost:8080 and localhost:8081
2

Install PostgreSQL

Deploys PostgreSQL via Helm chart for persistent data storage
3

Install Traefik

Ingress controller for routing *.localhost traffic to deployments
4

Build Docker images

Builds k8s-scheduler-server and k8s-scheduler-operator images
5

Load images into kind

Transfers images into the kind cluster
6

Apply Kubernetes manifests

Deploys server, operator, CRDs, and dev configuration
The setup takes about 1-2 minutes depending on your machine.

Access the Platform

Once the setup completes, open your browser:
open http://localhost:8081
You’ll be automatically logged in as dev@localhost (no OAuth required in dev mode).
Dev mode (DEV_MODE=true) skips Google OAuth and creates a test user automatically. This is only for local development — never enable this in production.

Create Your First Deployment

Now let’s deploy something!
1

Navigate to Deployments

Click “Deployments” in the sidebar
2

Click Create Deployment

Click the ”+ Create Deployment” button
3

Choose a template

Select “nginx” from the template dropdown
4

Name your deployment

Enter a name like my-first-app (lowercase, alphanumeric only)
5

Deploy

Click “Create” and wait for the deployment to start
The operator will create:
  • A Kubernetes Deployment with nginx pods
  • A Service to expose the pods
  • A Traefik IngressRoute for HTTP routing
  • A ConfigMap if the template includes config data
Watch the status change from CreatingRunning in the UI.

Access Your Deployment

Once the deployment is Running, you can access it at:
http://<deployment-name>.localhost:8080
For example, if you named it my-first-app:
curl http://my-first-app.localhost:8080
You should see the nginx welcome page.
The .localhost domain works without DNS because it’s a special reserved domain. Traefik routes requests based on the Host header.

View Logs

Check the logs for the server and operator:
kubectl logs -n scheduler-system deployment/k8s-scheduler-server -f
Expected output:
NAME                                      READY   STATUS    RESTARTS   AGE
k8s-scheduler-operator-xxxxx-xxxxx        1/1     Running   0          2m
k8s-scheduler-server-xxxxx-xxxxx          1/1     Running   0          2m

Explore the UI

The local dev environment includes a full-featured React UI:

Dashboard

  • View all deployments with status cards
  • Quick actions: restart, delete, view logs
  • Metrics graphs (CPU, memory, request rate)

Teams

  • Create teams
  • Invite members (email invites disabled in dev mode)
  • Manage roles: team_admin, developer, viewer

Secrets

  • Add organization-wide secrets
  • Add deployment-specific secrets
  • Secrets are stored in the database (no Vault in dev mode)

Templates

  • Browse system templates (nginx, LibreChat, etc.)
  • Create custom templates with YAML specs
  • Set visibility: private, team, or org
In dev mode, secrets are stored in the PostgreSQL database with encryption. In production, use HashiCorp Vault or AWS Secrets Manager for proper secrets management.

Make Code Changes

After editing Go or React code, rebuild and reload:
make dev-reload
This will:
  1. Rebuild Docker images for server and operator
  2. Load new images into the kind cluster
  3. Restart the deployments
  4. Wait for rollout to complete
Your changes will be live in about 30 seconds.

Teardown

When you’re done, delete the entire kind cluster:
make dev-local-down
This deletes the entire kind cluster and all data. Your deployments, secrets, and database records will be lost.
To start fresh, just run make dev-local again.

Troubleshooting

Port Conflict on 8081 or 8080

Another process is using the port. Find and stop it:
lsof -i :8081
lsof -i :8080
Or change the ports in deploy/dev/kind-config.yaml.

Pods in CrashLoopBackOff

Check the logs:
kubectl logs -n scheduler-system <pod-name>
Common cause: PostgreSQL not ready yet. Wait 30 seconds and the pod will retry.

Deployment Not Accessible at *.localhost:8080

Ensure Traefik is running:
kubectl get pods -n traefik
Check the IngressRoute was created:
kubectl get ingressroutes -A
If missing, check the operator logs for errors.

Cannot Access http://localhost:8081

Verify the server pod is running:
kubectl get pods -n scheduler-system
If the pod is in CrashLoopBackOff, check logs:
kubectl logs -n scheduler-system deployment/k8s-scheduler-server
Common issue: Database connection failed. Check PostgreSQL:
kubectl get pods -n postgres

What’s Next?

Local Development Guide

Deep dive into local dev workflows and configuration

Architecture Overview

Learn how k8s-scheduler components work together

Environment Variables (Dev Mode)

The dev overlay automatically sets these via deploy/dev/configmap-patch.yaml:
VariableDev ValueNotes
DEV_MODEtrueEnables dev login, skips OAuth validation
SESSION_BACKENDmemoryNo Redis needed
COOKIE_SECUREfalseNo TLS in local dev
SECRETS_BACKENDdatabaseNo Vault needed (uses encrypted DB storage)
BILLING_ENABLEDfalseNo Stripe needed
DEPLOYMENT_DOMAINlocalhostIngressRoutes use *.localhost
DISABLE_NETWORK_POLICIEStrueOperator skips network policies
REACT_UItrueServe embedded React SPA
You can override these by editing deploy/dev/configmap-patch.yaml and running make dev-reload.

Build docs developers (and LLMs) love