WebApp Operator is a simple Kubernetes operator built with Go and Kubebuilder. It introduces a custom resource named WebApp that lets a user declare an application image, replica count, and port, while the operator automatically creates and manages the corresponding Kubernetes Deployment and Service.
Instead of manually creating multiple Kubernetes resources, the user only defines a single WebApp object. The operator watches that object, creates the required resources, keeps them in sync, updates status, and cleans everything up when the WebApp is deleted.
A user creates a custom resource like this:
apiVersion: apps.example.com/v1alpha1
kind: WebApp
metadata:
name: my-nginx-app
spec:
image: nginx:latest
replicas: 3
port: 80
status:
phase: Running
readyReplicas: 3The operator will:
- π Watch the
WebAppresource - π¦ Create a
Deploymentwith the requested image and replicas - π Create a
Serviceexposing the requested port - π Reconcile changes continuously
- π Update
status.phaseandstatus.readyReplicas - π§Ή Clean up owned resources when the
WebAppis deleted
If the user changes:
replicas: 3to:
replicas: 5the operator automatically updates the Deployment so the application scales to 5 pods.
This project demonstrates the Kubernetes Operator pattern, where a custom resource and a controller work together to automate application lifecycle management. Kubernetes operators commonly use CRDs plus reconciliation loops to turn high-level user intent into actual cluster state.
This operator has the following:
- one custom resource
- one controller
- one managed
Deployment - one managed
Service - status updates
- cleanup behavior through owner references and reconciliation
- Go
- Kubernetes
- Kubebuilder
- controller-runtime
- CRDs
- Deployments
- Services
- Docker
- Kustomize
- Makefile
flowchart LR
User["User applies WebApp YAML"] --> API["Kubernetes API Server"]
API --> Operator["WebApp Operator"]
Operator --> Deployment["Deployment"]
Operator --> Service["Service"]
Operator --> Status["WebApp Status"]
- User applies a
WebAppcustom resource. - Kubernetes stores it through the CRD.
- The operator watches the new object.
- The operator creates or updates the matching
Deployment. - The operator creates or updates the matching
Service. - The operator updates
status.phaseandstatus.readyReplicas.
.
βββ api/ API definitions for the WebApp CRD
βββ cmd/ Operator entrypoint
βββ config/ CRD, RBAC, manager, and sample manifests
βββ internal/controller/ Reconciliation logic
βββ hack/ Boilerplate headers
βββ bin/ Generated binaries/tools
βββ Dockerfile Container image build
βββ Makefile Common development commands
βββ PROJECT Kubebuilder project metadata
βββ go.mod Go module definition
βββ README.md Project documentation
The custom resource is WebApp.
These fields are declared by the user:
image: container image to runreplicas: number of pod replicasport: container port to expose
These fields are written by the operator:
phase: high-level state such asPending,Running, orDegradedreadyReplicas: number of ready podsconditions: standard Kubernetes conditions array
apiVersion: apps.example.com/v1alpha1
kind: WebApp
metadata:
name: my-nginx-app
spec:
image: nginx:latest
replicas: 3
port: 80Apply it with:
kubectl apply -f config/samples/apps_v1alpha1_webapp.yamlFor each WebApp, the operator creates:
- a
Deployment - a
Service
For example, for:
metadata:
name: my-nginx-appthe operator may create:
Deployment/my-nginx-appService/my-nginx-app
These resources are continuously reconciled. If someone changes them manually, the operator will move them back toward the desired state defined in the WebApp resource.
The controller follows the standard reconciliation model used by Kubernetes operators [web:208][web:207]:
- Fetch the
WebAppresource - Check whether the target
Deploymentexists - Create or update the
Deployment - Check whether the target
Serviceexists - Create or update the
Service - Read current pod readiness
- Update
WebApp.status - Requeue on future changes automatically through watches
This design keeps the system idempotent: running reconciliation multiple times should still lead to the same desired state.
The operator should set owner references from the Deployment and Service back to the WebApp. That way, when the WebApp is deleted, Kubernetes garbage collection can clean up the owned resources automatically, which is a common controller pattern.
Install these tools first:
brew install go kubectl kustomize kindInstall Kubebuilder if needed:
brew install kubebuilderOptional but useful:
go install sigs.k8s.io/controller-tools/cmd/controller-gen@latestCheck your cluster access:
kubectl cluster-info
kubectl get nodesgit clone https://github.com/<your-username>/webapp-operator.git
cd webapp-operatorgo mod tidy
go mod downloadkind create cluster --name webapp-operatorVerify access:
kubectl cluster-info
kubectl get nodesGenerate deepcopy code and CRD-related artifacts:
make generate
make manifestsThese commands use controller-gen, which is the standard way Kubebuilder projects generate API and manifest artifacts [web:179][web:168].
Format and validate the code:
make fmt
make vetRun tests:
make testInstall the CRD into the current cluster:
make installRun the controller locally against your current kubeconfig:
make runThis starts the operator process on your machine, but it will manage resources inside the Kubernetes cluster pointed to by your kubeconfig.
Build the operator image:
make docker-build IMG=webapp-operator:latestLoad the image into kind:
kind load docker-image webapp-operator:latest --name webapp-operatorDeploy the operator:
make deploy IMG=webapp-operator:latestCheck the operator pod:
kubectl get pods -n webapp-operator-systemCreate the sample resource:
kubectl apply -f config/samples/apps_v1alpha1_webapp.yamlCheck the custom resource:
kubectl get webapps
kubectl get webapp my-nginx-app -o yamlCheck the resources created by the operator:
kubectl get deploy
kubectl get svc
kubectl get podsDescribe the custom resource:
kubectl describe webapp my-nginx-appEdit the resource:
kubectl edit webapp my-nginx-appChange:
replicas: 3to:
replicas: 5Then verify scaling:
kubectl get deploy
kubectl get pods
kubectl get webapp my-nginx-app -o yamlThe operator should reconcile the change and update the deployment replica count automatically.
Delete the custom resource:
kubectl delete webapp my-nginx-appThen verify cleanup:
kubectl get webapps
kubectl get deploy
kubectl get svcIf owner references are configured correctly, the related Deployment and Service should also be removed.
kind create cluster --name webapp-operatorkind delete cluster --name webapp-operatormake generatemake manifestsmake fmtmake vetmake testmake installmake runmake deploy IMG=webapp-operator:latestmake undeployCheck operator logs:
kubectl logs -n webapp-operator-system deploy/webapp-operator-controller-managerCheck CRD:
kubectl get crd
kubectl get crd webapps.apps.example.comCheck all related resources:
kubectl get webapps,deploy,svc,podsInspect a resource:
kubectl get webapp my-nginx-app -o yaml
kubectl get deploy my-nginx-app -o yaml
kubectl get svc my-nginx-app -o yaml- Add finalizers for explicit cleanup control
- Add validation for image and port fields
- Add support for environment variables and resource requests
- Add Ingress generation
- Add status conditions for rollout progress
- Add unit and e2e tests
- Add Helm packaging for operator installation
- Add Prometheus metrics for reconciliation behavior
This project is useful for understanding:
- Kubernetes CRDs
- Kubernetes operators
- reconciliation loops
- controller-runtime
- status subresources
- Deployments and Services
- owner references
- declarative infrastructure patterns
A realistic Kubernetes operator project. It shows how to extend the Kubernetes API with a custom resource and automate application lifecycle management through a controller, which is the core idea behind the operator pattern.