Créer un opérateur Kubernetes

Photo by Pixabay from Pexels

TL;DR: Cet article présente comment créer et installer un opérateur Kubernetes avec operator-sdk

Créer un opérateur revient à étendre le fonctionnement de Kubernetes à l'aide de Controllers spécifiques et de Custom Resource Definitions pour gérer des applications "nativement". Par exemple un opérateur MySQL permettra d'installer et mettre à jour une instance MySQL. Il pourra aussi gérer les sauvegardes, faciliter une restauration, mettre en place des réplicats ou alimenter la supervision. Gérer des bases de données deviendra aussi simple que de gérer un "deployment".

Il existe des opérateurs pour MySQL comme pour des dizaines d'autres applications. Quelques-uns sont référencés dans le projet awesome-operators. Même si le concept d'opérateurs date de 2016, l'utilisation ne fait que démarrer. Plusieurs raison à cela : il fallait que Kubernetes soit une plateforme mature ; remplacer des Ops par des opérateurs est un challenge ; les frameworks de création et la programmation d'opérateurs nécessite encore de se démocratiser.

La page CoreOS Operators présente les opérateurs comme a method of packaging, deploying and managing a Kubernetes application. Ce changement indique le premier challenge des opérateurs : facile à utiliser. L'apparition d'opérateurs pour gérer des opérateurs comme kudo, metacontroller ou Operator Lifecycle Manager adresse désormais ce point. Conséquence directe, plus en plus de projets utilisent cette idée pour monter en charge.

Les sections ci-dessous illustrent comment créer l'ossature d'un opérateur en Go avec le projet operator-sdk. Il existe plusieurs autres modèles d'opérateurs comme Kopf ou Kubebuilder qui doit converger avec operator-sdk. N'hésitez pas à explorer ces projets si vous voulez allez plus loin ou si vous préfèrez dév

Important: pour construire des opérateurs avec operator-sdk, regardez la page getting-started de operator-framework

Installer operator-sdk

Cet exemple s'appuie sur git, Go, kubectl et un cluster kubernetes. L'étape suivante consiste à installer operator-sdk. Il suffit pour cela de télécharger l'exécutable adéquat et à s'assurer qu'il est accessible le PATH. Par exemple, pour installer le cet outil sous un PC Linux il suffit de lancer un script comme celui ci-dessous

export OP_SDK=https://github.com/operator-framework/operator-sdk
export OP_VERSION=0.13.0

curl -L ${OP_SDK}/releases/download/v${OP_VERSION}/operator-sdk-v${OP_VERSION}-x86_64-linux-gnu \
  -o $HOME/.bin/operator-sdk

chmod +x $HOME/.bin/operator-sdk

operator-sdk version

export GOROOT=$(go env GOROOT)

Note: operator-sdk, dans sa version actuelle, a un problème connu décrit dans operator-sdk with go modules; Pour qu'il fonctionne correctement dans tous les cas, il faut mettre à jour la variable GOROOT pour éviter ce message deepcopy.go Hit an unsupported type invalid type for invalid type

Créer un opérateur

Le code de cet exemple est disponible dans le répertoire blog/bot-operator du projet easyteam-fr/side-effects Pour créer la structure du projet, lancer la commande ci-dessous en prenant soin, si vous utilisez les modules Go, d'ajouter au flag --repo l'arborescence de votre projet:

export SUBPROJECT=github.com/easyteam-fr/side-effects/blog/bot-operator
cd github.com/easyteam-fr/side-effects/blog
operator-sdk new bot-operator --repo=$SUBPROJECT

La structure de l'arborescence générée par operator-sdk est décrite dans Project Scaffolding Layout for Operator SDK

Créer une "Custom Resource"

L'étape suivante consiste à créer la structure de la "Custom Resource" associée à l'opérateur. Cet exemple gère une flotte de bots. Il s'agit donc du créer une Custom Resource Definition pour représenter un bot. La commande ci-dessous crée l'API et la structure vise associée

cd bot-operator
operator-sdk add api --help

operator-sdk add api --api-version=natives.easyteam.fr/v1alpha1 --kind=Bot

Un ensemble de fichiers est créé dans le répertoire pkg/apis. Le fichier pkg/apis/natives/v1alpha1/bot_types.go contient la structure Go qui représente un bot. Il faut ensuite modifier ces structures pour ajouter les champs recherchées. Pour représenter le bot, les 2 champs suivants sont utilisés:

  • un champ alias dans la section spec auquel on ajoute des directives de validation grâce à une syntaxe importée de Kubebuilder Generating CRD
  • un champ last_state dans la section status

Le code de bot_types.go devient:

// BotSpec defines the desired state of Bot
// +k8s:openapi-gen=true
type BotSpec struct {
	// +kubebuilder:validation:MaxLength=15
	// +kubebuilder:validation:MinLength=1
	Alias string `json:"alias,omitempty"`
}

// BotStatus defines the observed state of Bot
// +k8s:openapi-gen=true
type BotStatus struct {
	lastState string `json:"last_state,omitempty"`
}

Une fois les structures modifiées, on régènèrera le code pour intégrer l'API à Kubernetes ainsi que le fichier CRD à l'aide des commandes ci-dessous:

operator-sdk generate k8s
operator-sdk generate crds

Un exemple de resource est créé dans le répertoire deploy/crds avec le fichier natives.easyteam.fr_v1alpha1_bot_cr.yaml. Elle doit être modifiée pour correspondre à la définition précédente. Par exemple:

apiVersion: natives.easyteam.fr/v1alpha1
kind: Bot
metadata:
  name: red-bot
spec:
  alias: red

Créer un Controller

Les structures et CRD créées, l'étape suivante consiste à créer le Controller. Ici que le groupe d'API s'appelle natives.easyteam.fr, elle implémente une version v1alpha1 et gère la resource Bot:

operator-sdk add controller --api-version=natives.easyteam.fr/v1alpha1 --kind=Bot

le fichier bot_controller.go est créé dans le répertoire pkg/controller/bot. Celui-ci contiend l'implémentation de la logique Kubernetes pour gérer les resources. Dans un premier temps ce fichier ne sera pas modifié ; cela viendra plus tard.

Construire et publier l'opérateur

La commande operator-sdk permet de construire et faire un package avec l'opérateur:

operator-sdk build quay.io/easyteam/bot-controller:v0.0.1

Note: Avec une distribution Linux récente telle que Fedora 31, il se peut que vous rencontriez cette issue. Cela est du au fait que Docker et Moby ne supportent pas encore la version 2 des cgroups. Si c'est le cas, il faut lancer les commande ci-après et redémarrer sudo dnf install grubby, sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=0"

Une fois l'image docker créée, il faut remplacer REPLACE_IMAGE dans le fichier deploy/operator.yaml par le nom de l'opérateur que vous déploirez, par exemple sur quay.io et pousser l'image:

sed -i 's|REPLACE_IMAGE|quay.io/easyteam/bot-controller:v0.0.1|g' deploy/operator.yaml
docker login quay.io
docker push quay.io/easyteam/bot-controller:v0.0.1

Créer un package pour l'opérateur

En plus de l'image docker, quay.io permet de publier une application qui contient l'opérateur, y compris par exemple la Custom Resource Definition. La commande ci-dessous crée le package dans le format du catalogue Operator Lifecycle Manager:

operator-sdk olm-catalog gen-csv --csv-version 0.0.1 --update-crds

Le package est inclus dans deploy/olm-catalog/bot-operator/bot-operator.package.yaml. Ce document; décrit la structure du catalogue. Pour fonctionner, vous devrez ajouter des champs suivant dans le fichier CSV ou Cluster Service Version. Son utilisé sera abordé dans un prochain article. Pour commencer, il suffit d'ajouter les champs ci-dessous au fichier bot-operator.v0.0.1.clusterserviceversion.yaml situé dans le répertoire deploy/olm-catalog/bot-operator/0.0.1:

  keywords:
  - operators
  maintainers:
  - email: contact@easyteam.fr
    name: Easyteam
  provider:
    name: Easyteam

D'autre part pour contourner certains problème vous noterez que, dans ce même fichier:

  • si c'est la première version de l'opérateur, il faut supprimer le champ replaces:
  • si ce n'est pas déjà fait, il faut supprimer provider: {}
  • il faut ajouter un champ displayName dans les éléments listé au niveau spec.customresourcedefinitions.owned[]. Par exemple displayName: Bot.

Publier l'operateur sur quay.io

Cette étape n'est pas essentielle mais elle sert pour installer l'opérateur à l'aide de Operator Lifecycle Manager. Elle consiste à publier l'opérateur comme une application. Pour cela:

  • Installer le module Python operator-courier
  • Créer un token pour se connecter à Quay.io en supposant que le mot de passe est dans la variable PASSWORD et que le namespace quay.io est easyteam.
  • Publier l'application en précisant (1) le répertoire du package, (2) le namespace quay.io, (3) le nom de l'application, (4) la version et (5) le token de connexion

Voici un exemple de mise en place:

python3 -m pip install operator-courier
export TOKEN="basic $(echo -n "easyteam:$PASSWORD"|base64)"
operator-courier push deploy/olm-catalog/bot-operator easyteam bot-operator 0.0.1 "$TOKEN"

Note: Si vous utilisez une souscription gratuite de Quay.io, vous devrez passer l'application et l'image docker "public".

Déployer et tester un opérateur

L'opérateur peut être déployé. Dans un premier temps, cela peut-être réalisé manuellement.

kubectl create -f deploy/crds/natives.easyteam.fr_bots_crd.yaml

One done, you should be able to create the resources for your operator:

kubectl create -f deploy/service_account.yaml
kubectl create -f deploy/role.yaml
kubectl create -f deploy/role_binding.yaml
kubectl create -f deploy/operator.yaml

You can then check the deployment and pods are running as expected:

kubectl get deployment
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
bot-operator   1/1     1            1           10s

kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
bot-operator-78bd7f7f4d-vvlsh   1/1     Running   0          30s

Uninstall the operator for now as it does not really do anything useful yet:

kubectl delete -f deploy/operator.yaml
kubectl delete -f deploy/role_binding.yaml
kubectl delete -f deploy/role.yaml
kubectl delete -f deploy/service_account.yaml
kubectl delete -f deploy/crds/natives.easyteam.fr_bots_crd.yaml

Lancer une évaluation de l'opérateur

scorecard aide à tester et propose des améliorations pour l'opérateur. Pour l'utiliser, il faut, là encore disposer d'un cluster kubernetes et créer un fichier .osdk-scorecard.yaml dont le contenu pourra ressembler à ce qui suit:

scorecard:
  output: json
  plugins:
    - basic:
        cr-manifest:
          - "deploy/crds/example.carnage.sh_v1alpha1_bot_cr.yaml"
    - olm:
        cr-manifest:
          - "deploy/crds/example.carnage.sh_v1alpha1_bot_cr.yaml"
        csv-path: "deploy/olm-catalog/simple-op/0.0.1/simple-op.v0.0.1.clusterserviceversion.yaml"

Pour tester l'opérateur, il suffit alors de lancer operator-sdk scorecard puis de gérer le résultat.

En attendant la suite...

Pour développer le code associé à l'opérateur, il faut ensuite se plonger dans la documentation et en particulier operator-sdk/doc. Celle-ci est très riche, à commencer par le user-guide.md et un exemple basé sur un opérateur pour memcached. Le prochain article plongera dans la publication de cet opérateur sur quay.io notamment pour l'utiliser à l'aide de Operator LifeCycle Manager.

Published under  on .

Easyteam DevOps

Easyteam DevOps