Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ kind-down:

.PHONY:
deploy-kind: kind-up docker-push
kubectl apply --context kind-my-app -f configs/...
kubectl apply --context kind-my-app -f configs/crd/app.yaml
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,39 @@ You are the head of your dev ops department, and you'd like to provide your engi

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.

1. What are the event types that the reconciler can recieve?
1. What are the event types that the reconciler can recieve: Controller Request

1. Which controller option controls how often Level-based reconciliation occurs?
1. Which controller option controls how often Level-based reconciliation occurs: Resync after
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at this article https://www.redhat.com/en/blog/kubernetes-operators-best-practices#:~:text=Deriving%20from%20electronic%20circuit%20design,reacting%20to%20a%20state%20variation.

So level based reconciliation happens periodically, without an event occurring. Can you find the option for this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In older versions of controller runtime there was a resync option while creating a manager it used to be directly accessible through ctrl.Options but now it has to be done through the cache option and I used it in my kubebuilder implementation. During the creation of the manager I added the following option: Cache: cache.Options{
SyncPeriod: &syncPeriod}


1. Which event types are passed in on level based reconciliation?
1. Which event types are passed in on level based reconciliation: Update, Create, Delete for edge based reconciliation but for level based it should be started periodically

1. What is the difference between the `builder.Builder`'s `For`, `Owns` and `Watches` methods?
1. What is the difference between the `builder.Builder`'s `For`, `Owns` and `Watches` methods: For is for which resource kind is used i.e MyApps, Owns: the MyApp will own the CRs instances,

1. 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?
1. 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?: The events will be added to the reconciliation queue and will be handled in order for the atest version of the object
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that correct? That it will send 10 updates all with the newest version?

I actually forget the answer here so just double checking. I thought it coalesced into a single event with the latest update.

If you want help recreating this scenario we can do it :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it does coalesce into a single event. I know if some of the updates include similar changes let's say 6 update change the number of replicas of the same deployment for example, the controller will go with the latest change to the number of replicas but if the remaining 4 updates include different changes they would also be included. So maybe all the updates and merged into one to reach the latest desired state. I would love to recreate it


1. How can you control the speed of reconciliation?
1. How can you control the speed of reconciliation: Requeue after or SyncPeriod

1. How can you retry a failed reconiliation at a later time?
1. How can you retry a failed reconiliation at a later time: Requeue after

1. What happens to child objects if you delete a watched object?
1. What happens to child objects if you delete a watched object: the child will also be deleted

1. Does the reconciler trigger on updates to the watched object, updates to the child object, or both?
1. Does the reconciler trigger on updates to the watched object, updates to the child object, or both? both

1. 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)
1. 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) the child will be delted but not the child of the child. The reconciler doesn't trigger on the updates for children of children. If there are ny updates that conflict with the intent they will be handled in the next reconciliation cycle

1. What happens if a Reconciliation fails, and new updates come in?
1. What happens if a Reconciliation fails, and new updates come in? the update during which the error occured would be requeued for reconciliation. In any case the controller will eventully bring the resource to the desired state

1. What happens if a reconciliation fails to a child's child objects (ie: a deployments pods)?
1. What happens if a reconciliation fails to a child's child objects (ie: a deployments pods)? the controller will retry / we see that myapp-sample-2 pods keep getting restarted because of their low time span and kubernetes thinks they're crashing

1. If a single resource is in a failed state, does it block reconciliation of other objects?
1. If a single resource is in a failed state, does it block reconciliation of other objects? No

1. 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?
1. 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?API call
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or from the cache, which maintains the state of the most recent data.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I added the cache option to my manager declaration I thought it wasn't enabled by default but I guess it is


1. What metrics does the controller runtime emit? Describe what some of those metrics represent
1. What metrics does the controller runtime emit? Describe what some of those metrics represent: Reconcile time: how long reconciliation took, controller_runtime_reconcile_total Total number of reconciliations per controller, go_gc_duration_seconds A summary of the pause duration of garbage collection cycles, go_goroutines Number of goroutines that currently exist, workqueue_depth Current depth of workqueue, workqueue_longest_running_processor_seconds How many seconds has the longest running processor for workqueue been running, workqueue_queue_duration_seconds How long in seconds an item stays in workqueue before being requested, workqueue_unfinished_work_seconds How many seconds of work has been done that is in progress and hasn't been observed by work_duration. Large values indicate stuck threads. One can deduce the number of stuck threads by observing the rate at which this increases, workqueue_work_duration_seconds How long in seconds processing an item from workqueue takes.
controller_runtime_terminal_reconcile_errors_total Total number of terminal reconciliation errors per controller
TYPE controller_runtime_terminal_reconcile_errors_total counter
controller_runtime_terminal_reconcile_errors_total{controller="myapp"} 0

1. What is leader election, and when would you use it?
1. What is leader election, and when would you use it? It is used to designate one instance of a controller as the leader to perform reconciliation, change cluster state, etc... It is used in distributed systems to prevent conflicts and ensure consistency

1. What is the difference between Kubebuilder and controller runtime?
3 changes: 3 additions & 0 deletions cmds/my-app-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import (
"context"

"github.com/steeling/controller-runtime-exercise/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

func main() {
log.SetLogger(zap.New(zap.UseDevMode(true)))
ctx := context.Background()
// Create a new controller
c, err := controller.New()
Expand Down
17 changes: 16 additions & 1 deletion configs/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: example.com/v1alpha1
kind: MyApp
metadata:
name: myapp-sample
namespace: default
spec:
image: busybox
replicas: 2
Expand All @@ -13,17 +14,31 @@ apiVersion: example.com/v1alpha1
kind: MyApp
metadata:
name: myapp-sample-2
namespace: default
spec:
image: busybox
replicas: 2
args:
- sleep
- "5"
- "100"
---
apiVersion: example.com/v1alpha1
kind: MyApp
metadata:
name: myapp-sample-3
namespace: default
spec:
image: busybox
replicas: 3
args:
- sleep
- "10000"
---
apiVersion: example.com/v1alpha1
kind: MyApp
metadata:
name: myapp-bad-pod
namespace: default
labels:
reconciler: ignore
spec:
Expand Down
57 changes: 31 additions & 26 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,66 @@ module github.com/steeling/controller-runtime-exercise

go 1.22.2

require sigs.k8s.io/controller-runtime v0.18.4
require (
github.com/prometheus/client_golang v1.19.1
k8s.io/api v0.31.0
k8s.io/apimachinery v0.31.0
k8s.io/client-go v0.31.0
sigs.k8s.io/controller-runtime v0.19.0
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.3.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.33.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.30.1 // indirect
k8s.io/apiextensions-apiserver v0.30.1 // indirect
k8s.io/apimachinery v0.30.1 // indirect
k8s.io/client-go v0.30.1 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/apiextensions-apiserver v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
Loading