A modern, React-based web interface for managing and monitoring the Forkspacer Kubernetes operator. This UI provides an intuitive dashboard for interacting with the Forkspacer operator and its managed resources.
- Overview
- Architecture
- Features
- Installation
- Development
- CI/CD Pipeline
- Contributing
- Deployment
- Configuration
- Troubleshooting
- License
The Forkspacer Operator UI is part of the Forkspacer ecosystem, which consists of three main components:
- Forkspacer Operator - Core Kubernetes operator that manages custom resources
- API Server - Backend API service for business logic and data management
- Operator UI (this repository) - Frontend dashboard for user interaction
This UI communicates with the API Server to provide a user-friendly interface for managing Forkspacer resources.
┌─────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Forkspacer │◄────►│ API Server │ │
│ │ Operator │ │ (Backend) │ │
│ │ (watches │ │ (REST API) │ │
│ │ CRDs) │ └──────┬───────┘ │
│ └──────────────┘ │ │
│ │ │
│ ┌────────▼───────┐ │
│ │ Operator UI │◄────┼─── Users
│ │ (Frontend) │ │
│ │ (Nginx) │ │
│ └────────────────┘ │
└─────────────────────────────────────────────┘
- 🎯 Dashboard - Overview of operator resources and status
- 📊 Resource Management - Create, update, and delete Forkspacer resources
- 🔍 Real-time Monitoring - Live updates of resource states
- 🎨 Modern UI - Built with React and TypeScript
- 🔐 Secure - Integrates with Kubernetes RBAC
- 📱 Responsive - Works on desktop and mobile devices
- 📦 Module Management - Deploy and configure modules (Helm charts, databases, services)
Modules are the core resources managed by the Forkspacer operator. A Module represents a deployable component (typically a Helm chart) with configurable parameters, resource constraints, and outputs.
Here's an example of a Redis module that the UI helps you manage:
apiVersion: batch.forkspacer.com/v1
kind: Module
metadata:
name: redis
namespace: default
spec:
source:
raw:
kind: Helm
metadata:
name: redis
version: "1.0.0"
supportedOperatorVersion: ">= 0.0.0, < 1.0.0"
author: "platform-team"
description: "Redis in-memory data store"
category: "database"
resource_usage:
cpu: "200m"
memory: "256Mi"
config:
- type: option
name: "Redis Version"
alias: "version"
spec:
editable: true
required: false
default: "21.2.9"
values:
- "21.2.9"
- "21.2.7"
- "21.2.6"
- type: integer
name: "Replica Count"
alias: "replicaCount"
spec:
editable: true
required: false
default: 1
min: 0
max: 5
spec:
namespace: default
repo: https://charts.bitnami.com/bitnami
chartName: redis
version: "{{.config.version}}"
values:
- file: https://example.com/values.yaml
- raw:
replica:
replicaCount: "{{.config.replicaCount}}"
outputs:
- name: "Redis Hostname"
value: "redis-master.default"
- name: "Redis Username"
value: "default"
- name: "Redis Password"
valueFrom:
secret:
name: "{{.releaseName}}"
key: redis-password
namespace: default
- name: "Redis Port"
value: 6379
cleanup:
removeNamespace: false
removePVCs: true
workspace:
name: default
namespace: default
config:
version: 21.2.7
replicaCount: 1Metadata:
name: Module identifiercategory: Classification (database, monitoring, storage, etc.)description: Human-readable descriptionresource_usage: Expected CPU/memory consumption
Config:
- Dynamic form fields rendered in the UI
- Types:
option,integer,string,boolean - Each config item has validation rules (required, min/max, values)
- UI auto-generates forms based on config definitions
Spec:
repo: Helm repository URLchartName: Helm chart nameversion: Chart version (supports templating)values: Helm values (from file, raw YAML, or ConfigMap)
Outputs:
- Connection information exposed after deployment
- Can reference static values or Kubernetes secrets
- Displayed in the UI for easy access
Workspace:
- Associates the module with a workspace
- Enables multi-tenancy and resource isolation
The Operator UI provides:
- Module Catalog - Browse available modules by category
- Visual Form Builder - Auto-generated forms based on config schema
- Deployment Wizard - Step-by-step module deployment
- Live Status - Real-time health and status monitoring
- Output Viewer - Easy access to connection strings, credentials
- Version Management - Update module versions with one click
- Configuration Editor - Modify module settings post-deployment
Pull and run the latest image:
docker pull ghcr.io/forkspacer/operator-ui:latest
docker run -p 8080:80 ghcr.io/forkspacer/operator-ui:latestAccess the UI at http://localhost:8080
Deploy directly to your cluster:
apiVersion: apps/v1
kind: Deployment
metadata:
name: operator-ui
namespace: forkspacer-system
spec:
replicas: 1
selector:
matchLabels:
app: operator-ui
template:
metadata:
labels:
app: operator-ui
spec:
containers:
- name: operator-ui
image: ghcr.io/forkspacer/operator-ui:v0.1.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: operator-ui
namespace: forkspacer-system
spec:
selector:
app: operator-ui
ports:
- port: 80
targetPort: 80
type: ClusterIPApply the manifest:
kubectl apply -f operator-ui.yamlAccess via port-forward:
kubectl port-forward -n forkspacer-system svc/operator-ui 8080:80The Operator UI is included in the unified Forkspacer Helm chart:
helm repo add forkspacer https://forkspacer.github.io/charts
helm repo update
helm install forkspacer forkspacer/forkspacer \
--set operator.enabled=true \
--set apiServer.enabled=true \
--set operatorUI.enabled=true \
--namespace forkspacer-system \
--create-namespaceHelm Configuration Options:
operatorUI:
enabled: true
image:
repository: ghcr.io/forkspacer/operator-ui
tag: v0.1.0
pullPolicy: IfNotPresent
replicas: 1
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: nginx
hosts:
- host: forkspacer-ui.example.com
paths:
- path: /
pathType: Prefix- Node.js 18.x or later
- npm 9.x or later
- Docker (for building images)
- Clone the repository:
git clone https://github.com/forkspacer/operator-ui.git
cd operator-ui- Install dependencies:
npm install- Start the development server:
# Using make (recommended for local development)
make dev
# Or directly with npm (requires setting API URL)
REACT_APP_API_BASE_URL=http://localhost:8421 npm startThe app will open at http://localhost:3000 with hot-reloading enabled. The make dev command automatically sets the API URL environment variable for connecting to local api-server.
Runs the app in development mode with hot-reloading.
Launches the test runner in interactive watch mode.
# Run tests once
npm test -- --watchAll=false
# Run tests with coverage
npm test -- --coverage --watchAll=falseBuilds the app for production to the build/ folder. Optimizes for best performance.
Runs ESLint to check code quality (if configured).
npm run buildOutput in build/ directory.
# Default build (uses relative paths /api/v1 - for production with ingress)
docker build -t operator-ui:local .
# Build with custom API URL (for standalone deployments)
docker build --build-arg REACT_APP_API_BASE_URL=http://your-api-server:8421 -t operator-ui:local .
# Run the container
docker run -p 8080:80 operator-ui:localThe project uses GitHub Actions for automated CI/CD with three main workflows:
- Trigger: Pull request events and issue comments
- Purpose: Ensures contributors have signed the Contributor License Agreement
- Actions:
- Checks CLA signature status
- Comments on PRs with instructions if not signed
- Updates status checks
- Trigger: Pull requests and pushes to
mainbranch - Purpose: Validates code quality and builds
- Jobs:
- Lint - Runs code linting
- Test - Executes unit tests with coverage
- Build - Builds production bundle
- Docker Build - Verifies Dockerfile builds (no push)
Important: This workflow does NOT publish Docker images. It only verifies that the build succeeds.
- Trigger: Git tags matching
v*pattern (e.g.,v0.1.0,v1.2.3) - Purpose: Builds and publishes Docker images to GitHub Container Registry
- Jobs:
- Extracts version from tag
- Builds production bundle
- Builds Docker image
- Pushes two tags:
ghcr.io/forkspacer/operator-ui:v0.1.0(versioned)ghcr.io/forkspacer/operator-ui:latest(always newest)
- Creates GitHub Release with notes
We follow Semantic Versioning:
v0.1.0 → Initial release (pre-production)
v0.1.1 → Patch: bug fixes
v0.2.0 → Minor: new features, backwards compatible
v1.0.0 → Major: first stable release or breaking changes
- Ensure your branch is up to date:
git checkout main
git pull origin main- Create and push a version tag:
# For initial release
git tag v0.1.0
# Or for subsequent releases
git tag v0.1.1
# Push the tag to GitHub
git push origin v0.1.0- Automated process begins:
Tag pushed to GitHub
↓
Release workflow triggered
↓
Build React app
↓
Build Docker image
↓
Push to GitHub Container Registry:
- ghcr.io/forkspacer/operator-ui:v0.1.0
- ghcr.io/forkspacer/operator-ui:latest
↓
Create GitHub Release page
- Verify the release:
- Check GitHub Actions for workflow status
- View Releases page
- Verify image in Packages
- Test the published image:
docker pull ghcr.io/forkspacer/operator-ui:v0.1.0
docker run -p 8080:80 ghcr.io/forkspacer/operator-ui:v0.1.0Patch version (v0.1.0 → v0.1.1):
- Bug fixes
- Security patches
- Documentation updates
- Performance improvements (no API changes)
Minor version (v0.1.1 → v0.2.0):
- New features
- New UI components
- API additions (backwards compatible)
Major version (v0.9.0 → v1.0.0):
- First stable production release
- Breaking API changes
- Major architectural changes
We welcome contributions! Please follow these guidelines:
All contributors must sign the Contributor License Agreement (CLA) before their pull requests can be merged. The CLA Assistant bot will automatically comment on your PR with instructions.
To sign the CLA:
- Read the CLA document
- Comment on your PR:
I have read the CLA Document and I hereby sign the CLA
The CLA status check will update automatically.
-
Fork the repository
-
Create a feature branch:
git checkout -b feature/my-new-feature- Make your changes and commit:
git add .
git commit -m "feat: add new dashboard widget"- Push to your fork:
git push origin feature/my-new-feature- Open a Pull Request:
- Ensure all CI checks pass
- Sign the CLA if prompted
- Request review from maintainers
We follow Conventional Commits:
feat: add new feature
fix: resolve bug in component
docs: update README
test: add unit tests
chore: update dependencies
- Follow existing code patterns
- Write tests for new features
- Ensure
npm testpasses - Keep components small and focused
The UI is deployed as a static site served by Nginx. The Docker image is built with a multi-stage Dockerfile:
- Builder stage: Builds React app with Node.js
- Production stage: Serves static files with Nginx
Configure the UI by setting environment variables at build time:
# Example: Custom API endpoint
ENV REACT_APP_API_URL=https://api.forkspacer.example.comRebuild the image to apply changes.
To expose the UI externally, configure an Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: operator-ui-ingress
namespace: forkspacer-system
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- forkspacer-ui.example.com
secretName: operator-ui-tls
rules:
- host: forkspacer-ui.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: operator-ui
port:
number: 80Configure the API server endpoint in src/config.ts:
export const API_BASE_URL =
process.env.REACT_APP_API_URL || "http://localhost:8080";To customize Nginx behavior, create a custom config and rebuild:
# nginx.conf
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA routing
location / {
try_files $uri $uri/ /index.html;
}
# API proxy (optional)
location /api {
proxy_pass http://api-server:8080;
proxy_set_header Host $host;
}
}Update Dockerfile:
COPY nginx.conf /etc/nginx/conf.d/default.confIssue: UI shows blank page
- Check browser console for errors
- Verify API server is accessible
- Check CORS configuration on API server
Issue: Docker build fails
# Clear Docker cache and rebuild
docker build --no-cache -t operator-ui:test .Issue: CI workflow fails on PR
- Ensure tests pass locally:
npm test -- --watchAll=false - Check for linting errors
- Verify Dockerfile builds locally
Issue: Image not appearing in registry after tag push
- Check GitHub Actions workflow status
- Verify tag follows
v*pattern - Check repository permissions for GITHUB_TOKEN
Run the container with debug logging:
docker run -p 8080:80 \
-e NGINX_DEBUG=1 \
ghcr.io/forkspacer/operator-ui:latestView container logs:
# Docker
docker logs <container-id>
# Kubernetes
kubectl logs -n forkspacer-system deployment/operator-uiThis project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Documentation: https://forkspacer.github.io/docs
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Built with:
- React - UI framework
- Create React App - Build tooling
- TypeScript - Type safety
- Nginx - Web server
- GitHub Actions - CI/CD
Made with ❤️ by the Forkspacer team