Self-hosted service
kubernetes/sample-controller avatar
kubernetes/sample-controller

kubernetes/sample-controller: the reference Foo controller for CRD authors

Repository for sample controller. Complements sample-apiserver

3,517 stars1,212 forksGoApache-2.0

At a glance

What is it?
kubernetes/sample-controller is the upstream Kubernetes example of a controller that watches a Foo custom resource and reconciles Deployments from it. It is a teaching artifact and a code-generation template, not a product you deploy.
Who is it for?
Adopt it as a reading exercise and as the starting shape of your own controller, and only after you have confirmed the code-generator layout works in your module. Do not adopt it as a running component: it is a staged, read-only mirror, contributions go to kubernetes/kubernetes, and the Foo type exists to be copied, not deployed.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • kubernetes/sample-controller3,517 ★ · +1
Star history
Repository2026-09-242026-11-13
kubernetes/sample-controller3.5k3.5k

1 Stars in the last 50 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What kubernetes/sample-controller actually is, and who should read it

The README opens with a warning: this is an automatically published staged repository for Kubernetes, read-only for importing, and contributions belong in the main Kubernetes repository. That single sentence sets the terms. You are not looking at a library with a release cadence. There are no releases. The last push was on 2026-09-10, and the repository is not archived, but the content moves because it is staged from kubernetes/kubernetes, not because a maintainer here accepts patches.

The problem it solves is pedagogical. Writing a Kubernetes controller means wiring together a typed client, informers, listers, work queues and event handlers, and every one of those pieces has a correct shape that is easy to get subtly wrong. sample-controller implements one complete, minimal controller for a custom resource of type Foo, backed by a CustomResourceDefinition, and the README states its purpose plainly: this is an example of how to build a kube-like controller with a single type. It demonstrates registering a Foo type, creating, getting and listing Foo instances, and setting up a controller that handles create, update and delete events.

The audience is narrow and specific. If you are about to write your first custom controller and you want to see the whole skeleton in one repository, this is the skeleton. If you want a controller framework with batteries included, this is the wrong repository, and the README does not pretend otherwise.

The client-go machinery behind the Foo controller

The README says the sample uses client-go extensively and points to docs/controller-client-go.md for the interaction points. The repository layout confirms the split: controller.go holds the controller, main.go wires it up, and pkg/ holds the API types and generated code.

The data flow is the standard client-go pattern. A shared informer watches Foo resources through the generated client and feeds a work queue; the controller pops keys, looks the object up through a lister, and reconciles. Reconciliation here means creating, updating or deleting a Deployment that corresponds to the Foo. The README's running instructions end with kubectl get deployments, which is the observable result of that loop.

The generated layer is not hand-written. The README states that the project uses the generators in k8s.io/code-generator to produce a typed client, informers, listers and deep-copy functions, and that ./hack/update-codegen.sh produces pkg/apis/samplecontroller/v1alpha1/zz_generated.deepcopy.go and the pkg/generated/ tree. It also warns that changes should not be made to those files manually, and that when you base your own controller on this implementation you should run the script rather than copy the files. That is the most transferable instruction in the repository. go.mod pins k8s.io/code-generator, k8s.io/client-go, k8s.io/api and k8s.io/apimachinery, so the generator and the runtime libraries move together.

The API version is v1alpha1 in the CRD, and the README notes it can be evolved to a stable v1 using CRD versioning. That is a deliberate starting point, not an oversight.

Installing kubernetes/sample-controller and running your first Foo

There is no package to install. The README tells you to clone the repository and build the binary from source, and it notes that go-get or vendor this package as k8s.io/sample-controller. Start with the clone:

bash
git clone https://github.com/kubernetes/sample-controller
cd sample-controller

The README assumes a working kubeconfig, and says it is not required if you are operating in-cluster. The cluster must be newer than 1.9 because the sample uses apps/v1 Deployments. Build and start the controller against your kubeconfig:

bash
go build -o sample-controller .
./sample-controller -kubeconfig=$HOME/.kube/config

With the controller running, create the CustomResourceDefinition. The README uses the status-subresource variant in its running steps; crd.yaml is the alternative that carries validation.

bash
kubectl create -f artifacts/examples/crd-status-subresource.yaml

Then create a Foo and look at what the controller produced. The final command is the point of the exercise: if the controller is working, a Deployment appears that you never created by hand.

bash
kubectl create -f artifacts/examples/example-foo.yaml
kubectl get deployments

If you intend to generate code rather than only run the sample, the README adds a constraint: the code-generator repository must exist in an old-style location, and it suggests go mod vendor to create and populate the vendor directory. That is the step people skip, and it is the one that fails first.

Validation, the status subresource, and why UpdateStatus matters

The README is direct about validation: a structured schema is mandatory for apiextensions.k8s.io/v1. The example in crd.yaml constrains spec.replicas to an integer with a minimum of 1 and a maximum of 10. That is a small rule, but it illustrates the boundary the CRD draws around your type before your controller ever sees the object.

The status subresource is the more interesting design point. The README explains that CustomResourceSubresources is GA from v1.16, that crd-status-subresource.yaml enables /status, and that enabling it lets the controller use UpdateStatus to write only the status portion of the custom resource. It then points to the Kubernetes API conventions for the reasoning behind separating spec from status. The practical consequence is that spec belongs to the user and status belongs to the controller, and mixing the two writes means two writers racing over one object.

A detail in the type-definition section catches people out. The README states that the json tag is required on all user-facing fields, and that when the tag is omitted Kubernetes generators treat the field as internal and will not expose it in generated external output or in a generated CRD schema. A field with no json tag will simply not appear where you expect it. That is a silent failure, not a compile error, and it is worth checking before you debug anything else.

Where sample-controller is the wrong tool

The repository is read-only for importing and not used for direct contributions. If you file an issue or open a pull request here, the README says contributions should go to kubernetes/kubernetes instead. Treat any fork of this repository as a dead end for upstream work.

The Foo type is a teaching device. It has no meaning outside the example, and the README says as much by framing the whole thing as a demonstration of basic operations. There is no production story here: no release artifacts, no versioned tags, no upgrade path for the binary. If you copy controller.go into a service and ship it, you have adopted example code as a dependency, and the README's own instruction is to generate your own files rather than copy them.

The API version is v1alpha1. The README notes it can be evolved to v1 using CRD versioning, which means conversion and storage-version decisions are yours to make. Nothing in the repository does that for you.

Finally, the generated code is tied to the pinned k8s.io/code-generator revision in go.mod. Moving that dependency forward is a code-generation change, not a routine version bump, and the README's warning about not editing generated files manually means you cannot patch your way around a generator mismatch.

sample-controller against Kubebuilder and controller-runtime

The closest real alternative for the same job is Kubebuilder, which scaffolds a controller project on top of controller-runtime. The difference is in what you get and what you owe.

sample-controller gives you the raw client-go path: informers, listers, work queues and generated clients, all visible in the repository, with a script that regenerates the typed layer. You see every wire. The cost is that you also maintain every wire, and the code-generator layout requirement (the old-style location, the vendor directory) is a real setup burden that the README acknowledges rather than hides.

controller-runtime, which Kubebuilder uses, abstracts the informer and queue plumbing behind a reconciler interface and a manager. You write less code and inherit a set of conventions about watches, predicates and status updates. You also see less of the machinery when it misbehaves, and the generated-client approach in sample-controller is what you would reach for if you want the client-go idioms visible in your own codebase.

Both approaches end at the same place: a controller reconciling a custom resource against real cluster state. The choice is whether you want the client-go primitives in front of you or behind an interface. For a first controller, seeing them is the reason to read this repository.

Maintenance, licensing, and what the staged status means for upgrades

The repository is licensed Apache-2.0, with the LICENSE file at the top level. That is the same licence as the Kubernetes project it is staged from, and it permits commercial use and modification. This is a description of the licence file, not legal advice; check the terms yourself if your organisation has specific requirements.

Maintenance is the part to think about carefully. The last push was on 2026-09-10, so the code is current, but the update mechanism is not a maintainer merging your patch. The README states that this is an automatically published staged repository and that contributions belong in kubernetes/kubernetes. Upgrades arrive when the staging process republishes, which means you cannot pin to a tag and expect a changelog. The repository has no published GitHub releases.

The practical upgrade cost sits in go.mod. The k8s.io/api, k8s.io/apimachinery, k8s.io/client-go and k8s.io/code-generator entries are pinned to specific pseudo-versions, and the module declares go 1.27.0. When you base a real controller on this code, you inherit that pinning. Every time you move the Kubernetes libraries forward, you re-run ./hack/update-codegen.sh and review the diff in pkg/generated/, because the README forbids editing those files by hand. Budget for that regeneration step as part of the upgrade, not as an afterthought.

Editorial conclusion

Adopt it as a reading exercise and as the starting shape of your own controller, and only after you have confirmed the code-generator layout works in your module. Do not adopt it as a running component: it is a staged, read-only mirror, contributions go to kubernetes/kubernetes, and the Foo type exists to be copied, not deployed. Verify first that your cluster accepts apiextensions.k8s.io/v1 CRDs with a structural schema, then run ./hack/update-codegen.sh in your own repository before you write a single handler.

Frequently asked questions

What does kubernetes/sample-controller do?

It implements a simple controller that watches Foo resources defined by a CustomResourceDefinition, and it demonstrates registering the type, creating, getting and listing Foo instances, and handling create, update and delete events. The README describes it as an example of how to build a kube-like controller with a single type.

How do I create my own controller based on kubernetes/sample-controller?

The README says not to copy the generated files, and to run ./hack/update-codegen.sh to generate your own typed client, informers, listers and deep-copy functions. It also notes that generating code requires the code-generator repository in an old-style location, which go mod vendor can provide.

What are examples of controllers in Kubernetes?

The README gives use cases for custom resource types rather than a list of built-in controllers: provisioning and managing external datastores such as CloudSQL or RDS instances, and higher level abstractions around Kubernetes primitives, for example a single resource defining an etcd cluster backed by a Service and a ReplicationController.

What is the most used controller in Kubernetes?

The README does not rank controllers or name the most used one. It only describes the single Foo controller implemented in this repository and the client-go mechanisms it relies on.

Official sources

  1. Issues
  2. kubernetes/sample-controller on GitHub
  3. License: Apache-2.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kubernetes-sample-controller.svg)](https://hysenlabs.com/projects/kubernetes-sample-controller)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/kubernetes-sample-controller.svg)](https://hysenlabs.com/projects/kubernetes-sample-controller)

Was this useful?