This repo contains a learn-by-doing style exercise to familiarize users with the inner workings of the controller runtime. Many projects, like Argo CD, Istio, and everything that leverages the Operator Framework. The most common use case is to think of Kubernetes resources (those little yaml definitions) as defining the intended state of the world, and services that leverage the Controller Runtime are actors that will "reconcile" the state of the world to the intended state.
The Controller Runtime can leverage both level and edge based reconiliation. Edge based watches for events, like resource creation, deletion, or updates and reconciles the state of the world to match the intent. Level based periodically reads in the current intent, and reconciles so the state of the world matches the intent.
-
Create a kubernetes cluster via the Azure CLI or Azure Portal. There is optionally a command in the Makefile to deploy a KiND cluster, but it's recommended to run against a real cluster.
-
Use the commands in the Makefile to build and deploy the CRD's, Controller, and example manifests. Then continue with the steps below.
You are the head of your dev ops department, and you'd like to provide your engineers with a simpler interface for defining their services with a common set of K8s best practices. To do so, you plan to defin a new K8s resource MyApp that provides a smaller API surface, and a lot of defaults around resources, pod disruption budgets, and more.
-
Modify the
Reconcilemethod to create a Deployment with the provided image, a default set of resources (CPU and mem), and a pod disruption budget. -
Add some custom metrics to the metrics handler, and enable the metrics handler. What's an example metric you might want to keep track of?
-
Enable leader election
-
Use a custom queue that orders Reconciliation by name, lexicographically.
-
Modify the reconciler to ignore
MyApp's with labelsreconciler: ignore -
When a
MyAppis deleted, remove all children. -
Make sure the status of MyApp is kept up to date.
-
Migreate the controller runtime usage to leverage the KubeBuilder
Answer the following questions to test your understanding. You may want to tweak your code or add print/debug statements to test how it works. For each of the below questions also try to come up with an example scenario where this feature would be useful.
-
Which controller option controls how often Level-based reconciliation occurs?
-
Which event types are passed in on level based reconciliation?
-
What is the difference between the
builder.Builder'sFor,OwnsandWatchesmethods? -
What happens if 10 updates to the same object occur in rapid succession (ie: before a single Reconcile occurs)? How many times is Reconcile called, and with which version of the object?
-
How can you control the speed of reconciliation?
-
How can you retry a failed reconiliation at a later time?
-
What happens to child objects if you delete a watched object?
-
Does the reconciler trigger on updates to the watched object, updates to the child object, or both?
-
Answer the above question, but for children of children? ie: 1 controller that creates a child object, that in turn creates a child object (ie: creating a deployment, will in turn create Pods)
-
What happens if a Reconciliation fails, and new updates come in?
-
What happens if a reconciliation fails to a child's child objects (ie: a deployments pods)?
-
If a single resource is in a failed state, does it block reconciliation of other objects?
-
A ReconcileRequest only has the
NamespacedName. How do you get the full object? Is this object cached, or result in an API call to the k8s master? -
What metrics does the controller runtime emit? Describe what some of those metrics represent. You can use the kubectl port-forward command to discover this.
-
What is leader election, and when would you use it?
-
What is the difference between Kubebuilder and controller runtime?
-
How does the Pod Disruption Budget work during a rollout? What about scaling down nodes? And when evicting a pod?