Organize zero-scale-platform project with standard layout, go.mod, Makefile, deployment manifests, CLI, and docs

This commit is contained in:
Stephen Schuresko
2026-09-13 21:23:51 -04:00
parent ca9edaac08
commit e5e0dc2b7c
11 changed files with 412 additions and 137 deletions

4
.gitignore vendored
View File

@@ -1,2 +1,2 @@
gateway
mock-app
/gateway
/mock-app

27
Makefile Normal file
View File

@@ -0,0 +1,27 @@
IMAGE ?= localhost:32000/systemd-runner:latest
NAMESPACE ?= default
.PHONY: all build image push deploy restart clean
all: build
build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o gateway ./cmd/gateway
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o mock-app ./cmd/mock-app
image: build
docker build -t $(IMAGE) -f Dockerfile.systemd .
push: image
docker push $(IMAGE)
deploy:
kubectl apply -f deploy/deployment.yaml -n $(NAMESPACE)
kubectl apply -f deploy/service.yaml -n $(NAMESPACE)
kubectl apply -f deploy/ingress.yaml -n $(NAMESPACE)
restart:
kubectl rollout restart deployment/zero-scale-gateway -n $(NAMESPACE)
clean:
rm -f gateway mock-app

106
README.md Normal file
View File

@@ -0,0 +1,106 @@
# Zero-Scale Platform
A lightweight, high-density serverless execution runtime and dynamic reverse-proxy for Kubernetes.
Rather than maintaining dedicated Pods and container runtimes for infrequently accessed services, the **Zero-Scale Platform** multiplexes stateless and microservice binaries inside a single sandboxed container using transient `systemd-run` execution units.
---
## How It Works
```mermaid
graph TD
Client[HTTP Client] -->|1. Incoming Request :80| Ingress[Kubernetes Ingress]
Ingress -->|2. Route Host Header| Gateway[Gateway Reverse Proxy]
subgraph "Zero-Scale Gateway Pod (systemd-runner)"
Gateway -->|3. Check /opt/apps/<host>| Volume[(Longhorn Binaries Volume)]
Gateway -->|4. Fetch DB Secret & ConfigMap| K8sAPI[Kubernetes InCluster API]
Gateway -->|5. systemd-run with dynamic PORT & DB env| Systemd[systemd PID 1]
Systemd -->|6. Spawns sandboxed transient service| App[Dynamic App Process]
Gateway -->|7. Reverse Proxy to 127.0.0.1:PORT| App
Reaper[Idle Reaper Timer] -->|8. Idle > 15m: systemctl stop| App
end
```
### Core Features
1. **True Scale-to-Zero**: Idle apps consume **zero memory and zero CPU**.
2. **Sub-Second Cold Starts**: Because apps launch as local native Linux processes via `systemd-run`, cold starts complete in **~500 ms** (warm requests respond in **~50–80 ms**).
3. **Dynamic Credential Injection**: Automatically reads Kubernetes `ConfigMap` and `Secret` resources to pass database credentials (`DATABASE_HOST`, `DATABASE_USER`, `DATABASE_PASSWORD`, etc.) to the binary on startup.
4. **Storage Integration**: Seamlessly bind-mounts Longhorn shared RWX volumes (e.g. `/app/uploads`) into the sandboxed process.
5. **Automated Idle Reaper**: Monitors application activity; after 15 minutes of inactivity, the gateway terminates the process and reclaims the ephemeral port.
---
## Directory Structure
```text
zero-scale-platform/
├── Makefile # Standardized build, image, and deploy commands
├── go.mod # Go module definition
├── Dockerfile.systemd # Container image (Debian Bookworm + systemd + wasmtime)
├── cmd/
│ ├── gateway/
│ │ └── main.go # The core zero-scale proxy daemon
│ └── mock-app/
│ └── main.go # Reference mock HTTP service
├── deploy/ # Kubernetes manifests
│ ├── deployment.yaml # Gateway Deployment (replaces manual pods)
│ ├── service.yaml # Gateway ClusterIP Service (:80)
│ └── ingress.yaml # Ingress routing configuration
├── scripts/
│ └── zero-scale-ctl.sh # CLI tool for deploying and monitoring apps
└── services/ # Systemd service unit templates
├── gateway.service
└── ...
```
---
## Management CLI (`zero-scale-ctl.sh`)
The helper script in `scripts/zero-scale-ctl.sh` simplifies managing zero-scale applications:
### Deploy an Application
```bash
./scripts/zero-scale-ctl.sh deploy-app \
--name bdash2 \
--host bdash2.kube.fairfaxmedia.net \
--url http://minio.minio-operator/binaries/bdash-x86_64 \
--db \
--mount /app/uploads
```
### List Configured Applications
```bash
./scripts/zero-scale-ctl.sh list-apps
```
### Check Application Status & Logs
```bash
# Check systemd status inside the gateway
./scripts/zero-scale-ctl.sh status bdash2.kube.fairfaxmedia.net
# Tail systemd journal logs
./scripts/zero-scale-ctl.sh logs bdash2.kube.fairfaxmedia.net
```
---
## Building and Deploying
### 1. Compile Binaries
```bash
make build
```
### 2. Build and Push Container Image
```bash
make image
make push
```
### 3. Deploy to Kubernetes
```bash
make deploy
```

56
deploy/deployment.yaml Normal file
View File

@@ -0,0 +1,56 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: zero-scale-gateway
namespace: default
labels:
app: zero-scale-gateway
app.kubernetes.io/name: zero-scale-gateway
app.kubernetes.io/part-of: zero-scale-platform
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: zero-scale-gateway
template:
metadata:
labels:
app: zero-scale-gateway
app.kubernetes.io/name: zero-scale-gateway
spec:
nodeSelector:
kubernetes.io/hostname: didi-macbookpro14-3
containers:
- name: systemd-runner
image: localhost:32000/systemd-runner:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
securityContext:
privileged: true
volumeMounts:
- mountPath: /run
name: run
- mountPath: /run/lock
name: run-lock
- mountPath: /opt/apps
name: apps-volume
- mountPath: /app/uploads
name: bdash-uploads
volumes:
- name: run
emptyDir:
medium: Memory
- name: run-lock
emptyDir:
medium: Memory
- name: apps-volume
persistentVolumeClaim:
claimName: zero-scale-binaries-pvc
- name: bdash-uploads
persistentVolumeClaim:
claimName: builds-dash-uploads-longhorn-rwx

45
deploy/ingress.yaml Normal file
View File

@@ -0,0 +1,45 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zero-scale-gateway
namespace: default
labels:
app: zero-scale-gateway
app.kubernetes.io/name: zero-scale-gateway
app.kubernetes.io/part-of: zero-scale-platform
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: public
rules:
- host: bdash2.fairfaxmedia.net
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: zero-scale-gateway
port:
number: 80
- host: bdash2.kube.fairfaxmedia.net
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: zero-scale-gateway
port:
number: 80
- host: hopscotch.kube.fairfaxmedia.net
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: zero-scale-gateway
port:
number: 80

18
deploy/service.yaml Normal file
View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: zero-scale-gateway
namespace: default
labels:
app: zero-scale-gateway
app.kubernetes.io/name: zero-scale-gateway
app.kubernetes.io/part-of: zero-scale-platform
spec:
type: ClusterIP
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: zero-scale-gateway

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module git.fairfaxmedia.net/open-cream-cheese/zero-scale-platform
go 1.26

155
scripts/zero-scale-ctl.sh Executable file
View File

@@ -0,0 +1,155 @@
#!/usr/bin/env bash
set -eo pipefail
NAMESPACE="${NAMESPACE:-default}"
GATEWAY_POD_LABEL="app.kubernetes.io/name=zero-scale-platform"
function usage() {
cat <<EOF
Zero-Scale Platform Management CLI
Usage:
$0 [command] [options]
Commands:
deploy-app Deploy or update a zero-scale application
list-apps List all configured zero-scale applications
delete-app <name> Delete an application ConfigMap
status <host> Check the systemd status of an app inside the gateway
logs <host> View the systemd journal logs of an app inside the gateway
install-chart Install or upgrade the full Helm chart
Options for deploy-app:
--name <name> Application identifier (e.g., bdash2) [Required]
--host <host> Hostname to route (e.g., bdash2.kube.fairfaxmedia.net) [Required]
--url <url> Binary download URL (S3 / MinIO / HTTP) [Required]
--type <elf|wasm> Runtime type (default: elf)
--db Enable automated PostgreSQL schema provisioning
--mount <path> Container directory to bind-mount from Longhorn (e.g. /app/uploads)
--no-scale-to-zero Keep application running warm permanently
Examples:
# Deploy a new application
$0 deploy-app --name bdash2 --host bdash2.kube.fairfaxmedia.net --url http://minio.minio-operator/binaries/bdash-x86_64 --db --mount /app/uploads
# List active apps
$0 list-apps
# Check logs of a running systemd unit
$0 logs bdash2.kube.fairfaxmedia.net
EOF
exit 1
}
function get_gateway_pod() {
local pod
pod=$(kubectl get pods -n "$NAMESPACE" -l "$GATEWAY_POD_LABEL" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
if [ -z "$pod" ]; then
pod=$(kubectl get pods -n "$NAMESPACE" -l app=zero-scale-gateway -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
fi
if [ -z "$pod" ]; then
echo "Error: No running zero-scale gateway pod found in namespace $NAMESPACE" >&2
exit 1
fi
echo "$pod"
}
case "$1" in
deploy-app)
shift
NAME=""
HOST=""
URL=""
TYPE="elf"
DB="false"
MOUNTS=""
SCALE_TO_ZERO="true"
while [[ $# -gt 0 ]]; do
case "$1" in
--name) NAME="$2"; shift 2 ;;
--host) HOST="$2"; shift 2 ;;
--url) URL="$2"; shift 2 ;;
--type) TYPE="$2"; shift 2 ;;
--db) DB="true"; shift 1 ;;
--mount) MOUNTS="$2"; shift 2 ;;
--no-scale-to-zero) SCALE_TO_ZERO="false"; shift 1 ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
if [ -z "$NAME" ] || [ -z "$HOST" ] || [ -z "$URL" ]; then
echo "Error: --name, --host, and --url are required." >&2
exit 1
fi
echo "==> Applying ConfigMap zero-scale-app-${NAME}..."
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: zero-scale-app-${NAME}
namespace: ${NAMESPACE}
labels:
zero-scale-app: "true"
data:
host: "${HOST}"
url: "${URL}"
type: "${TYPE}"
$( [ "$DB" = "true" ] && echo " database: \"true\"" )
$( [ -n "$MOUNTS" ] && echo " mounts: \"${MOUNTS}\"" )
$( [ "$SCALE_TO_ZERO" = "false" ] && echo " scale-to-zero: \"false\"" )
EOF
echo "==> Application ${NAME} deployed successfully for host ${HOST}."
;;
list-apps)
echo "==> Configured Zero-Scale Applications in namespace '$NAMESPACE':"
kubectl get configmaps -n "$NAMESPACE" --show-labels | grep "zero-scale-app" || echo "No zero-scale applications found."
;;
delete-app)
NAME="$2"
if [ -z "$NAME" ]; then
echo "Usage: $0 delete-app <name>" >&2
exit 1
fi
echo "==> Deleting ConfigMap zero-scale-app-${NAME}..."
kubectl delete configmap -n "$NAMESPACE" "zero-scale-app-${NAME}"
;;
status)
HOST="$2"
if [ -z "$HOST" ]; then
echo "Usage: $0 status <host>" >&2
exit 1
fi
POD=$(get_gateway_pod)
UNIT="app-${HOST}"
echo "==> Checking status of ${UNIT} in pod ${POD}..."
kubectl exec -n "$NAMESPACE" "$POD" -- systemctl status "$UNIT" || true
;;
logs)
HOST="$2"
if [ -z "$HOST" ]; then
echo "Usage: $0 logs <host>" >&2
exit 1
fi
POD=$(get_gateway_pod)
UNIT="app-${HOST}"
echo "==> Fetching journal logs for ${UNIT} in pod ${POD}..."
kubectl exec -n "$NAMESPACE" "$POD" -- journalctl -u "$UNIT" --no-pager -n 50
;;
install-chart)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CHART_DIR="${SCRIPT_DIR}/zero-scale-chart"
echo "==> Installing / upgrading zero-scale-platform Helm chart from ${CHART_DIR}..."
helm upgrade --install zero-scale-platform "$CHART_DIR" -n "$NAMESPACE"
;;
*)
usage
;;
esac

View File

@@ -1,135 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: zero-scale-artifacts
namespace: default
data:
artifacts.json: |
{
"artifacts": {
"bdash2.kube.fairfaxmedia.net": {
"url": "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/README.md",
"type": "elf"
},
"hopscotch.kube.fairfaxmedia.net": {
"url": "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/README.md",
"type": "elf"
}
}
}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zero-scale-binaries-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: longhorn-2-replicas
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: zero-scale-gateway
namespace: default
labels:
app: zero-scale-gateway
spec:
nodeSelector:
kubernetes.io/hostname: didi-macbookpro14-3
containers:
- name: systemd-runner
image: localhost:32000/systemd-runner:latest
securityContext:
privileged: true
ports:
- containerPort: 80
name: http
volumeMounts:
- name: run
mountPath: /run
- name: run-lock
mountPath: /run/lock
- name: apps-volume
mountPath: /opt/apps
- name: bdash-uploads
mountPath: /app/uploads
- name: config-volume
mountPath: /etc/zero-scale
volumes:
- name: run
emptyDir:
medium: Memory
- name: run-lock
emptyDir:
medium: Memory
- name: apps-volume
persistentVolumeClaim:
claimName: zero-scale-binaries-pvc
- name: bdash-uploads
persistentVolumeClaim:
claimName: builds-dash-uploads-longhorn-rwx
- name: config-volume
configMap:
name: zero-scale-artifacts
---
apiVersion: v1
kind: Service
metadata:
name: zero-scale-gateway
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: zero-scale-gateway
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zero-scale-gateway
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: public
rules:
- host: bdash2.fairfaxmedia.net
http:
paths:
- backend:
service:
name: zero-scale-gateway
port:
number: 80
path: /
pathType: ImplementationSpecific
- host: bdash2.kube.fairfaxmedia.net
http:
paths:
- backend:
service:
name: zero-scale-gateway
port:
number: 80
path: /
pathType: ImplementationSpecific
- host: hopscotch.kube.fairfaxmedia.net
http:
paths:
- backend:
service:
name: zero-scale-gateway
port:
number: 80
path: /
pathType: ImplementationSpecific