Skip to content

Repository files navigation

KubeLoom

Turn a single 15-line AppService CRD into a fully deployed, autoscaled, secured, and observable deployment without writing 200 lines of brittle YAML.


License Contributions welcome

Go Kubernetes Kubebuilder CRD


Table of Contents

The Problem

Deploying a microservice to Kubernetes means hand-writing 6-10 YAML files (Deployment, Service, Ingress, HPA, PDB, NetworkPolicy...) and getting several subtly wrong.

How KubeLoom Solves It

Write this:

apiVersion: platform.mydomain.dev/v1alpha1
kind: AppService
metadata:
  name: my-api
spec:
  app:
    image: my-api:1.0.0
    replicas: 3
    port: 8080
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 10
    targetCPUUtilizationPercentage: 70

The operator reconciles it into 9 production-ready resources — Deployment, Service, HPA, Ingress, PVC, PDB, NetworkPolicy, canary rollout, and a Grafana dashboard — automatically.

Without vs With KubeLoom

Without KubeLoom With KubeLoom
Files to write 6-10 separate YAML manifests 1 AppService CRD (~15 lines)
Canary rollout Manual second Deployment + Istio config canary.enabled: true
Observability Hand-code ServiceMonitor + Grafana JSON observability.enabled: true
Network policy Write CIDR rules from memory networkPolicy.enabled: true
Autoscaling Separate HPA manifest, easy to drift autoscaling.enabled: true
Toggle a resource off Delete the YAML file, hope nothing breaks enabled: false (operator deletes it)

Architecture

                    ┌─────────────────────────────┐
                    │      Developer writes       │
                    │     1 AppService CRD        │
                    └──────────────┬──────────────┘
                                   │
                                   ▼
                    ┌─────────────────────────────┐
                    │     KubeLoom Operator       │
                    │   (controller-runtime)      │
                    └──────────────┬──────────────┘
                                   │
              ┌────────────────────┼────────────────────┐
              │                    │                    │
              ▼                    ▼                    ▼
    ┌──────────────┐    ┌──────────────┐     ┌──────────────────┐
    │   Core       │    │  Scaling &   │     |   Networking &   |
    │   Workload   │    │  Resilience  │     |   Observability  |
    ├──────────────┤    ├──────────────┤     ├──────────────────┤
    │ Deployment   │    │ HPA          │     │ Ingress          │
    │ Service      │    │ PDB          │     │ NetworkPolicy    │
    │ PVC          │    │ Canary       │     │ Grafana Dashboard│
    │ Env/Probes   │    │ Strategy     │     │ Prometheus       │
    │ Security     │    │ Lifecycle    │     │ annotations      │
    └──────────────┘    └──────────────┘     └──────────────────┘

Reconciliation Flow

  AppService CR
       │
       ▼
 ┌─────────────┐
 │ reconcileDeployment  ──→  Deployment (full pod spec)
 │ reconcileService     ──→  Service
 │ reconcileHPA         ──→  HPA (or delete if disabled)
 │ reconcileIngress     ──→  Ingress (or delete if disabled)
 │ reconcileStorage     ──→  PVC (or delete if disabled)
 │ reconcileDisruption  ──→  PDB (or delete if disabled)
 │ reconcileNetworkPolicy ─→ NetworkPolicy (or delete if disabled)
 │ reconcileCanary      ──→  Canary Deployment (or delete if disabled)
 │ reconcileObservability ─→ ConfigMap (Grafana dashboard)
 └─────────────┘
       │
       ▼
  status.conditions[Available=True]

Key Features

  • One CRD, nine resources — single AppService generates Deployment, Service, HPA, Ingress, PVC, PDB, NetworkPolicy, canary Deployment, and Grafana dashboard ConfigMap
  • Toggle-driven — every optional resource has an enabled flag. Flip it on/off without removing code
  • Idempotent reconciliation — safe to run repeatedly. Creates or updates with CreateOrUpdate, deletes when disabled
  • Full pod spec control — env vars, probes (HTTP/TCP), lifecycle hooks, security contexts, DNS, image pull, logging, sidecars, init containers, rolling update strategy
  • Canary deployments — 1-replica canary with track=canary label for traffic differentiation
  • Observability — auto-generated Grafana dashboard ConfigMaps + Prometheus scrape annotations
  • Resilience labels — Istio retry and circuit-breaker annotations on pod labels
  • Real test coverage — 12 unit test files, envtest integration tests, e2e in isolated Kind clusters via GitHub Actions

Demo

# Install CRDs and deploy the controller
make install
export IMG=<your-registry>/kubeloom:latest
make docker-build docker-push IMG=$IMG
make deploy IMG=$IMG

# Apply a sample AppService
kubectl apply -k config/samples/

The operator immediately reconciles:

demo-app                             ← your AppService
├── Deployment/demo-app              ← pod spec with all mutations
├── Deployment/demo-app-canary       ← 1-replica canary with track label
├── Service/demo-app                 ← ClusterIP with observability annotations
├── HPA/demo-app                     ← CPU-based autoscaling (2-8 replicas)
├── PDB/demo-app                     ← minAvailable: 1
├── NetworkPolicy/demo-app           ← CIDR-based ingress/egress rules
├── Ingress/demo-app                 ← (disabled in sample, host routing with TLS)
└── ConfigMap/grafana-dashboard-*    ← auto-generated Grafana dashboard

E2E Report Output

The report script (scripts/e2e-report.sh) validates every reconciled resource:

Complete output (click to expand)

Full e2e report

Output — Part 1: Resources & Environment

Output part 1

Output — Part 2: Security, Strategy & Lifecycle

Output part 2

Getting Started

Prerequisites

  • Go 1.26+
  • Docker (or Podman) for building the controller image
  • kubectl configured for a Kubernetes cluster
  • Kind (for local development and e2e tests)

Quick Start

git clone https://github.com/Kritagya123611/Kubeloom.git
cd Kubeloom

export IMG=<your-registry>/kubeloom:latest
make docker-build docker-push IMG=$IMG

make install
make deploy IMG=$IMG
kubectl apply -k config/samples/

kubectl logs -n kubeloom-system deployment/kubeloom-controller-manager -c manager -f

Local Development

make run                                          # run controller locally
kubectl apply -k config/samples/                  # apply sample in another terminal

Running Tests

make test           # unit + integration (envtest, no cluster needed)
make lint           # golangci-lint
make test-e2e       # e2e in isolated Kind cluster (auto-cleanup)

Configuration

The controller accepts these flags at startup:

Flag Default Description
--metrics-bind-address :8443 Metrics server listen address
--health-probe-bind-address :8081 Health/readiness probe address
--leader-elect false Enable leader election for HA
--metrics-secure true Require TLS for metrics endpoint
--enable-http2 false Enable HTTP/2 (disabled to mitigate CVE-2023-44488)

These flags control how the operator itself runs. For the workload it manages, everything is driven by the AppService spec fields below.

AppService Spec

The AppService CRD at platform.mydomain.dev/v1alpha1 supports 24 spec fields. Each field maps to specific Kubernetes resources:

Field Description Reconciles To
app Image, replicas, port, command, args, workingDir, imagePullPolicy Deployment, Pod
env Environment variables, envFrom (ConfigMap/Secret refs) Pod env vars
resources CPU/memory requests and limits Container resources
probes Readiness, liveness, startup (HTTP GET or TCP) Pod probes
service Service type, port, targetPort Service
ingress Host, path, TLS, annotations Ingress
autoscaling Min/max replicas, CPU/memory utilization targets HPA
scheduling nodeSelector, tolerations, affinity, topologySpreadConstraints Pod scheduling
security runAsNonRoot, readOnlyRootFilesystem, seccompProfile, etc. SecurityContext
storage PVC size, storageClass, mountPath PersistentVolumeClaim
canary Enabled, weight, stableImage Canary Deployment
resilience Retry attempts, circuit-breaker thresholds Pod labels
disruption minAvailable, maxUnavailable PDB
networkPolicy CIDR-based ingress/egress allow lists NetworkPolicy
observability ServiceMonitor CR, Grafana dashboard, metrics config ServiceMonitor, ConfigMap, Service annotations
logging Log level, format, sidecar image Env vars, sidecar container
lifecycle PreStop, PostStart hooks (exec, HTTP, TCP) Pod lifecycle
strategy RollingUpdate maxSurge/maxUnavailable Deployment strategy
dns Pod hostname Pod hostname
imagePull Registry prefix, imagePullSecrets Pod imagePullSecrets
sidecars Additional sidecar containers Pod containers
initContainers Init containers Pod init containers
serviceAccountName Custom service account name Pod serviceAccountName (SA created if rbac.createServiceAccount: true)
rbac ServiceAccount creation, roles, clusterRoles ServiceAccount, RoleBinding, ClusterRoleBinding

Project Structure

├── cmd/main.go                          Manager entry point
├── api/v1alpha1/
│   ├── appservice_types.go              CRD type definitions (24 fields)
│   ├── groupversion_info.go             Group/version registration
│   └── zz_generated.deepcopy.go         Auto-generated DeepCopy
├── internal/controller/
│   ├── appservice_controller.go         Main reconciler (9 sub-reconcilers)
│   ├── deployment.go                    Deployment reconciliation + pod spec
│   ├── service.go                       Service reconciliation
│   ├── hpa.go                           HPA (create/delete)
│   ├── ingress.go                       Ingress (create/delete)
│   ├── storage.go                       PVC (create/delete)
│   ├── disruption.go                    PDB (create/delete)
│   ├── networkpolicy.go                 NetworkPolicy (create/delete)
│   ├── canary.go                        Canary Deployment
│   ├── observability.go                 Grafana dashboard ConfigMap
│   ├── env.go                           Env var mutation
│   ├── probes.go                        Health probe mutation
│   ├── lifecycle.go                     Lifecycle hook mutation
│   ├── scheduling.go                    NodeSelector mutation
│   ├── security.go                      SecurityContext mutation
│   ├── dns.go                           DNS hostname mutation
│   ├── imagepull.go                     Image registry/pull secret mutation
│   ├── logging.go                       Log level/format + resilience labels
│   ├── sidecars.go                      Sidecar + init container mutation
│   ├── strategy.go                      Deployment strategy mutation
│   ├── *_test.go                        12 unit test files (envtest)
│   └── suite_test.go                    Ginkgo test suite setup
├── config/
│   ├── crd/bases/                       Generated CRD YAML
│   ├── rbac/                            Generated RBAC manifests
│   ├── samples/                         Example AppService CRs
│   └── manager/                         Controller Deployment manifest
├── test/e2e/                            End-to-end tests (Kind cluster)
├── scripts/e2e-report.sh                Visual e2e report script
├── Makefile                             Build, test, deploy commands
├── Dockerfile                           Multi-stage (golang:1.26 → distroless)
└── PROJECT                              Kubebuilder metadata

Contributing

Development Setup

# Install tooling (downloads controller-gen, kustomize, envtest to ./bin/)
make manifests generate

# Run tests
make test

# Lint and auto-fix
make lint-fix

Workflow

  1. Edit api/v1alpha1/*_types.go for CRD changes → run make manifests generate
  2. Edit internal/controller/*.go for reconciliation logic → run make test
  3. Run make lint-fix before committing
  4. CI validates everything (lint, unit tests, e2e on Kind)

Submitting Changes

git checkout -b feature/my-change
make test lint-fix
git add . && git commit -m "Add feature description"
git push origin feature/my-change
# Open a PR — CI runs automatically

Tech Stack

Component Technology
Language Go 1.26
Framework Kubebuilder v4.15.0 / controller-runtime v0.24.1
CRD Version API v1 (CustomResourceDefinition v1)
Kubernetes v1.36 client libraries
Testing Ginkgo + Gomega, envtest (real API + etcd)
E2E Kind clusters, Cert-Manager
CI GitHub Actions (lint, test, e2e)
Linting golangci-lint v2.12.2 (20+ analyzers)
Runtime Image distroless/static:nonroot (UID 65532)

License

Apache License 2.0 — Copyright 2026. See LICENSE for details.

Acknowledgments

About

A Kubernetes operator managing full microservice lifecycles. Reconciles one AppService CRD into 9 production-ready resources: Deployment, Service, HPA, Ingress, PVC, PDB, NetworkPolicy, canary rollouts, and Grafana.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages