kubebuilder init. When you open the generated folder it can feel like Kubebuilder dumped a lot of files at once.
Think of this project as a labeled workbench: Kubebuilder has already placed the tools and drawers before you build the operator. You don’t need to memorize every file — just know which drawer to open for each job.
Treat this layout as a simple map: knowing where startup code, API types, reconcile logic, deployment manifests, and helper targets live is enough to get productive.
The
PROJECT file is code-generated. Avoid manual edits unless you fully understand the implications—let Kubebuilder and plugins manage this file.PROJECT file looks like:
go.mod is the parts list for a Go project. It pins dependencies such as controller-runtime and the Kubernetes client libraries.
The Makefile is the row of buttons on the bench. Targets like make manifests, make generate, make run, and make docker-build run the same workflow the same way every time. Below is an excerpt showing common variables and setup that many targets depend on:
Dockerfile is the packaging station: one stage builds the Go binary, and a smaller image runs it. This multi-stage example is the common pattern Kubebuilder projects use (slightly cleaned for clarity):
cmd/main.go is the operator’s power switch and the entry point for the controller-runtime manager. The manager owns the shared Kubernetes client, the cache, metrics and health probes, leader election, and controller registration. A minimal example showing webhook server setup looks like:
kubebuilder create api, the generated controllers will be registered from this startup code.
The config/ directory is the deployment drawer. It holds Kustomize overlays and base manifests so you can compose deployable YAML without duplicating shared pieces. For example, a config/default/kustomization.yaml often ties resources together and can include namespace, namePrefix, labels, and other resource references:
config/managercontains the controller Deployment/Pod spec.config/rbaccontains Role/ClusterRole and RoleBinding/ClusterRoleBinding yaml.config/crd/will hold generated CRD YAMLs aftermake manifests.config/samples/stores example custom resources you can apply to test controllers.
hack/boilerplate.go.txt to append license headers to generated Go files.
A sample RBAC rule in config/rbac looks like:
test/ is where end-to-end or integration tests live. .golangci.yml configures the linter used by make lint. A typical configuration that demonstrates plugin usage is:
api/ directory and no controllers/ directory. That is expected: those folders appear after you run kubebuilder create api.
api/will hold the webapp Go types (API shapes).controllers/will hold the reconciler, which is the code that reacts when a webapp changes.
Keep this map in your head: startup code in
cmd/, API shapes in api/, reconcile logic in controllers/, deployment YAML in config/, and repeatable commands in the Makefile. Once that map is clear, the scaffold stops feeling like a wall of files and starts feeling like a workbench with labeled drawers.
Use kubebuilder create api to scaffold your first API and controller.
Links and references