Controllers
A controller is a container image ctrlplane runs against your control plane. Deploy one under Controllers → Deploy a controller with a name and an image; Edit changes it later.
What your controller gets
Section titled “What your controller gets”KUBECONFIG=/var/run/tenant/kubeconfig |
A kubeconfig for your control plane. controller-runtime and client-go use it automatically. |
HOME=/var/run/tenant |
So tools that only read ~/.kube/config find the same kubeconfig. |
WATCH_NAMESPACE, POD_NAMESPACE |
Your control plane’s namespace: the one your operator may use. |
HTTPS_PROXY, HTTP_PROXY, NO_PROXY |
Only with a tunnel; see Networking. |
/var/run/secrets/kubernetes.io/serviceaccount/namespace |
The namespace, where client libraries look for it. |
These are set by ctrlplane; environment variables of yours with the same names are ignored.
Permissions: the controller is the service account
system:serviceaccount:<namespace>:<controller>, in the group ctrlplane:controllers. It may do
anything in your control plane’s namespace and with your own API types (in any namespace, since
many are cluster-scoped), and record events. It has no access to built-in cluster-wide objects.
That access comes with the certificate ctrlplane issues it: service accounts you create yourself
don’t get it.
Making your operator fit
Section titled “Making your operator fit”Most operators built with controller-runtime or kubebuilder work unchanged. Check these:
- Runs as non-root. Controllers run as user 65532, without capabilities or privilege escalation. Images that need root won’t work.
- Webhooks: set a webhook port and point your webhook configurations at the Service ctrlplane makes; see Webhooks.
- Leader election works (leases in your namespace). With one replica you can leave it off.
- Metrics: ctrlplane scrapes
:8080/metricsover HTTP. kubebuilder v4 projects default to HTTPS on:8443or no metrics: add the arguments--metrics-bind-address=:8080and--metrics-secure=false.
Settings
Section titled “Settings”-
Arguments and environment: one argument per line; environment as
KEY=valuelines. -
CPU and memory limits: your controllers share their control plane’s CPU and memory. Without limits, a controller gets an even share of what’s left; set limits to split it your way. A controller that doesn’t fit isn’t started, and the site says so.
-
Probes: liveness, readiness and startup probes, as Kubernetes YAML:
livenessProbe:httpGet: {path: /healthz, port: 8081}readinessProbe:httpGet: {path: /readyz, port: 8081}HTTP and TCP probes can’t name a
host: they always check your controller’s own pod. -
Private images: under Private image, a registry username and password or token, for example a GitHub token with
read:packagesfor ghcr.io. The registry is taken from the image name. Credentials are stored for that controller, never shown again, and deleted with it.
Updating and removing
Section titled “Updating and removing”Edit a controller to change its image or settings, and it rolls out the new version. If that version can’t start, the old one keeps running and the site shows why.
Removing a controller stops it and deletes its deployment and credentials. Your resources stay.
When it doesn’t start
Section titled “When it doesn’t start”The site shows why: ImagePullBackOff (wrong image or missing credentials), CrashLoopBackOff
with its last exit, or limits that don’t fit. Logs shows its output, including the run before
the last restart. See Troubleshooting.