Kubernetes API mit Java anbinden
Kubernetes bietet mit seiner erweiterbaren API eine sehr einfache Möglichkeit zusätzliches Verhalten mit Kubernetes zu integrieren. Neben der API-Spezifikation als OpenAPI (ehemals Swagger) stellt das Kubernetes-Projekt auch fertige Clients für verschiedene Programmiersprachen an. Eine besondere Rolle nimmt der Kubernetes Go-Client ein, da dieser auch innerhalb von Kubernetes selbst eingesetzt wird.
Auf Basis der OpenAPI-Spezifikation stehen generierte Clients für Java, Python, C# und JavaScript. Zu den offiziellen Kubernetes-Clients kommen noch durch die Community erstellte und gepflegte Libraries für diverse Sprachen hinzu.
Im Folgenden wird demonstriert, wie die Kubernets-API mit Java verwendet werden kann. Wie der dazu benötigte lesende API-Zugriff eingerichtet werden kann, wurde bereits in Kubernetes Readonly API Zugriff erklärt.
Die Java-Implementierung für die Kubernetes-API findet sich bei GitHub: https://github.com/kubernetes-client/java/
Mit Maven wird der Kubernetes-Client als Dependency deklariert und kann dann verwendet werden. Als HTTP-Client kommt OkHttp zum Einsatz, was auch unter Android funktioniert.
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>4.0.0</version>
<scope>compile</scope>
</dependency>
Der Java-Client bietet verschiedene Konfigurationsvarianten, um auf die Kubernetes-API zuzugreifen. Relevant sind dabei vor allem die Komponenten API Endpunkt und Authentifizierung: Aus diesen beiden Parametern ergibt sich dann, wie der technische Zugriff umgesetzt wird.
Praktischerweise bietet die Klasse io.kubernetes.client.util.Config
eine statische Factory-Methode defaultClient
, die verschiedene Varianten zur Konfiguration durchprobiert:
-
Ist die Umgebungsvariable
$KUBECONFIG
gesetzt, wird die dort spezifizierte Konfiguration verwendet -
Existiert
$HOME/.kube/config
, wird diese Konfiguration verwendet -
Es wird versucht, einen Kubernetes Serviceaccount zum Zugriff auf den
kubernetes
Service innerhalb eines Clusters zu verwenden -
Als letzte Variante wird der Zugriff auf
http://localhost:8080
versucht - dies entspricht einemkubectl proxy --port 8080
Somit ist der Zugriff mit relativ wenig Aufwand umzusetzen. Zur Demonstration sollen die zu einem Cluster gehörigen Nodes, ihre Architektur und das verwendete Betriebssystem abgefragt werden.
public class Client
{
public static void main(String[] args) throws IOException, ApiException
{
ApiClient client = Config.defaultClient();
Configuration.setDefaultApiClient(client);
CoreV1Api api = new CoreV1Api();
V1NodeList listNode = api.listNode(true, null, null, null, null, null, null, 10, false);
for (V1Node node : listNode.getItems())
{
V1NodeSystemInfo nodeInfo = node.getStatus().getNodeInfo();
String addr = node.getStatus().getAddresses().size() > 0 ? node.getStatus().getAddresses().get(0).getAddress() : "???";
String name = node.getMetadata().getName();
System.out.format("%s (%s) - %s: %s (%s) %n", name, addr, nodeInfo.getArchitecture(), nodeInfo.getOsImage(), nodeInfo.getOperatingSystem());
}
}
}
Etwas gewöhnungsbedürftig ist die Angabe von Filter- und Ausgabeparametern für die Objektabfrage, da hier viele null
-Werte verwendet werden.
Die Signatur von listNode
sieht wie folgt aus:
public V1NodeList listNode(
Boolean includeUninitialized,
String pretty,
String _continue,
String fieldSelector,
String labelSelector,
Integer limit,
String resourceVersion,
Integer timeoutSeconds,
Boolean watch
) throws ApiException
Da alle Parameter optional sind, werden null
-Werte verwendet, wenn der Parameter nicht gesetzt wird.
Zudem fällt direkt auf, dass für includeUninitialized
ein boolean-Parameter verwendet wurde, für die pretty
-Ausgabe jedoch ein String
, der den Wert "true"
erhalten kann.
Auch wenn ein Pretty-Printing der Ausgabe für eine maschinelle Verarbeitung selten sinnvoll sein wird, wäre eine bessere Konsistenz wünschenswert.
Kubernetes Watch-API
Neben der Request-Response API zur Abfrage von Objekten bietet Kubernetes auch eine Watch-API.
Diese liefert kontinuierliche Updates bei Änderungen des Zustands und erlaubt damit Reaktionen in Echtzeit.
Die Umsetzung ist bei Kubernetes mit einer regulären HTTP-Verbindung gelöst, die jedoch lange bestehen bleibt und zeilenweise JSON-Objekte liefert.
In den Objekten ist der jeweilige Event-Typ (ADDED
, MODIFIED
, DELETED
) in einem Attribut vermerkt.
Die Java API dazu weicht deutlich von der Variante einer einzelnen Abfrage ab.
ApiClient client = Config.defaultClient();
client.getHttpClient().setReadTimeout(0, TimeUnit.SECONDS); // (1)
Configuration.setDefaultApiClient(client);
CoreV1Api api = new CoreV1Api();
Watch<V1Pod> watch = Watch.createWatch( // (2)
client,
api.listPodForAllNamespacesCall(null, null, null, null, null, null, null, null, true, null, null), // (3)
new TypeToken<Watch.Response<V1Pod>>(){}.getType()
);
for (Watch.Response<V1Pod> item : watch) // (4)
{
switch (item.type)
{
case "ADDED":
{
String name = item.object.getMetadata().getName();
String image = item.object.getSpec().getContainers().get(0).getImage();
System.out.format("ADDED: %s (%s) %s %n", name, image, item.object.getStatus().getPhase());
break;
}
}
}
-
Für die Watch-API wird eine dauerhaft lesende HTTP-Verbindung eingesetzt, daher muss der Read-Timeout entsprechend auf unendlich konfiguriert werden
-
Statt eines blockierenden Aufrufs wird ein
Watch
erzeugt, vergleichbar einem Java Future -
Der API-Aufruf selbst muss entsprechend konfiguriert werden (
watch=true
) -
Der Iterator blockiert und liefert neue Ergebnisse, wenn ein neues Element von der API übermittelt wird
Auf die Ergebnisse kann dann entsprechend reagiert werden, zum Beispiel auch wiederum durch Aufrufe der Kubernetes API, um Änderungen der Clusterkonfiguration auszulösen.
Ein anderes Anwendungsbeispiel ist die Watch-API für Servicediscovery von Kubernetes-Service-Objekten zu nutzen, um eine Anwendung daraufhin dynamisch zu konfigurieren.
Zu den Themen Kubernetes, Docker und Cloud Architektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.