Lasso es un marco de controlador.
Lasso tiene cierta paridad funcional con el proyecto de tiempo de ejecución del controlador y podría usarse en lugar de tiempo de ejecución del controlador.
Lasso es de bajo nivel. Si desea administrar sus propios controladores, puede usarlo. Si busca más comodidad y funcionalidad para crear sus propios tipos de recursos, le recomendamos consultar Wrangler.
Marco de controlador central utilizado por Wrangler y Norman.
Este documento se escribió pensando en dos audiencias: alguien que es nuevo en los controladores de Kubernetes y alguien que no es nuevo en los controladores de Kubernetes pero sí en Lasso.
Si pertenece a la categoría de "Alguien que no es nuevo en los controladores de Kubernetes", puede pasar a la propuesta de valor de Lasso.
Si es nuevo en los controladores de Kubernetes, se recomienda que no se salte ninguna sección.
Si no tiene conocimientos básicos de Kubernetes, se recomienda consultar primero otra documentación sobre los conceptos básicos, como la descripción general de Kubernetes.
Nota: Este será un curso intensivo muy breve. Te animamos a buscar otros recursos sobre el tema, ¡hay muchos! Dos recursos recomendados son el Proyecto de controlador de muestra y la Introducción a los marcos del controlador de Kubernetes.
De la documentación de Kubernetes
En Kubernetes, un controlador es un bucle de control que observa el estado compartido del clúster a través del apiserver y realiza cambios intentando mover el estado actual hacia el estado deseado.
La palabra "controlador" se usa de manera más vaga de lo que la definición anterior podría hacerle creer. En nuestras propias palabras: los controladores son controladores de bucles que actúan en respuesta a eventos de recursos de Kubernetes. En Lasso, también usamos la palabra "controlador" para referirnos a toda la estructura que se encarga de registrar este controlador de bucle y proporcionarle los recursos que necesita. En resumen, los controladores son estructuras que agrupan todo lo necesario para interactuar y operar con tipos de Kubernetes.
Para lograr el objetivo anterior, es necesario alcanzar algunos subobjetivos:
Existen muchos marcos para ayudar a lograr los objetivos anteriores. Lasso es uno de ellos. Lo que la mayoría de estos marcos tienen en común, incluido Lasso, es que utilizan la funcionalidad del cliente para lograr estos objetivos. Podrías lograr estos objetivos utilizando simplemente client-go. Durante el resto de esta sección, veremos cómo se arma un controlador simplemente usando conceptos de client-go.
Se utiliza un informador para lograr los objetivos anteriores necesarios para un controlador de Kubernetes. Un informador posee un controlador de eventos y un indexador. El indexador posee funciones de almacenamiento y mapa para indexar objetos dentro del almacén llamados indexadores. Las estructuras subyacentes son diferentes, pero a continuación se muestra una pseudoestructura para ilustrar esto:
Informer
EventHandler
Indexer
Store
Indexers
El EventHandler puede tener una lógica diferente para crear, actualizar y eliminar eventos. El controlador de eventos es donde entra en juego el controlador. Lo utiliza para configurar los controladores de eventos de creación, actualización y eliminación.
El indexador se utiliza como caché.
El almacén es donde el indexador conserva los objetos.
Los indexadores son funciones que el indexador puede utilizar para indexar objetos persistentes. Una vez indexados con un indexador, los objetos se pueden recuperar utilizando cadenas que describen una característica que le interesa al indexador.
El indexador se utilizará a menudo para recuperar un objeto mediante metadatos simples, como el espacio de nombres y el nombre.
El informador primero completa el indexador enumerando todos los recursos devueltos por un cliente. Luego, el informador observa el recurso de Kubernetes al que está asignado. Cuando llega un evento, lo utiliza para actualizar su indexador y ejecutar sus controladores de eventos.
Normalmente, una aplicación necesitaría varios controladores. Sin embargo, puede que no sea eficaz que cada controlador tenga su propio informador y, por tanto, su propio indexador. El SharedIndexerInformer de client-go se puede usar para agregar múltiples controladores que usan los mismos indexadores.
Hay una excelente imagen de cómo podría funcionar un controlador de Kubernetes en el repositorio kubernetes/sample-controller.
Nota: Los informantes se han simplificado en aras de la brevedad. Si está interesado en saber exactamente cómo funcionan, le recomendamos que lea el código de client-go.
Lasso estandariza qué es un controlador con su paquete de controladores. Lasso presenta fábricas para administrar cachés, controladores y clientes dentro de un proyecto. Esto es imperativo para el ganadero que gestiona muchas instancias de muchos tipos.
El controlador Lasso utiliza la cola de trabajo del cliente. Lasso registra un controlador de eventos que procesa la cola de trabajos. El controlador orientado a la cola de trabajo hace que solo sea necesario agregar un controlador de eventos para cada tipo de Kubernetes. Ahora, registrar un controlador simplemente lo agrega a la lista de controladores del tipo. Poner en cola un objeto lo agrega a la cola de trabajos. Luego, cada objeto en la cola de trabajo será procesado por trabajadores que se ejecutan en gorutinas. El controlador de eventos del controlador volverá a poner en cola cualquier objeto que haga que uno o más controladores del controlador devuelvan un error que no sea del tipo ErrIgnore
. Esta cola de trabajos también puede tener objetos en cola de otras fuentes. Esta funcionalidad se expone a través de la función Enqueue del controlador. Esto transforma los controladores de ser solo reactivos a los recursos de Kubernetes y resincronizaciones de caché, a ser también invocables por código.
El tiposharedController incorpora la interfaz del controlador para exponer la funcionalidad de su controlador. SharedController también expone la función RegisterHandler junto con la función Cliente. RegisterHandler agrega el controlador pasado a la lista de controladores del controlador y el Cliente devuelve un cliente para el tipo de recurso correspondiente del controlador compartido; SharedController tiene un campo GVK (Tipo de versión de grupo) que indica para qué tipo es.
El aspecto "Compartido" comienza en el controlador Lasso más primitivo. El uso de una cola de trabajo permite, por ejemplo, compartir un conjunto de controladores de eventos. Luego, el controlador compartido Lasso se suma a esto manteniendo un cliente reutilizable para GVK y agregando una forma de registrar fácilmente controladores en el controlador que se encuentra debajo con RegisterHandler.
SharedController puede crear su controlador subyacente. Solo lo hará una vez que un controlador esté registrado en el controlador compartido.
Envuelve el cliente de Kubernetes. Contiene campos GVK para administrar el cliente en una estructura principal como SharedClientFactory. Expone algunas funciones adicionales, como configurar el encabezado User-Agent para el cliente REST subyacente.
El lazo Cache es un contenedor ligero alrededor de un SharedIndexInformer de client-go.
El principal beneficio de Lasso Cache es que se le puede asignar una fábrica de caché, que administra SharedIndexInformer en la memoria mediante GVK para que puedan reutilizarse. Al utilizar las funciones de Lasso Cache, se administrará a sí mismo dentro de CacheFactory que se pasó para crearlo.
La fábrica de caché compartida almacena los cachés y permite administrarlos mediante estructuras GVK. Una vez que se hayan creado los cachés, se podrán reutilizar.
La Fábrica de Clientes Compartidos existe para que un cliente para un GVK pueda reutilizarse después de haber sido creado.
SharedControllerFactory une todo lo anterior. Permite un único punto de entrada para acceder a clientes, cachés y controladores, todo lo cual administra por usted. Es posible interactuar principalmente con la fábrica de controladores compartidos. Creará todos los controladores, clientes y cachés subyacentes que necesita. Se asegurará de que no haya duplicados de estos objetos. Prevendrá condiciones de carrera.
Una vez que use ForObject, ForKind, ForResource o ForResourceKind, SharedControllerFactory hará lo siguiente:
DeferredController es una función que, una vez ejecutada, creará y devolverá un controlador. Creará el controlador utilizando un caché de SharedCacheFactory. El propósito de la función deferredController es posponer el llenado del caché hasta que sea absolutamente necesario. Esto garantiza que solo se almacenen en la memoria los recursos de Kubernetes que tengan controladores registrados, que estén en cola o que hayan solicitado la memoria caché de su controlador.
Cuando obtienes un controlador compartido de SharedControllerFactory, todavía no se creará una instancia de un controlador subyacente. En su lugar, llamará al método deferredController para crear uno una vez que se realice una de las operaciones mencionadas.
A continuación se detallan los pasos para registrar controladores de una manera sencilla y ejecutarlos en Lasso:
package main
import (
"context"
"github.com/rancher/lasso/pkg/controller"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
)
func main () {
config , err := clientcmd . BuildConfigFromFlags ( "" , os . Getenv ( "KUBECONFIG" ))
if err != nil {
panic ( err )
}
// Setup types you want to work with
scheme := runtime . NewScheme ()
appsv1 . AddToScheme ( scheme )
controllerFactory , err := controller . NewSharedControllerFactoryFromConfig ( config , scheme )
if err != nil {
panic ( err )
}
// ForObject, ForKind, ForResource, and ForResourceKind can all be used to retrieve the controller.
// They all accept different parameters but the first three all eventually call ForResourceKind.
// Refer to [How to use Lasso](#how-to-use-lasso) for more information on how ForResourceKind works.
sharedController , err := controllerFactory . ForObject ( & appsv1. Deployment {})
if err != nil {
panic ( err )
}
// Register a handler on a shared controller. If you need a dedicated queue then use controller.New()
sharedController . RegisterHandler ( context . TODO (), "my-handler" , controller . SharedControllerHandlerFunc ( func ( key string , obj runtime. Object ) (runtime. Object , error ) {
// obj is the latest version of this obj in the cache and MAY BE NIL when an object is finally deleted
dep , ok := obj .( * appsv1. Deployment )
if ! ok {
return obj , nil
}
// Do some stuff ...
// Get stuff from the cache
sharedController . Informer (). GetStore (). Get ( key )
result := & appsv1. Deployment {}
err := sharedController . Client (). Update ( ctx , dep . Namespace , dep , result , metav1. UpdateOptions {})
// return the latest version of the object
return result , err
}))
// the second, int parameter is the number of workers to be used for EACH controller.
err = controllerFactory . Start ( context . TODO (), 5 )
if err != nil {
panic ( err )
}
}
Algunas de las pruebas de Lasso utilizan envtest para ejecutarse. Envtest permite ejecutar pruebas en un servidor Kubernetes "falso" con poca o ninguna sobrecarga.
Para instalar el binario setup-envtest
requerido, use el siguiente comando:
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
Antes de ejecutar las pruebas, debe ejecutar el siguiente comando para configurar el servidor falso:
# note that this will use a new/latest version of k8s. Our CI will run against the version of k8s that corresponds to lasso's
# current client-go version, as seen in scripts/test.sh
export KUBEBUILDER_ASSETS= $( setup-envtest use -p path )
Los siguientes recursos fueron útiles para escribir estos documentos. Son muy recomendables para aprender más de lo que aquí se presenta: