Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Generic libraries for building idiomatic Kubernetes controllers

License

NotificationsYou must be signed in to change notification settings

authzed/controller-idioms

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Report CardGo DocumentationDiscord ServerTwitter

Watch a short overview of controller-idioms on CNCF's YouTube

controller-idioms is a collection of generic libraries that complement and extend fundamental Kubernetes libraries (e.g.controller-runtime) to implement best practices for Kubernetes controllers.

These libraries were originally developed byAuthzed to build theSpiceDB Operator and their internal projects poweringAuthzed Dedicated.

Available idioms include:

  • adopt: efficiently watch resources the controller doesn't own (e.g. references to a secret or configmap)
  • bootstrap: install required CRDs and default CRs typically for CD pipelines
  • component: manage and aggregate resources that are created on behalf of another resource
  • fileinformer: an InformerFactory that watches local files typically for loading config without restarting
  • hash: hashing resources to detect modifications
  • metrics: metrics for resources that implement standardmetav1.Condition arrays
  • pause: handler that allows users stop the controller reconciling a particular resource without stopping the controller
  • static: controller for "static" resources that should always exist on startup

Have questions? Join ourDiscord.

Looking to contribute? SeeCONTRIBUTING.md.

Overview

Handlers

AHandler is a small, composable, reusable piece of a controller's state machine.It has a simple, familiar signature:

func (h*MyHandler)Handle(context.Context) {// do some work}

Handlers are similar to anhttp.Handler or agrpc.UnaryHandler, but can pass control to another handler as needed.
This allows handlers to compose in nice ways:

funcmainControlLoop(ctx context.Context) {handler.Chain(validateServiceAccount,handler.Parallel(createJob,createPersistentVolume,         )    ).Handle(ctx)}

Thehandler package contains utilities for building, composing, and decorating handlers, and for building large state machines with them.See thedocs for more details.

Handlers take some inspiration fromstatecharts to deal with the complexity of writing and maintaining controllers, while staying close to golang idioms.

Typed Context

Breaking a controller down into small pieces withHandlers means that each piece either needs to re-calculate results from other stages or fetch the previously computed result fromcontext.

Thetypedctx package provides generic helpers for storing / retrieving values from acontext.Context.

varCtxExpensiveObject=typedctx.NewKey[ExpensiveComputation]()func (h*ComputeHandler)Handle(ctx context.Context) {ctx=CtxExpensiveObject.WithValue(ctx,myComputedExpensiveObject)}func (h*UseHandler)Handle(ctx context.Context) {precomputedExpensiveObject=CtxExpensiveObject.MustValue(ctx)// do something with object}

Handlers are typically chained in a way that preserves the context between handlers, but not always.

For example:

varCtxExpensiveObject=typedctx.NewKey[ExpensiveComputation]()func (h*ComputeHandler)Handle(ctx context.Context) {ctx=CtxExpensiveObject.WithValue(ctx,myComputedExpensiveObject)}func (h*DecorateHandler)Handle(ctx context.Context) {ComputeHandler{}.Handle(ctx)// this fails, because the ctx passed into the wrapped handler isn't passed back outCtxExpensiveObject.MustValue(ctx)}

To deal with these cases,typedctx provides aBoxed context type that instead stores a pointer to the object, with additional helpers for making a "space" for the pointer to be filled in later.

varCtxExpensiveObject= typedctx.Boxed[ExpensiveComputation](nil)func (h*ComputeHandler)Handle(ctx context.Context) {ctx=CtxExpensiveObject.WithValue(ctx,myComputedExpensiveObject)}func (h*DecorateHandler)Handle(ctx context.Context) {// adds an empty pointerctx=CtxExpensiveObject.WithBox(ctx)// fills in the pointer - note that the implementation of ComputeHandler didn't changeComputeHandler{}.Handle(ctx)// now this succeeds, and returns the unboxed valueCtxExpensiveObject.MustValue(ctx)}

Typed Informers, Listers, Indexers

Thetyped package converts (dynamic) kube informers, listers, and indexers into typed counterparts via generics.

informerFactory:=dynamicinformer.NewFilteredDynamicSharedInformerFactory(client,defaultResync,namespace,tweakListOptions)indexer:=informerFactory.ForResource(corev1.SchemeGroupVersion.WithResource("secrets")).Informer().Indexer()secretIndexer:= typed.NewIndexer[*corev1.Secret](indexer)// secrets is []*corev1.Secret instead of unstructuredsecrets,err:=secretIndexer.ByIndex("my-index-name","my-index-value")

Controllers and Managers

Themanager package provides an optional lightweight controllerManager abstraction (similar to kubernetes controller manager, or the manager from controller runtime). It also provides a simpleController abstraction and some basic implementations.

The rest ofcontroller-idioms can be used without using these if you are already using another solution.

Manager

  • provides a way to start and stop a collection of controllers together
  • controllers can be dynamically added/removed after the manager has started
  • starts health / debug servers that tie into the health of the underlying controllers

BasicController

  • provides default implementations of health and debug servers

OwnedResourceController

  • implements the most common pattern for a controller: reconciling a single resource type via a workqueue
  • has a single queue managing a single type
  • on start, starts processing objects from the queue
  • doesn't start any informers

Informer Factory Registry

It can be useful to access the informer cache of one controller from another place, so that multiple controllers in the same binary don't need to open separate connections against the kube apiserver and maintain separate caches of the same objects.

Thetyped package provides aRegistry that synchronizes access to shared informer factories across multiple controllers.

Queue

Thequeue package provides helpers for working with client-go'sworkqueues.

queue.OperationsContext can be used from within aHandler to control the behavior of the queue that has called the handler.

The queue operations are:

  • Done (stop processing the current key)
  • Requeue (requeue the current key)
  • RequeueAfter (wait for some period of time before requeuing the current key)
  • ReqeueueErr (record an error and requeue)
  • RequeueAPIError (requeue after waiting according to the priority and fairness response from the apiserver)

If calling these controls from a handler, it's important toreturn immediately so that the handler does not continue processing a key that the queue thinks has stopped.

Middleware

Middleware can be injected between handlers with themiddleware package.

middleware.ChainWithMiddleware(middleware.NewHandlerLoggingMiddleware(4),)(c.checkPause,c.adoptSecret,c.validate).Handle(ctx)

[8]ページ先頭

©2009-2025 Movatter.jp