Kubeflow Without Kubernetes? Deploy a Complete MLOps Suite in 60 Seconds with Gubernator A developer has introduced Gubernator, a single-binary container orchestrator written in Go, which can deploy a complete MLOps suite including JupyterLab, MLflow, MinIO, and Ollama in under 60 seconds using standard Docker Compose syntax, without the overhead of Kubernetes. The tool aims to simplify MLOps deployment by replacing Kubernetes components with a lightweight Go binary and built-in Caddy ingress, reducing control plane memory usage from 16-32 GB to under 200 MB. If you’ve ever tried setting up Kubeflow on Kubernetes, you know the drill: docker-compose.yml gbnt Gubernator https://github.com/mario-ezquerro/gubernator is a single-binary container orchestrator written in Go that combines: /var/contenedores across cluster nodes. ┌─────────────────────────────────────────────────────────────┐ │ Data Scientist / AI Engineer │ └──────────────────────────────┬──────────────────────────────┘ │ https:// .kubeflow.gbnt.local ▼ ┌─────────────────────────────────────────────────────────────┐ │ Built-in Caddy Ingress & CoreDNS Gateway │ └──────┬──────────────┬──────────────┬──────────────┬─────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌──────────────┐┌──────────────┐┌──────────────┐┌──────────────┐ │ JupyterLab ││ MLflow ││ MinIO S3 ││ Ollama / vLLM│ │ Workspace ││ Tracking ││ Artifacts & ││ Inference │ │ PyTorch ││ & Registry ││ Datasets ││ Serving │ │ :8888 ││ :5000 ││ :9001 ││ :11434 │ └──────────────┘└──────────────┘└──────────────┘└──────────────┘ | Capability | Kubernetes Kubeflow | Gubernator MLOps kubeflow-stack | |---|---|---| Control Plane Overhead | 16 GB – 32 GB RAM etcd, Istio, K8s | < 200 MB RAM Go binary | Configuration Format | Helm / Kustomize / CRD manifests | Standard docker-compose.yml | Deployment Time | 30–45 minutes | < 60 seconds | Experiment Tracking | Katib + Kubeflow Metadata | MLflow Tracking + Model Registry | Artifact Store | MinIO on PVCs | MinIO S3 with Granaries Storage | Inference Serving | KServe + Knative + Istio | Ollama / vLLM OpenAI API compatible | Domain Routing & TLS | VirtualServices + IngressGateway | Automatic Caddy Ingress .local | Here is the entire stack defined in standard Docker Compose syntax: version: "3.8" services: 1. MinIO S3 Object Storage Datasets & Model Checkpoints minio: image: minio/minio:latest restart: unless-stopped command: server /data --console-address ":9001" environment: - MINIO ROOT USER=kubeflow - MINIO ROOT PASSWORD=gubernator123 ports: - "9000:9000" - "9001:9001" volumes: - /var/contenedores/kubeflow/minio data:/data labels: - "ingress.host=minio.kubeflow.gbnt.local" - "gbnt.caddy.port=9001" - "gbnt.service.name=minio-s3" 2. MLflow Tracking Server & Model Registry mlflow: image: ghcr.io/mlflow/mlflow:latest restart: unless-stopped command: mlflow server --host 0.0.0.0 --port 5000 --workers 1 --allowed-hosts " " --backend-store-uri sqlite:////data/mlflow.db --default-artifact-root s3://mlflow-artifacts/ environment: - AWS ACCESS KEY ID=kubeflow - AWS SECRET ACCESS KEY=gubernator123 - MLFLOW S3 ENDPOINT URL=http://minio.kubeflow.gbnt.local - MLFLOW S3 IGNORE TLS=true - MLFLOW ALLOWED HOSTS= ports: - "5000:5000" volumes: - /var/contenedores/kubeflow/mlflow data:/data labels: - "ingress.host=mlflow.kubeflow.gbnt.local" - "gbnt.caddy.port=5000" - "gbnt.service.name=mlflow-tracking" 3. Interactive JupyterLab & PyTorch Workspaces jupyter-workspace: image: quay.io/jupyter/pytorch-notebook:latest restart: unless-stopped environment: - JUPYTER TOKEN=gubernator-secret - JUPYTER ENABLE LAB=yes - AWS ACCESS KEY ID=kubeflow - AWS SECRET ACCESS KEY=gubernator123 - MLFLOW TRACKING URI=http://mlflow.kubeflow.gbnt.local - MLFLOW S3 ENDPOINT URL=http://minio.kubeflow.gbnt.local ports: - "8888:8888" volumes: - /var/contenedores/kubeflow/workspaces:/home/jovyan/work - /var/contenedores/kubeflow/cache:/home/jovyan/.cache labels: - "ingress.host=notebooks.kubeflow.gbnt.local" - "gbnt.caddy.port=8888" - "gbnt.service.name=jupyterlab" 4. Model Serving & LLM Inference Gateway inference-engine: image: ollama/ollama:latest restart: unless-stopped ports: - "11434:11434" volumes: - /var/contenedores/kubeflow/models:/root/.ollama labels: - "ingress.host=inference.kubeflow.gbnt.local" - "gbnt.caddy.port=11434" - "gbnt.service.name=model-serving" 🛠️ Deploying in 1 Command On your Gubernator cluster, run: gbnt stack deploy kubeflow-stack -c docker-compose.yml Or open the Gubernator Web Dashboard http://localhost:4001 , head over to Compose Studio, select the Kubeflow MLOps Blueprint, and click Deploy Stack. Gubernator's scheduler automatically: Prioritizes Centurion Worker nodes over the Manager. Spreads the workloads evenly across available workers. Automatically sets up internal DNS CoreDNS and reverse proxy routes Caddy Ingress . Generates instant TLS certificates for all services. Instant Endpoints & Access Immediately after deployment, your MLOps platform is ready: JupyterLab Workspace: https://notebooks.kubeflow.gbnt.local https://notebooks.kubeflow.gbnt.local Token: gubernator-secret MLflow Experiment Tracking: https://mlflow.kubeflow.gbnt.local https://mlflow.kubeflow.gbnt.local MinIO S3 Console: https://minio.kubeflow.gbnt.local https://minio.kubeflow.gbnt.local User: kubeflow / Pass: gubernator123 ⚡ Ollama Inference Engine: https://inference.kubeflow.gbnt.local https://inference.kubeflow.gbnt.local OpenAI-compatible /v1/chat/completions 🧪 Testing the End-to-End Pipeline in Python Data scientists can write normal Python code to log experiments, save models to MinIO S3, and serve predictions: python import mlflow import mlflow.sklearn from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load iris import os Connect to the cluster's MLflow server os.environ "MLFLOW S3 ENDPOINT URL" = "http://minio.kubeflow.gbnt.local" os.environ "AWS ACCESS KEY ID" = "kubeflow" os.environ "AWS SECRET ACCESS KEY" = "gubernator123" mlflow.set tracking uri "http://mlflow.kubeflow.gbnt.local" mlflow.set experiment "iris-classification-demo" with mlflow.start run : X, y = load iris return X y=True clf = RandomForestClassifier n estimators=100, max depth=4 clf.fit X, y Log metrics accuracy = clf.score X, y mlflow.log param "n estimators", 100 mlflow.log metric "accuracy", accuracy Persist model to MinIO S3 and register mlflow.sklearn.log model clf, "model", registered model name="IrisProductionModel" print f"✅ Training completed Accuracy: {accuracy 100:.2f}%" Key Takeaways You don't always need Kubernetes: If you are not running hundreds of parallel multi-step distributed DAG pipelines with Argo, Kubernetes adds unnecessary friction and cost. Standard Compose is enough: With an orchestrator like Gubernator, you get clustering, load balancing, health checks, automated Ingress, and persistent storage using simple, familiar Docker Compose files. Resource Efficiency: You save 10x-20x the RAM, allowing you to invest your hardware budget where it actually matters: GPUs and model training. 🔗 Project Links 🐙 GitHub Repository: mario-ezquerro/gubernator 📖 Documentation: Gubernator Docs ⭐ Give it a star on GitHub if you found this useful