A logo showing the text blog.marcnuri.com
English
Inicio»Java»Accede al API de Kubernetes desde un Pod con Java

Entradas Recientes

  • Fabric8 Kubernetes Client 7.2.0 está disponible!
  • Conectarse a un servidor MCP con JavaScript y AI SDK
  • Conectarse a un servidor MCP con JavaScript y LangChain.js
  • El Futuro de las Herramientas para Desarrolladores en la era de la IA
  • Conectarse a un servidor Model Context Protocol (MCP) con Java y LangChain4j

Categorías

  • Antiguo
  • Front-end
  • Go
  • Herramientas
  • Industria y negocios
  • Inteligencia Artificial
  • Java
  • JavaScript
  • Operaciones
  • Personal
  • Proyectos personales

Archivos

  • mayo 2025
  • abril 2025
  • marzo 2025
  • febrero 2025
  • enero 2025
  • diciembre 2024
  • noviembre 2024
  • agosto 2024
  • junio 2024
  • mayo 2024
  • abril 2024
  • marzo 2024
  • febrero 2024
  • enero 2024
  • diciembre 2023
  • noviembre 2023
  • octubre 2023
  • septiembre 2023
  • agosto 2023
  • julio 2023
  • junio 2023
  • mayo 2023
  • abril 2023
  • marzo 2023
  • febrero 2023
  • enero 2023
  • diciembre 2022
  • noviembre 2022
  • octubre 2022
  • agosto 2022
  • julio 2022
  • mayo 2022
  • marzo 2022
  • febrero 2022
  • enero 2022
  • diciembre 2021
  • noviembre 2021
  • octubre 2021
  • septiembre 2021
  • agosto 2021
  • julio 2021
  • diciembre 2020
  • octubre 2020
  • agosto 2020
  • junio 2020
  • mayo 2020
  • marzo 2020
  • febrero 2020
  • enero 2020
  • noviembre 2019
  • octubre 2019
  • julio 2019
  • diciembre 2018
  • agosto 2018
  • julio 2018
  • junio 2018
  • mayo 2018
  • marzo 2018
  • febrero 2018
  • noviembre 2017
  • octubre 2017
  • agosto 2017
  • julio 2017
  • enero 2017
  • julio 2016
  • enero 2016
  • diciembre 2015
  • noviembre 2015
  • diciembre 2014
  • marzo 2014
  • febrero 2011
  • junio 2008
  • mayo 2008
  • abril 2008
  • enero 2008
  • junio 2007
  • mayo 2007
  • abril 2007
  • marzo 2007

Accede al API de Kubernetes desde un Pod con Java

2020-10-07 en Java etiquetado Cliente / Cloud / Java / Eclipse JKube / Kubernetes / OpenShift / YAKC por Marc Nuri | Última actualización: 2022-02-03
English version

Introducción

En este ejemplo os mostraré cómo podéis acceder a la API REST de vuestro Kubernetes cluster desde un Pod utilizando YAKC (Yet Another Kubernetes Client), Eclipse JKube y Spring Boot.

En la primera parte os enseñaré cómo crear una aplicación muy sencilla basada en Spring Boot con la dependencia a YAKC Kubernetes Client (ver introducción a YAKC).

En la segunda parte describo cómo desplegar la aplicación en un cluster de Kubernetes y cómo hacer peticiones a los endpoints REST expuestos en el Servicio del Pod para obtener información del Cluster.

Aplicación de ejemplo

Lo primero que haremos será crear una aplicación Spring Boot the ejemplo. Este es el fichero pom.xml que utilizaremos. Además de las dependencias estándar para Spring Boot, también debemos de incluir las dependencias de YAKC Kubernetes Client (y su api):

1<!-- ... -->
2  <dependencies>
3<!-- ... -->
4    <dependency>
5      <groupId>com.marcnuri.yakc</groupId>
6      <artifactId>kubernetes-api</artifactId>
7      <version>${project.version}</version>
8    </dependency>
9    <dependency>
10      <groupId>com.marcnuri.yakc</groupId>
11      <artifactId>kubernetes-client</artifactId>
12      <version>${project.version}</version>
13    </dependency>
14  </dependencies>
15<!-- ... -->

Ahora podemos declarar un Bean de KubernetesClient en la main class de nuestra aplicación (AccessClusterFromPodApplication):

1/* ... */
2  @Bean(destroyMethod = "close")
3  public KubernetesClient kubernetesClient() {
4    return new KubernetesClient();
5  }
6/* ... */

Este Bean nos permitirá inyectar (autowire) la instancia compartida (singleton) de KubernetesClient al resto de componentes de la aplicación.

Cluster Service

Primero definiremos los distintos métodos que vamos a necesitar en la interfaz ClusterService. A continuación definiremos su implementación en la clase KubernetesClientClusterService.

El método más complejo de la clase es la implementación del método getDeploymentLogs. Este método se encarga de consultar y agregar las trazas (ordenadas por fecha/hora) de todos los Pods de un Deployment específico. Describiré con más detalle esta implementación debido a su complejidad. El resto de métodos deberían de ser evidentes en el código.

1@Override
2  public String getDeploymentLogs(String deploymentName) {
3    try {
4      final Deployment deployment = kubernetesClient.create(AppsV1Api.class)
5        .readNamespacedDeployment(deploymentName, getNamespace()).get();
6      return kubernetesClient.create(CoreV1Api.class).listNamespacedPod(getNamespace(),
7        new ListNamespacedPod().labelSelector(
8          deployment.getSpec().getSelector().getMatchLabels().entrySet().stream()
9            .map(e -> String.format("%s=%s", e.getKey(), e.getValue())).collect(
10            Collectors.joining(","))
11        )).stream()
12        .flatMap(this::getPodLog)
13        .sorted()
14        .collect(Collectors.joining("\n"));
15    } catch(NotFoundException e) {
16      throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
17    } catch (IOException e) {
18      throw new ServerErrorException(e.getMessage(), e);
19    }
20  }
21
22  private Stream<String> getPodLog(Pod pod) {
23    try {
24      return Stream.of(kubernetesClient.create(CoreV1Api.class)
25        .readNamespacedPodLog(pod.getMetadata().getName(), getNamespace(), new ReadNamespacedPodLog().timestamps(true))
26        .get().split("\n")
27      ).map(logLine -> {
28        final String[] splitLine = logLine.split("\\s", 2);
29        return String.format("%s [%s] - %s", splitLine[0], pod.getMetadata().getName(),
30          splitLine.length > 1 ? splitLine[1] : "");
31      });
32    } catch (IOException e) {
33      throw new ServerErrorException("Cannot retrieve log", e);
34    }
35  }

El método comienza creando un cliente para la API de Apps V1. Utilizaremos esta API para consultar información del Deployment correspondiente al nombre proporcionado en el namespace configurado.

A continuación emplearemos las entradas del campo spec.selector.matchLabels del Deployment obtenido para obtener la lista de Pods que concuerdan con este selector. Convertimos la lista de Pods en un Stream al que hacemos flatMap para mapearlos en un stream de entradas en el log de cada uno de los Pods. La implementación de este mapeo la vemos en el método getPodLog.

El método getPodLog utiliza la API Core V1 para leer las entradas de los logs de un determinado Pod incluyendo los timestamps. A continuación transformamos cada una de las trazas obtenidas para dividirlas por separadores de línea y así poder incluir el nombre del Pod en cada una de las líneas después del timestamp.

Finalmente, en el método getDeploymentLogs una vez el mapeo de los logs se ha completado, se ordenan las entradas y se combinan en un único String que será el resultado del método.

A pesar de la complejidad que supone transformar, combinar y ordenar las trazas de todos los Pods correspondientes a un Deployment, las interfaces declarativas y “streamable” de YAKC lo convierten en una tarea sencilla. La implementación resultante también es muy legible y se puede conseguir con muy pocas líneas de código.

Cluster Resource

En la clase ClusterResource puedes ver la implementación de los distintos endpoints REST que expondrá la aplicación. Esta clase es un RestController estándar de Spring. La clase contiene distintos métodos anotados con GetMapping que permiten consultar el nombre del namespace configurado, los Deployments y Pods en este namespace, así como las trazas agregadas de todos los Pods de un Deployment determinado.

Por ejemplo, para el método que he descrito en la sección anterior, podemos hacer una petición GET a http://cluster-ingress-url/deployments/deployment-name/logs y así obtener el Log agregado para el Deployment especificado:

1@GetMapping("deployments/{deployment}/logs")
2  public String getDeploymentLogs(@PathVariable("deployment") String deployment) {
3    return clusterService.getDeploymentLogs(deployment);
4  }

Desplegando la aplicación en el Cluster

Una vez hemos destripado la aplicación y hemos visto como utilizar YAKC para interactuar con el Cluster, es el momento de desplegarla.

Lo primero que debemos hacer es configurar el cluster para permitir que el Pod pueda acceder a la API del cluster. Para ello debemos proporcionar acceso al service account por defecto del Pod. Esto lo podemos conseguir ejecutando el siguiente comando:

1kubectl create clusterrolebinding default-cluster-admin --clusterrole cluster-admin --serviceaccount=default:default

A partir de este momento, el service account por defecto (credenciales proporcionadas en la ruta /var/run/secrets/kubernetes.io/serviceaccount/token) del Pod podrá acceder a la API REST del cluster.

Eclipse JKube

Para desplegar la aplicación utilizaré el Kubernetes Maven Plugin de Eclipse JKube ya que nos permite desplegar cualquier aplicación Java con una mínima configuración.

Configuramos el plugin en la sección build del pom.xml:

1<!-- ... -->
2<plugin>
3  <groupId>org.eclipse.jkube</groupId>
4  <artifactId>kubernetes-maven-plugin</artifactId>
5  <version>1.18.1</version>
6  <executions>
7    <execution>
8      <id>jkube</id>
9      <phase>package</phase>
10      <goals>
11        <goal>build</goal>
12        <goal>resource</goal>
13        <goal>apply</goal>
14      </goals>
15    </execution>
16  </executions>
17  <configuration>
18    <enricher>
19      <config>
20        <jkube-service>
21          <type>NodePort</type>
22        </jkube-service>
23      </config>
24    </enricher>
25  </configuration>
26</plugin>
27<!-- ... -->

He vinculado las tareas build, resource y apply del plugin a la fase package. Con esto conseguiremos que la imagen Docker de la aplicación de construya y despliegue en el cluster automáticamente cuando ejecutemos el comando mvn package.

También podéis observar que he añadido una configuración para los enrichers de JKube de manera que el Service generado sea de tipo NodePort.

Si vamos a desplegar la aplicación en Minikube, es conveniente compartir el acceso al Docker daemon de Minikube a nuestro sistema anfitrión. Esto nos permitirá no tener que publicar la imagen construida en un registro compartido.

  • eval $(minikube docker-env) on Linux
  • @FOR /f "tokens=*" %i IN ('minikube -p minikube docker-env') DO @%i on Windows

Una vez configurado el entorno, podemos proceder a desplegar la aplicación (mvn clean package):

Access Cluster From Pod JKube mvn package
Access Cluster From Pod JKube mvn package

Si todo ha ido bien, la aplicación debería de estar ahora desplegada. Si estamos utilizando Minikube, podemos probar los endpoints de la aplicación ejecutando los siguientes comandos:

Access Cluster From Pod curl
Access Cluster From Pod curl

Conclusión

En esta publicación os he mostrado como podemos acceder con facilidad a la API REST de Kubernetes desde una aplicación Java corriendo en un Pod mediante YAKC (Yet Another Kubernetes Client). También os he mostrado como construir la imagen Docker de la aplicación y como desplegarla en el cluster con una mínima configuración empleando el Plugin de Maven para Kubernetes de Eclipse JKube.

Puedes encontrar el código fuente completo de este post en la sección quickstarts del repositorio de GitHub de YAKC.

YAKC - Yet Another Kubernetes Client
YAKC - Yet Another Kubernetes Client
Twitter iconFacebook iconLinkedIn iconPinterest iconEmail icon

Navegador de artículos
Eclipse JKube: Herramientas y plugins de Java para Kubernetes y OpenShiftKubernetes 1.19 Ingress API desde Java con YAKC
© 2007 - 2025 Marc Nuri