Fabric8 Client pour Kubernetes en Java
La bibliothèque Fabric8 constitue une surcouche Java complète pour interagir avec l'API REST de Kubernetes. Elle se distingue du client officiel client-java par une ergonomie supérieure, des abstractions de haut niveau et une intégration naturelle avec l'écosystème Java.
Architecture interne
Le fonctionnement reposera sur trois composants fondamentaux :
- Couche d'abstraction métier : fournit des interfaces typées pour manipuler les ressources Kubernetes (Pods, Deployments, Services, etc.) avec un style d'API fluent et chaîné ;
- Moteur de communication : gère l'authentification (fichier kubeconfig, jeton OAuth, certificats, ServiceAccount), la sérialisation JSON/YAML via Jackson, et les échanges HTTP grâce à OkHttp ;
- Appels REST : les opérations aboutissent à des requêtes vers les endpoints de l'API Kubernetes (
/api/v1/pods,/apis/apps/v1/deployments, etc.).
Caractéristiques techniques principales
- Modélisation des ressources : chaque type de ressource Kubernetes correspond à une classe Java (POJO), dont les attributs reflètent fidèlement la structure YAML de Kubernetes ;
- Mécanisme Watch : s'appuie sur l'API Watch de Kubernetes pour détecter en temps réel les modifications de ressources, exposé via l'interface
Watcheravec prise en charge asynchrone ; - Découverte automatique : récupère automatiquement les identifiants d'authentification depuis
~/.kube/configen développement local, ou depuis le Secret de ServiceAccount dans un environnement conteneurisé ; - Résilience : intègre des mécanismes de relance automatique et de gestion des dépassements de délai.
Comparaison avec le client officiel
| Critère | Fabric8 | client-java officiel |
|---|---|---|
| Style d'API | Fluent, chaîné, concis | Verbose, proche du REST brut |
| Courbe d'apprentissage | Progressive, accessible | Plus raide, destiné aux frameworks |
| Fonctionnalités intégrées | Mises à jour progressives, rollbacks, etc. | Opérations CRUD basiques uniquement |
| Maintenance | Communauté Fabric8 | Équipe officielle Kubernetes |
Mise en pratique
Prérequis
Environnement requis : JDK 8 ou supérieur, un outil de build Maven ou Gradle, et un cluster Kubernetes accessible (Minikube, Docker Desktop ou distant).
Ajout de la dépendance Maven dans le fichier pom.xml :
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>6.12.0</version>
</dependency>
<!-- Facultatif : pour la gestion des Custom Resource Definitions -->
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>crd-generator-apt</artifactId>
<version>6.12.0</version>
<scope>provided</scope>
</dependency>
Instanciation du client
Trois approches sont disponibles selon le contexte de déploiement :
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import java.io.File;
public class ConnexionCluster {
public static void main(String[] args) {
// Approche 1 : configuration automatique (recommandée)
try (KubernetesClient session = new DefaultKubernetesClient()) {
System.out.println("Connexion établie : " + session.getConfiguration().getMasterUrl());
}
// Approche 2 : paramétrage manuel pour un accès distant
Config parametres = new ConfigBuilder()
.withMasterUrl("https://10.0.0.50:6443")
.withOauthToken("eyJhbGciOiJSUzI1NiIsInR5cCI6...")
.withTrustCerts(true) // uniquement en environnement de test
.build();
try (KubernetesClient session = new DefaultKubernetesClient(parametres)) {
System.out.println("Connexion manuelle réussie");
}
// Approche 3 : chargement d'un fichier kubeconfig personnalisé
Config depuisFichier = ConfigBuilder.parseConfig(
new File("/etc/k8s/cluster-config.yaml"));
try (KubernetesClient session = new DefaultKubernetesClient(depuisFichier)) {
System.out.println("Connexion via kubeconfig personnalisé réussie");
}
}
}
L'instruction try-with-resources garantit la libération automatique des connexions réseau. En production, évitez withTrustCerts(true) et configurez un certificat CA valide.
Opérations CRUD sur les Deployments
L'exemple suivant illustre les quatre opérations fondamentales sur une ressource Deployment :
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import java.util.Map;
public class GestionDeployments {
public static void main(String[] args) {
try (KubernetesClient api = new DefaultKubernetesClient()) {
String espace = "default";
// === Création ===
Map<String, String> etiquettes = Map.of("composant", "web", "environnement", "dev");
Deployment spec = new DeploymentBuilder()
.withNewMetadata()
.withName("serveur-web")
.withLabels(etiquettes)
.endMetadata()
.withNewSpec()
.withReplicas(2)
.withNewSelector()
.withMatchLabels(etiquettes)
.endSelector()
.withNewTemplate()
.withNewMetadata()
.withLabels(etiquettes)
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName("httpd")
.withImage("httpd:2.4-alpine")
.addNewPort()
.withContainerPort(80)
.endPort()
.endContainer()
.endSpec()
.endTemplate()
.endSpec()
.build();
Deployment cree = api.apps().deployments()
.inNamespace(espace).create(spec);
System.out.println("Déploiement créé : " + cree.getMetadata().getName());
// === Lecture d'une instance ===
Deployment recupere = api.apps().deployments()
.inNamespace(espace)
.withName("serveur-web")
.get();
System.out.println("Nombre de réplicas : " + recupere.getSpec().getReplicas());
// === Lecture filtrée par étiquettes ===
api.apps().deployments()
.inNamespace(espace)
.withLabel("composant", "web")
.list()
.getItems()
.forEach(d -> System.out.println("Trouvé : " + d.getMetadata().getName()));
// === Modification (réplicas → 4) ===
Deployment modifie = api.apps().deployments()
.inNamespace(espace)
.withName("serveur-web")
.edit(dep -> new DeploymentBuilder(dep)
.editSpec()
.withReplicas(4)
.endSpec()
.build());
System.out.println("Réplicas mis à jour : " + modifie.getSpec().getReplicas());
// === Suppression ===
boolean supprime = api.apps().deployments()
.inNamespace(espace)
.withName("serveur-web")
.delete();
System.out.println(supprime ? "Suppression effectuée" : "Échec de la suppression");
}
}
}
Surveillance en temps réel avec le mécanisme Watch
Le système Watch permet d'écouter les événements de cycle de vie des ressources Kubernetes de manière asynchrone :
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
public class ObservateurPods {
public static void main(String[] args) throws InterruptedException {
try (KubernetesClient api = new DefaultKubernetesClient()) {
api.pods().inNamespace("default").watch(new Watcher<Pod>() {
@Override
public void eventReceived(Action action, Pod pod) {
String nomPod = pod.getMetadata().getName();
String phase = pod.getStatus().getPhase();
System.out.printf("[WATCH] %s → %s (état: %s)%n",
action.name(), nomPod, phase);
}
@Override
public void onClose(WatcherException erreur) {
if (erreur != null) {
System.err.println("Fermeture anormale : " + erreur.getMessage());
} else {
System.out.println("Observateur arrêté proprement");
}
}
});
// Maintenir le processus actif pendant 60 secondes
Thread.sleep(60_000);
}
}
}
Pour tester, exécutez kubectl run demo-pod --image=nginx -n default dans un terminal : l'événement ADDED apparaîtra dans la console. La suppression du Pod déclenchera l'événement DELETED.
Exécution de commandes à l'intérieur d'un Pod
Fabric8 permet d'exécuter des commandes dans un conteneur, équivalent à kubectl exec :
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
import java.io.ByteArrayOutputStream;
public class ExecDansPod {
public static void main(String[] args) {
try (KubernetesClient api = new DefaultKubernetesClient()) {
String ciblePod = "serveur-web-7f8d9c6b4-abc12"; // à adapter
String cibleConteneur = "httpd";
ByteArrayOutputStream resultat = new ByteArrayOutputStream();
ExecWatch session = api.pods()
.inNamespace("default")
.withName(ciblePod)
.inContainer(cibleConteneur)
.writingOutput(resultat)
.exec("cat", "/usr/local/apache2/conf/httpd.conf");
session.close();
System.out.println("Sortie de la commande :\n" + resultat.toString());
}
}
}
Bonnes pratiques pour la production
- Réutilisation de l'instance client : instanciez
KubernetesClientune seule fois et partagez-la (singleton ou bean Spring) ; évitez les créations répétées ; - Gestion des exceptions : interceptez
KubernetesClientExceptionet différenciez les cas d'erreur (ressource introuvable, droits insuffisants, délai dépassé) ; - Principe du moindre privilège : attribuez un ServiceAccount avec les permissions minimales requises plutôt que
cluster-admin; - Externalisation de la configuration : stockez l'adresse du cluster et les jetons d'authentification dans des fichiers de configuration ou des secrets, jamais en dur dans le code source ;
- Fermeture des observateurs : arrêtez explicitement les instances Watch à l'arrêt de l'application pour prévenir les fuites mémoire.