Contactez-nous
-
kubernetes

Comment écrire un plugin kubectl ?

Comment écrire un plugin kubectl ?

Sommaire

Introduction

Si vous n’avez pas trouvé votre bonheur dans les plugins kubectl existants, il est assez simple de créer votre propre plugin pour kubectl. En effet, dès qu’un fichier présent dans le PATH commence par kubectl- et est exécutable, il peut être utilisé comme plugin.

Le script peut être écrit dans n’importe quel langage qui propose de créer des CLI, mais les plus utilisés sont Bash et Go. Le nom du fichier définit la commande qu’il faudra taper pour l’utiliser : un script appelé kubectl-test pourra être exécuté avec la commande kubectl test.

Cependant, il n’est pas possible de surcharger des commandes existantes dans kubectl, ni même de créer des sous-commandes de commandes existantes. Par exemple, un plugin nommé kubectl-get ne sera jamais appelé, car la commande kubectl get existante prendra le dessus.

Exemple de plugin kubectl en Bash

Nous allons maintenant voir comment créer un plugin pour kubectl en Bash.

Pour cela, on va créer un fichier nommé kubectl-hello et y copier le code suivant : 

#!/bin/bash

if [[ "$1" == "world" ]]
then
   echo "Hello World!"
   exit 0
fi

echo "Welcome to kubectl-hello"

Ce code permet d’afficher un message différent à l’utilisateur en fonction de si un argument spécifique est passé au script ou non.

Ensuite, on va rendre ce script exécutable, et le déplacer dans le PATH : 

chmod +x ./kubectl-hello

sudo mv ./kubectl-hello /usr/local/bin

On peut alors exécuter ce plugin grâce à la commande kubectl : 

# vérifier que le plugin est bien reconnu
$ kubectl plugin list
The following compatible plugins are available:

/usr/local/bin/kubectl-hello

$ kubectl hello
Welcome to kubectl-hello

$ kubectl hello world
Hello World!

 

Bien nommer son plugin kubectl

Comme nous l’avons vu précédemment, un plugin pour kubectl est simplement un script dont le nom commence par kubectl-.

Pour décider quel plugin utiliser en fonction de la commande appelée, kubectl recherche les plugins en commençant par ceux qui ont le nom le plus long. Une fois qu’un plugin a été trouvé, il est appelé en lui passant en arguments les éventuels paramètres restants.

Par exemple, si on exécute la commande kubectl a b c,  il va d’abord chercher un plugin nommé kubectl-a-b-c, puis un autre nommé kubectl-a-b, et ainsi de suite.

La recherche s’arrête également lorsqu’elle rencontre un paramètre nommé et passe le reste des arguments en paramètres au plugin.

Pour illustrer ce fonctionnement, voici un exemple : 

$ export PATH="$HOME/kubectl-plugins:$PATH"

$ kubectl plugin list
The following compatible plugins are available:

/home/xxx/kubectl-plugins/kubectl-a-b
/home/xxx/kubectl-plugins/kubectl-a-b-c

$ cat ~/kubectl-plugins/kubectl-a-b
#!/bin/bash

echo "Plugin A B"

for i in $*; do 
 echo $i
done

$ cat ~/kubectl-plugins/kubectl-a-b-c
#!/bin/bash

echo "Plugin A B C"

for i in $*; do 
 echo $i
done

$ kubectl a b c d
Plugin A B C
d

$ kubectl a b c
Plugin A B C

$ kubectl a b  
Plugin A B

$ kubectl a  
error: unknown command "a" for "kubectl"

$ kubectl a b --param=test c d
Plugin A B
--param=test
c
d

Si l’on souhaite utiliser un tiret dans le nom de notre plugin, c’est également possible, mais il faut alors le remplacer par un underscore dans le nom du fichier.

Il faut cependant garder à l’esprit qu’en utilisant cette méthode, la règle de nommage générale s’applique toujours. Le plugin pourra donc par ailleurs être appelé avec des underscores à la place des tirets dans la commande kubectl.

$ cat ~/kubectl-plugins/kubectl-my_plugin
#!/bin/bash
echo "My kubectl plugin"

$ kubectl my-plugin
My kubectl plugin

$ kubectl my_plugin
My kubectl plugin

Si votre plugin n’est pas reconnu par kubectl, la commande kubectl plugin list peut détecter les erreurs de nommage les plus fréquentes et afficher un avertissement avec les détails.

Elle peut détecter trois types d’erreurs : 

  • Un plugin a le même nom qu’une commande kubectl existante ;
  • Deux plugins utilisent le même nom ;
  • Un plugin n’est pas exécutable malgré un nom correct.
$ kubectl plugin list
The following compatible plugins are available:

/usr/local/bin/kubectl-hello
/home/xxx/kubectl-plugins/kubectl-get
 - warning: kubectl-get overwrites existing command: "kubectl get"
/home/xxx/kubectl-plugins/kubectl-hello
 - warning: /home/xxx/kubectl-plugins/kubectl-hello is overshadowed by a similarly named plugin: /usr/local/bin/kubectl-hello
/home/xxx/kubectl-plugins/kubectl-notexecutable
 - warning: /home/xxx/kubectl-plugins/kubectl-notexecutable identified as a kubectl plugin, but it is not executable
error: 3 plugin warnings were found

 

Rédiger le contenu du plugin

Certaines bonnes pratiques peuvent être adoptées afin de faciliter l’utilisation d’un plugin kubectl par la suite.

La première recommandation est d’avoir une cohérence des commandes de son plugin avec celles qui sont natives à kubectl. Par exemple, il est conseillé d’implémenter les options suivantes pour ne pas perdre les utilisateurs : 

  • -n et --namespace : pour sélectionner le namespace sur lequel les commandes s’appliqueront ;
  • -A et --all-namespaces : pour appliquer les commandes sur tous les namespaces ;
  • -h et --help : pour afficher l’aide sur l’utilisation du plugin.

En complément de ces options, il est recommandé d’afficher l’aide sur l’utilisation du plugin (identique à celle de l’option --help) lorsque l’utilisateur l’appelle sans aucun argument.

Si on est dans le cas d’un script avec une arborescence de commandes et de sous-commandes, on peut également découper le code en mettant chaque sous-commande dans un script dédié au lieu d’utiliser des conditions à l’intérieur d’un même script. Ainsi, on réduit la complexité du code produit. Cela est rendu possible grâce aux conventions de nommage que nous avons vues précédemment.

Dans l’exemple suivant, on définit un plugin appelé myplugin qui possède trois actions : une par défaut si on n’utilise aucune sous-commande, ainsi que deux sous-commandes nommées list et create. Pour cela, on va créer trois fichiers différents : 

$ cat ~/kubectl-plugins/kubectl-myplugin
#!/bin/bash
echo "My kubectl plugin"

$ cat ~/kubectl-plugins/kubectl-myplugin-list
#!/bin/bash
echo "List my kubectl plugin"

$ cat ~/kubectl-plugins/kubectl-myplugin-create
#!/bin/bash
echo "Create my kubectl plugin"

$ kubectl myplugin
My kubectl plugin

$ kubectl myplugin create
Create my kubectl plugin

$ kubectl myplugin list  
List my kubectl plugin

Pour finir, une bonne pratique générale est de ne pas réinventer la roue. Dans le cas de l’écriture d’un plugin en Go, de nombreuses ressources sont mises à disposition par la communauté.

On peut utiliser le projet cli-runtime qui est déjà utilisé par kubectl et qui permet d’interagir avec l’API Kubernetes et propose la gestion d’un certain nombre d’options par défaut, dont celles que nous avons vues plus haut.

Pour partir sur de bonnes bases, un exemple de plugin est également disponible dans le dépôt sample-cli-plugin, dont le but est de changer le namespace par défaut sur lequel les commandes kubectl s’appliquent.!

 

Publier le plugin kubectl sur Krew

Krew est l’équivalent d’un gestionnaire de paquets pour les plugins kubectl. Il permet aux utilisateurs de télécharger ces différents plugins, et gère de nombreux aspects du cycle de vie tels que les montées de versions.

Une fois que notre plugin a bien été testé et qu’il apporte quelque chose à la communauté, il peut être partagé au public. Pour cela, il y a trois grandes étapes à suivre.

Tout d’abord, il faut rendre le code du plugin disponible en open source. Pour cela, on peut créer un dépôt sur GitHub et y déposer son code. Il est également nécessaire de mettre à disposition une archive contenant le code source du plugin, qui pourra ensuite être téléchargée par Krew. Cette archive doit être versionnée en utilisant la gestion sémantique de version. Dans un premier temps, on peut la créer manuellement puis la mettre à disposition sur le même dépôt GitHub.

Ensuite, il faut écrire un manifeste de plugin pour Krew. Il prend la forme d’un document en YAML qui décrit des métadonnées sur le plugin, la façon dont il doit être téléchargé puis installé sur la machine d’un utilisateur.

Une description complète de ce fichier est disponible sur le site de Krew, avec la liste des options que l’on peut utiliser. Pour le rédiger, il est recommandé de copier et d’adapter des manifestes de plugins déjà existants. Voici un exemple de manifeste extrait du plugin ctx : 

apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
 name: ctx
spec:
 homepage: https://github.com/ahmetb/kubectx
 shortDescription: Switch between contexts in your kubeconfig
 version: v0.9.4
 description: |
   Also known as "kubectx", a utility to switch between context entries in
   your kubeconfig file efficiently.
 caveats: |
   If fzf is installed on your machine, you can interactively choose
   between the entries using the arrow keys, or by fuzzy searching
   as you type.
   See https://github.com/ahmetb/kubectx for customization and details.
 platforms:
 - selector:
     matchExpressions:
     - key: os
       operator: In
       values:
       - darwin
       - linux
   uri: https://github.com/ahmetb/kubectx/archive/v0.9.4.tar.gz
   sha256: 91e6b2e0501bc581f006322d621adad928ea3bd3d8df6612334804b93efd258c
   bin: kubectx
   files:
   - from: kubectx-*/kubectx
     to: .
   - from: kubectx-*/LICENSE
     to: .

Pour finir, on peut tester l’installation du plugin à partir du manifeste et de l’archive en utilisant la commande suivante :

kubectl krew install --manifest=foo.yaml --archive=foo.tar.gz

Si cela fonctionne, on peut donc ouvrir une Pull Request sur le dépôt officiel de Krew en ajoutant notre manifeste dans le dossier plugins/ et attendre qu’elle soit mergée. Quand ce sera le cas, le plugin sera disponible pour tous les utilisateurs en utilisant la commande kubectl krew search.

En complément, une liste des prérequis qui doivent être validés est disponible sur le site de Krew (en anglais).

Conclusion

Les plugins pour kubectl permettent d’ajouter de nombreuses fonctionnalités à celles déjà existantes dans cet outil. Si on ne trouve pas de plugin faisant ce que l’on veut, il est alors possible de créer le sien.

Dans la version la plus simple, un plugin kubectl prend la forme d’un script Bash ayant un nom spécifique, et cela offre déjà de nombreuses possibilités simplement en jouant sur le nommage de ce plugin. Cependant, ce type de plugin ne fonctionnera pas sur Windows par exemple. On peut alors créer des CLI plus complexes, en Go notamment.

Cela permet déjà d’automatiser des actions que l’on exécute souvent. Si un plugin peut être utile à la communauté, il est alors possible de le mettre à disposition de tous en l’ajoutant dans le gestionnaire de package Krew.

Sources :