### Setup Kubernetes Environment with Kind Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md This script sets up the necessary Docker images for example services and loads them into the Kind cluster. If using a non-default Kind cluster name, provide it as the first argument. ```shell ./setup-kubernetes.sh ``` ```shell ./setup-kubernetes.sh ``` -------------------------------- ### SecretController Example Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt An example controller demonstrating how to consume the `SecretWatcher` to stream and log Kubernetes secret events. ```APIDOC ## watchSecrets / SecretController ### Description An endpoint that initiates a stream of watch events for secrets in a given namespace and logs the event details. ### Method GET ### Endpoint /secrets/{namespace} ### Parameters #### Path Parameters - **namespace** (String) - Required - The namespace for which to watch secrets. ``` -------------------------------- ### Build Example Services Docker Images Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Builds the Docker images for the example services. Ensure you have a Kubernetes cluster accessible via kubectl. ```shell ./gradlew clean dockerBuild --refresh-dependencies ``` -------------------------------- ### Start Kubernetes Proxy Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Starts a proxy to the Kubernetes API server. This is often required for tools and applications to interact with the cluster. ```shell kubectl proxy ``` -------------------------------- ### ConfigMapReconciler Example Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-operator.adoc Illustrates a `ResourceReconciler` for `V1ConfigMap` resources, demonstrating the use of the `Operator` annotation and the `reconcile` method. ```java package example.micronaut.operator; import io.micronaut.kubernetes.client.openapi.informer.handler.Informer; import io.micronaut.kubernetes.client.openapi.operator.Operator; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.OperatorResourceLister; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.Request; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.ResourceReconciler; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.Result; import io.kubernetes.client.openapi.models.V1ConfigMap; import jakarta.inject.Singleton; import java.util.Optional; @Singleton @Operator(informer = @Informer(apiType = V1ConfigMap.class)) public class ConfigMapReconciler implements ResourceReconciler { @Override public Result reconcile(Request request, OperatorResourceLister lister) { Optional configMapOptional = lister.get(request); if (configMapOptional.isPresent()) { V1ConfigMap configMap = configMapOptional.get(); // <4> // TODO: Implement idempotent reconciliation logic here. // <5> // The reconciliation logic is responsible for the update of the resource status. return Result.success(); // <6> } else { return Result.success(); // <6> } } } ``` -------------------------------- ### ConfigMap onAddFilter Example Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-operator.adoc A predicate to filter which created `V1ConfigMap` resources are subject to reconciliation. ```java package example.micronaut.operator; import io.kubernetes.client.openapi.models.V1ConfigMap; import java.util.function.Predicate; public class OnAddFilter implements Predicate { @Override public boolean test(V1ConfigMap v1ConfigMap) { return v1ConfigMap.getMetadata().getNamespace().equals("default"); } } ``` -------------------------------- ### ConfigMap Resource Reconciler Example Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/kubernetes-operator.adoc Example of a reconciler for Kubernetes V1ConfigMap resources. It demonstrates the use of the `Operator` and `ResourceReconciler` annotations and interfaces for managing Kubernetes resources. ```java package io.micronaut.kubernetes.client.operator; import io.micronaut.kubernetes.client.informer.Informer; import io.micronaut.kubernetes.client.operator.Operator; import io.micronaut.kubernetes.client.operator.ResourceReconciler; import io.micronaut.kubernetes.client.operator.OperatorResourceLister; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapList; import io.kubernetes.client.util.Watch; import io.kubernetes.client.extended.controller.reconciler.Request; import io.kubernetes.client.extended.controller.reconciler.Result; import java.util.Optional; @Operator( informer = @Informer(group = "", version = "v1", kind = "configmap", செய்யப்படும் = V1ConfigMap.class,されます = V1ConfigMapList.class,されます = "configmaps") ) public class ConfigMapResourceReconciler implements ResourceReconciler { @Override public Result reconcile(Request request, OperatorResourceLister lister) { Optional configMapOptional = lister.get(request); if (configMapOptional.isPresent()) { V1ConfigMap configMap = configMapOptional.get(); // Reconciliation logic here System.out.println("Reconciling ConfigMap: " + configMap.getMetadata().getName()); // Example: Update status if needed // configMap.getStatus().put("reconciled", "true"); // return Result.updateStatus(configMap); return Result.success(); } else { // Resource not found, handle deletion or ignore System.out.println("ConfigMap not found for request: " + request.getName()); return Result.success(); } } } ``` -------------------------------- ### ConfigMap Definition Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Example Kubernetes ConfigMap definition. ```yaml apiVersion: v1 kind: ConfigMap metadata: name: mounted-config data: mounted.yml: |- foo: bar ``` -------------------------------- ### ConfigMap Resource Reconciler with Filters Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/kubernetes-operator.adoc Example demonstrating how to configure onAddFilter, onUpdateFilter, and onDeleteFilter for a V1ConfigMap reconciler. ```java package io.micronaut.kubernetes.client.operator; import io.micronaut.kubernetes.client.operator.Operator; import io.micronaut.kubernetes.client.operator.reconciler.ResourceReconciler; import io.kubernetes.client.openapi.models.V1ConfigMap; import jakarta.inject.Singleton; @Operator(onAddFilter = ConfigMapOnAddFilter.class, onUpdateFilter = ConfigMapOnUpdateFilter.class, onDeleteFilter = ConfigMapOnDeleteFilter.class) @Singleton public class ConfigMapResourceReconcilerWithFilters implements ResourceReconciler { @Override public Optional reconcile(V1ConfigMap resource) { // Reconciliation logic here return Optional.empty(); } } ``` -------------------------------- ### Configure Startup Termination on Secret Import Exception Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Configure the application to terminate startup if there's an unexpected exception while reading secrets. Setting `terminateStartupOnException=true` ensures that the application does not start without essential secrets. ```yaml micronaut: config: import: - optional:kubernetes://secret?name=my-secret&terminateStartupOnException=true ``` -------------------------------- ### Pod Definition with Volume Mount Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Example Kubernetes Pod definition mounting a ConfigMap as a volume. ```yaml apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: micronautapp volumeMounts: - name: configuration mountPath: /etc/configuration readOnly: true volumes: - name: configuration configMap: name: mounted-config ``` -------------------------------- ### Override Setup Fixture for Resources Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Override the `setupFixture` method in `KubernetesSpecification` to programmatically create custom Kubernetes resources like roles, bindings, deployments, and services. ```groovy @Override def setupFixture(String namespace) { createNamespaceSafe(namespace) operations.createRole("kubernetes-client", namespace) operations.createRoleBinding("kubernetes-client", namespace, "kubernetes-client") operations.createDeploymentFromFile(loadFileFromClasspath("k8s/kubernetes-client-example-deployment.yml"), "kubernetes-client-example", namespace) operations.createService("kubernetes-client-example", namespace, new ServiceSpecBuilder() .withType("LoadBalancer") .withPorts( new ServicePortBuilder() .withPort(8085) .withTargetPort(new IntOrString(8085)) .build() ) .withSelector(["app": "kubernetes-client-example"]) .build()) } ``` -------------------------------- ### ConfigMap onUpdateFilter Example Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-operator.adoc A predicate to filter which updated `V1ConfigMap` resources are subject to reconciliation. ```java package example.micronaut.operator; import io.kubernetes.client.openapi.models.V1ConfigMap; import java.util.function.BiPredicate; public class OnUpdateFilter implements BiPredicate { @Override public boolean test(V1ConfigMap oldV1ConfigMap, V1ConfigMap newV1ConfigMap) { return !oldV1ConfigMap.getMetadata().getResourceVersion().equals(newV1ConfigMap.getMetadata().getResourceVersion()); } } ``` -------------------------------- ### Usage Example: Create Namespaced Widget Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Demonstrates how to use the `WidgetApiReactor` to create a namespaced widget. This involves instantiating the `Widget` model, setting its metadata and spec, and then calling the `createNamespacedWidget` method. ```java import jakarta.inject.Inject; class WidgetService { @Inject WidgetApiReactor widgetApi; Mono createWidget(String namespace, String name) { Widget w = new Widget(); w.setApiVersion("example.io/v1"); w.setKind("Widget"); var meta = new io.micronaut.kubernetes.client.openapi.model.V1ObjectMeta(); meta.setName(name); meta.setNamespace(namespace); w.setMetadata(meta); w.setSpec("color=blue"); return widgetApi.createNamespacedWidget(namespace, w, null, null, null); // On success emits: Widget{metadata.name="my-widget", spec="color=blue"} } } ``` -------------------------------- ### Pod Definition with Secret Volume Mount Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Example of a Pod definition mounting a Kubernetes Secret as a volume. ```yaml apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret ``` -------------------------------- ### Kubernetes Secret Definition Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Example of a Kubernetes Secret resource definition. ```yaml apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm ``` -------------------------------- ### Custom ApiClient Configuration Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client.adoc Example of creating a BeanCreatedEventListener to customize the ApiClient's OkHttpClient. This is for advanced configuration not suitable for application.yml. ```java snippet::io.micronaut.kubernetes.client.ApiClientListener[tags="listener", project="kubernetes-client", source="test"] ``` -------------------------------- ### Mount ConfigMap as Volume Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Example of mounting a ConfigMap as a volume in a Kubernetes Pod definition. This makes the ConfigMap data available as files within the container. ```yaml apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: micronautapp volumeMounts: - name: configuration mountPath: /etc/configuration readOnly: true volumes: - name: configuration configMap: name: mounted-config ``` -------------------------------- ### Kubernetes Service Definition (YAML) Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/service-discovery.adoc Example of a Kubernetes Service definition that creates a Service object and an Endpoints object with the same name. ```yaml kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376 ``` -------------------------------- ### Micronaut Client Annotation Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-service-discovery.adoc Example of how to use the Kubernetes Service ID with the `@Client` annotation in a Micronaut HTTP client. ```java @Client("my-service") interface MyServiceClient { // ... } ``` -------------------------------- ### ConfigMap onDeleteFilter Example Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-operator.adoc A predicate to filter which deleted `V1ConfigMap` resources are subject to reconciliation. Note that the resource will be already deleted when this filter is executed. ```java package example.micronaut.operator; import io.kubernetes.client.openapi.models.V1ConfigMap; import java.util.function.BiPredicate; public class OnDeleteFilter implements BiPredicate { @Override public boolean test(V1ConfigMap v1ConfigMap, V1ConfigMap v1ConfigMap2) { return v1ConfigMap.getMetadata().getName().startsWith("my-app-"); } } ``` -------------------------------- ### Operator Annotation with Filters Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-operator.adoc Example of setting `onAddFilter`, `onUpdateFilter`, and `onDeleteFilter` within the `Operator` annotation for `V1ConfigMap` reconciliation. ```java @Operator(informer = @Informer(apiType = V1ConfigMap.class), onAddFilter = OnAddFilter.class, onUpdateFilter = OnUpdateFilter.class, onDeleteFilter = OnDeleteFilter.class) ``` -------------------------------- ### Micronaut Client Annotation Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/service-discovery.adoc Example of how to use the Kubernetes service name 'my-service' as the Service ID in a Micronaut HTTP client annotation. ```java @Client("my-service") ``` -------------------------------- ### Mounting a Kubernetes Secret as a Volume Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Example of a Kubernetes Pod definition that mounts a secret as a volume. Ensure the secret data is base64 encoded and matches the expected file format. ```yaml apiVersion: v1 kind: Secret metadata: name: mounted-secret type: Opaque data: application.properties: Zm9vPWJhcg== ``` ```yaml apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mounted-secret ``` -------------------------------- ### Custom Leader Election Properties Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/kubernetes-operator.adoc Example of configuring leader election properties for the operator. This allows customization of lease duration, renew deadline, and retry period. ```yaml kubernetes: client: operator: leader-election: lock: lease-duration: 60s renew-deadline: 50s retry-period: 20s ``` -------------------------------- ### Example Kubernetes Health Check Output Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/health-checks.adoc This JSON output shows the details of a health check request, including Kubernetes-specific information like pod status and container details, as well as service discovery information. ```json { "name": "micronaut-service", "status": "UP", "details": { "kubernetes": { "name": "micronaut-service", "status": "UP", "details": { "namespace": "default", "podName": "example-service-786cd45b78-bzfw5", "podPhase": "Running", "podIP": "10.1.3.124", "hostIP": "192.168.65.3", "containerStatuses": [ { "name": "example-service", "image": "registry.hub.docker.com/alvarosanchez/example-service:latest", "ready": true } ] } }, "compositeDiscoveryClient(kubernetes)": { "name": "micronaut-service", "status": "UP", "details": { "services": { "example-service": [ "http://10.1.3.124:8081", "http://10.1.3.126:8081" ], "non-secure-service": [ "http://10.1.3.127:1234" ], "kubernetes": [ "https://kubernetes:443" ], "secure-service-port-name": [ "https://10.1.3.127:1234" ], "example-client": [ "http://10.1.3.125:8082" ], "secure-service-port-number": [ "https://10.1.3.127:443" ], "secure-service-labels": [ "https://10.1.3.127:1234" ] } } }, "diskSpace": { "name": "micronaut-service", "status": "UP", "details": { "total": 109702647808, "free": 69758287872, "threshold": 10485760 } } } } ``` -------------------------------- ### Terminate Startup on Exception Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Terminate application startup if an exception occurs while reading ConfigMaps by setting `kubernetes.client.config-maps.terminate-startup-on-exception` to `true`. ```yaml kubernetes: client: config-maps: terminate-startup-on-exception: true ``` -------------------------------- ### Import ConfigMaps by Labels Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Import ConfigMaps that match specific Kubernetes labels using the `kubernetes://config-map?labels=` URI. This allows for dynamic selection of multiple resources. ```yaml micronaut: config: import: - optional:kubernetes://config-map?labels=app=my-app,env=prod ``` -------------------------------- ### Create ConfigMap from File Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Command to create a Kubernetes ConfigMap from a file. ```bash kubectl create configmap my-config --from-file=my-config.properties ``` ```bash kubectl create configmap my-config --from-file=my-config.yml ``` ```bash kubectl create configmap my-config --from-file=my-config.json ``` -------------------------------- ### Terminate Startup on Secret Exception Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Set `kubernetes.client.secrets.terminate-startup-on-exception` to `true` to stop service startup if secrets cannot be read due to an exception. ```yaml kubernetes: client: secrets: terminate-startup-on-exception: true ``` -------------------------------- ### Terminate Startup on Config Import Exception Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Set `terminateStartupOnException=true` in the import URI to stop application startup if there's an exception while reading ConfigMaps. By default, exceptions are logged and startup continues. ```yaml micronaut: config: import: - optional:kubernetes://config-map?name=my-config-map&terminateStartupOnException=true ``` -------------------------------- ### Import ConfigMap by Name Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Import a specific ConfigMap by its name using the `kubernetes://config-map?name=` URI. ```yaml micronaut: config: import: - optional:kubernetes://config-map?name=my-config-map ``` -------------------------------- ### Create Kind Kubernetes Cluster Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Creates a local Kubernetes cluster using Kind. The --wait flag ensures the cluster is ready before proceeding. ```shell kind create cluster --wait 5m ``` -------------------------------- ### Create ConfigMap from File Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Command to create a Kubernetes ConfigMap from an existing file. Supports properties, YAML, and JSON file formats. ```bash kubectl create configmap my-config --from-file=my-config.properties ``` ```bash kubectl create configmap my-config --from-file=my-config.yml ``` ```bash kubectl create configmap my-config --from-file=my-config.json ``` -------------------------------- ### Injecting CoreV1Api Client Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client.adoc Demonstrates how to inject and use the CoreV1Api client for synchronous operations. Ensure the `micronaut-kubernetes-client` dependency is added. ```java import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1PodList; import jakarta.inject.Singleton; @Singleton public class MyService { private final CoreV1Api coreV1Api; public MyService(CoreV1Api coreV1Api) { this.coreV1Api = coreV1Api; } public void myMethod(String namespace) throws ApiException { V1PodList v1PodList = coreV1Api.listNamespacedPod(namespace).execute(); } } ``` -------------------------------- ### Custom Kubernetes Namespace Resolver Implementation Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Provide a custom implementation of NamespaceResolver to override auto-detection, for example, by reading environment variables. ```java import io.micronaut.context.annotation.Replaces; @Singleton @Replaces(NamespaceResolver.class) public class HardcodedNamespaceResolver implements NamespaceResolver { @Override public String resolveNamespace() { return System.getenv().getOrDefault("MY_NAMESPACE", "production"); } } ``` -------------------------------- ### Import Multiple ConfigMaps by Name Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Import multiple ConfigMaps by repeating the `kubernetes://config-map?name=` entry in the `micronaut.config.import` list. ```yaml micronaut: config: import: - optional:kubernetes://config-map?name=my-config-map - optional:kubernetes://config-map?name=other-config-map ``` -------------------------------- ### Configure Minikube Docker Environment Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Use this command to configure your shell to use Minikube's Docker runtime instead of the system's. This is necessary for building Docker images within the Minikube environment. ```shell eval $(minikube -p minikube docker-env) ``` -------------------------------- ### Get All ConfigMaps from Informer Cache Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-informer.adoc Retrieves all ConfigMaps currently stored in the SharedIndexInformer's local cache. This is useful for iterating over all cached resources. ```java List configMaps = sharedIndexInformer.getAll(); ``` -------------------------------- ### Get ConfigMap from Informer Cache Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-informer.adoc Retrieves a ConfigMap from the SharedIndexInformer's local cache. Use this when you need to access cached Kubernetes objects. ```java ConfigMap configMap = sharedIndexInformer.get("my-config-map"); ``` -------------------------------- ### Kubernetes Client Configuration Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi.adoc Configure the Kubernetes client, including enabling it, specifying the kube config path, and setting the default namespace. ```yaml kubernetes: client: enabled: true kube-config-path: file:/path/to/kubeconfig namespace: test-namespace service-account: enabled: true certificate-authority-path: file:/path/to/certificate/authority/file token-path: file:/path/to/token/file namespace-path: file:/path/to/namespace/file token-reload-interval: 2m ``` -------------------------------- ### Create ConfigMap from Literal Values Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Command to create a Kubernetes ConfigMap from literal key-value pairs. ```bash kubectl create configmap my-config --from-literal=special.how=very --from-literal=special.type=charm ``` -------------------------------- ### Get Existing SharedIndexInformer Programmatically Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/kubernetes-informer.adoc Retrieve an existing SharedIndexInformer using the SharedIndexInformerFactory bean. This is useful when you need to access an informer that has already been created. ```java import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapList; import io.micronaut.kubernetes.client.informer.SharedIndexInformerFactory; // ... SharedIndexInformerFactory informerFactory; SharedIndexInformer informer = informerFactory.get(V1ConfigMap.class, "default"); ``` -------------------------------- ### Create ConfigMap from Literal Values Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Command to create a Kubernetes ConfigMap from literal key-value pairs. ```bash kubectl create configmap my-config --from-literal=special.how=very --from-literal=special.type=charm ``` -------------------------------- ### Run All Tests Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Executes the entire test suite, including unit tests, integration tests, and functional tests that deploy applications to Kubernetes. ```shell ./gradlew test ``` -------------------------------- ### Configure Exception Handling for Pod Labels Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Configure whether to terminate startup if secrets cannot be read due to missing pod labels. Setting `exceptionOnPodLabelsMissing=true` will cause the application to fail startup in such cases. ```yaml micronaut: config: import: - optional:kubernetes://secret?podLabels=app.kubernetes.io/instance&exceptionOnPodLabelsMissing=true ``` -------------------------------- ### Legacy ConfigMap Operator with @Operator Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Implement a Kubernetes operator using the legacy `@Operator` annotation. Requires `apiType` and `apiListType` to be specified in the embedded `@Informer`. This example reconciles V1ConfigMap resources. ```java import io.kubernetes.client.extended.controller.reconciler.Request; import io.kubernetes.client.extended.controller.reconciler.Result; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapList; import io.micronaut.context.env.Environment; import io.micronaut.context.annotation.Requires; import io.micronaut.kubernetes.client.informer.Informer; import io.micronaut.kubernetes.client.operator.Operator; import io.micronaut.kubernetes.client.operator.OperatorResourceLister; import io.micronaut.kubernetes.client.operator.ResourceReconciler; import org.jspecify.annotations.NonNull; import java.util.Optional; @Requires(env = Environment.KUBERNETES) @Operator(informer = @Informer(apiType = V1ConfigMap.class, apiListType = V1ConfigMapList.class)) public class LegacyConfigMapReconciler implements ResourceReconciler { private final CoreV1Api coreV1Api; public LegacyConfigMapReconciler(CoreV1Api coreV1Api) { this.coreV1Api = coreV1Api; } @Override @NonNull public Result reconcile(@NonNull Request request, @NonNull OperatorResourceLister lister) { Optional opt = lister.get(request); opt.ifPresent(cm -> { System.out.println("Reconciling: " + cm.getMetadata().getName()); // perform work... }); return new Result(false); } } ``` -------------------------------- ### Annotate ResourceEventHandler with @Informer Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Annotate a class implementing `ResourceEventHandler` with `@Informer` to automatically create and start a `SharedIndexInformer`. This informer watches Kubernetes resources in specified namespaces and triggers event handlers. ```java import io.micronaut.kubernetes.client.openapi.informer.handler.Informer; import io.micronaut.kubernetes.client.openapi.informer.handler.ResourceEventHandler; import io.micronaut.kubernetes.client.openapi.model.V1Secret; import org.slf4j.Logger; import org.slf4j.LoggerFactory; // Watches all V1Secret objects in the current pod's namespace (resolved automatically) @Informer( apiType = V1Secret.class, namespace = Informer.RESOLVE_AUTOMATICALLY, // default; reads from SA namespace file labelSelector = "app=my-app", // optional label filter resyncCheckPeriod = 60_000L, // millis; 0 = framework default waitForInitialSync = true // block startup until cache is populated ) public class SecretResourceEventHandler implements ResourceEventHandler { private static final Logger LOG = LoggerFactory.getLogger(SecretResourceEventHandler.class); @Override public void onAdd(V1Secret obj) { // Called when a new Secret is created LOG.info("Secret added: {}", obj.getMetadata().getName()); } @Override public void onUpdate(V1Secret oldObj, V1Secret newObj) { // Called when a Secret is modified String name = oldObj.getMetadata().getName(); LOG.info("Secret updated: {}", name); } @Override public void onDelete(V1Secret obj, boolean deletedFinalStateUnknown) { // Called when a Secret is deleted // deletedFinalStateUnknown=true means the watch was interrupted before delete was observed LOG.info("Secret deleted: {} (finalStateUnknown={})", obj.getMetadata().getName(), deletedFinalStateUnknown); } } ``` -------------------------------- ### Enable Kubernetes Configuration Client Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc To enable the distributed configuration client, define `micronaut.config-client.enabled=true` in your bootstrap configuration. ```yaml micronaut: config-client: enabled: true ``` -------------------------------- ### Run Checkstyle Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Execute the Checkstyle Gradle task to ensure code quality and adherence to project coding standards before submitting a Pull Request. ```shell ./gradlew checkstyleMain ``` -------------------------------- ### Reactor Reactive Client Usage Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client.adoc Demonstrates injecting and using the Reactor reactive client for asynchronous operations. Requires the `micronaut-kubernetes-client-reactor` dependency. ```java import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1PodList; import io.micronaut.kubernetes.client.reactive.CoreV1ApiReactiveClient; import reactor.core.publisher.Mono; import jakarta.inject.Singleton; @Singleton public class MyService { private final CoreV1ApiReactiveClient coreV1ApiReactiveClient; public MyService(CoreV1ApiReactiveClient coreV1ApiReactiveClient) { this.coreV1ApiReactiveClient = coreV1ApiReactiveClient; } public void myMethod(String namespace) { Mono v1PodList = coreV1ApiReactiveClient.listNamespacedPod(namespace).execute(); } } ``` -------------------------------- ### Import ConfigMaps by Pod Labels Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Import ConfigMaps by matching labels from the pod the Micronaut application is running in, using `kubernetes://config-map?podLabels=`. This is useful for package managers like Helm. ```yaml micronaut: config: import: - optional:kubernetes://config-map?podLabels=app.kubernetes.io/instance ``` -------------------------------- ### Kubernetes Service Discovery Includes Configuration Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/service-discovery.adoc Configure Micronaut to include specific services for discovery by listing their names in the `kubernetes.client.discovery.includes` property. ```properties kubernetes: client: discovery: includes: - my-service - other-service ``` -------------------------------- ### Configure Kubernetes ConfigMaps and Secrets Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Enable and configure live reloading for ConfigMaps and Secrets. Specify which ConfigMaps/Secrets to include or exclude, and define labels or paths for mounting. ```yaml kubernetes: client: namespace: default config-maps: enabled: true watch: true # live reload on ConfigMap changes includes: [app-config, feature-flags] excludes: [kube-root-ca.crt] labels: env: production paths: - /etc/config # mount path (also supports file system) secrets: enabled: true # false by default for security watch: false includes: [db-credentials] paths: - /etc/secrets ``` -------------------------------- ### Use Reactive Kubernetes Client API Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi.adoc Inject and use configured API objects from the `io.micronaut.kubernetes.client.openapi.api.reactor` package for the reactive client. ```java snippet::micronaut.client.PodController[project-base="examples/example-kubernetes-client-openapi-reactor", source="main"] ``` -------------------------------- ### Custom Kubernetes Token Loader Implementation Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Implement a custom KubernetesTokenLoader to fetch tokens from external sources like Vault. Ensure the order is set appropriately if it needs to run before the default ServiceAccountTokenLoader. ```java import io.micronaut.kubernetes.client.openapi.credential.KubernetesTokenLoader; import jakarta.inject.Singleton; import org.jspecify.annotations.Nullable; @Singleton public class VaultTokenLoader implements KubernetesTokenLoader { @Override public @Nullable String getToken() { // Fetch a short-lived token from Vault, a secret store, etc. return System.getenv("KUBE_TOKEN"); // simplified example } @Override public int getOrder() { // Lower value = higher priority. Runs before ServiceAccountTokenLoader (order=0). return -10; } } ``` -------------------------------- ### RxJava 3 Reactive Client Usage Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client.adoc Shows how to inject and use the RxJava 3 reactive client for asynchronous operations. Requires the `micronaut-kubernetes-client-rxjava3` dependency. ```java import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1PodList; import io.micronaut.kubernetes.client.rxjava3.CoreV1ApiRxClient; import io.reactivex.Single; import jakarta.inject.Singleton; @Singleton public class MyService { private final CoreV1ApiRxClient coreV1ApiRxClient; public MyService(CoreV1ApiRxClient coreV1ApiRxClient) { this.coreV1ApiRxClient = coreV1ApiRxClient; } public void myMethod(String namespace) { Single v1PodList = coreV1ApiRxClient.listNamespacedPod(namespace).execute(); } } ``` -------------------------------- ### Define and Consume Kubernetes Watcher Interface Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Annotate an interface with `@KubernetesClientApiWatcher` and `@Client("kubernetes")` to stream `WatchEvent` objects. Consume the stream using Reactor's `Flux`. ```java import io.micronaut.http.annotation.Consumes; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.PathVariable; import io.micronaut.http.annotation.QueryValue; import io.micronaut.http.client.annotation.Client; import io.micronaut.kubernetes.client.openapi.model.V1Secret; import io.micronaut.kubernetes.client.openapi.watcher.WatchEvent; import io.micronaut.kubernetes.client.openapi.watcher.annotation.KubernetesClientApiWatcher; import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; // Define the watcher interface @KubernetesClientApiWatcher @Client("kubernetes") public interface SecretWatcher { @Get("/api/v1/namespaces/{namespace}/secrets") @Consumes({"application/json;stream=watch"}) Flux> watchNamespacedSecrets( @PathVariable String namespace, @QueryValue @Nullable String labelSelector, @QueryValue @Nullable Boolean watch ); } // Consume the watcher import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Controller("/secrets") public class SecretController { private static final Logger LOG = LoggerFactory.getLogger(SecretController.class); @Inject SecretWatcher secretWatcher; // GET /secrets/default — starts streaming watch events @Get("/{namespace}") public void watchSecrets(String namespace) { secretWatcher.watchNamespacedSecrets(namespace, null, true) .subscribe(event -> LOG.info( "type={} name={}", event.type(), event.object() != null ? event.object().getMetadata().getName() : "n/a" )); // Output: type=ADDED name=my-secret // type=MODIFIED name=my-secret // type=DELETED name=my-secret } } ``` -------------------------------- ### Programmatically Create Informers with SharedIndexInformerFactory Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Create and manage informers programmatically using `SharedIndexInformerFactory`. Attach `ResourceEventHandler` instances to the returned `SharedIndexInformer` to handle resource events. ```java import io.micronaut.context.annotation.Context; import io.micronaut.kubernetes.client.openapi.informer.SharedIndexInformer; import io.micronaut.kubernetes.client.openapi.informer.SharedIndexInformerFactory; import io.micronaut.kubernetes.client.openapi.informer.handler.ResourceEventHandler; import io.micronaut.kubernetes.client.openapi.model.V1ConfigMap; import io.micronaut.kubernetes.client.openapi.resolver.NamespaceResolver; import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Context // eagerly instantiated so informers start on application startup public class ConfigMapInformer { private static final Logger LOG = LoggerFactory.getLogger(ConfigMapInformer.class); private final SharedIndexInformerFactory factory; private final NamespaceResolver namespaceResolver; ConfigMapInformer(SharedIndexInformerFactory factory, NamespaceResolver namespaceResolver) { this.factory = factory; this.namespaceResolver = namespaceResolver; } @PostConstruct void initialize() { String namespace = namespaceResolver.resolveNamespace(); // e.g. "default" // Create informer for V1ConfigMap in the resolved namespace SharedIndexInformer informer = factory.sharedIndexInformerFor( V1ConfigMap.class, namespace, null, // labelSelector — null means no filter true, // waitForInitialSync 30_000L // resyncPeriodMillis ); informer.addEventHandler(new ResourceEventHandler<>() { @Override public void onAdd(V1ConfigMap obj) { LOG.info("ConfigMap added: {}", obj.getMetadata().getName()); } @Override public void onUpdate(V1ConfigMap oldObj, V1ConfigMap newObj) { LOG.info("ConfigMap updated: {}", oldObj.getMetadata().getName()); } @Override public void onDelete(V1ConfigMap obj, boolean deletedFinalStateUnknown) { LOG.info("ConfigMap deleted: {}", obj.getMetadata().getName()); } }); // Retrieve from cache later: // List all = informer.getIndexer().list(); // V1ConfigMap specific = informer.getIndexer().getByKey("default/my-configmap"); } } ``` -------------------------------- ### Configure Mounted ConfigMaps Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-config-client.adoc Configure the Kubernetes client to read ConfigMaps from specified directory paths. ```yaml kubernetes: client: config-maps: paths: - /etc/configuration ``` -------------------------------- ### Custom Resource List Implementation (KubernetesListObject) Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-informer.adoc Defines a custom Kubernetes resource list class. This class must implement the KubernetesListObject interface. ```java package io.micronaut.kubernetes.client.openapi.informer.example1; import io.micronaut.kubernetes.client.openapi.common.KubernetesListObject; import java.util.List; public class CustomObjectList implements KubernetesListObject { private String apiVersion; private String kind; private ObjectMeta metadata; private List items; @Override public String getApiVersion() { return apiVersion; } @Override public String getKind() { return kind; } @Override public ObjectMeta getMetadata() { return metadata; } @Override public List getItems() { return items; } // Setters and other methods omitted for brevity } ``` -------------------------------- ### Import Kubernetes ConfigMap and Secret Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/config-import.adoc Configure `micronaut.config.import` to load Kubernetes ConfigMap and Secret resources. These will be available as PropertySource instances. ```yaml micronaut: config: import: - optional:kubernetes://config-map?name=my-config-map - optional:kubernetes://secret?name=my-secret ``` -------------------------------- ### Kubernetes Test Specification Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/CONTRIBUTING.md Set up a test specification using `@MicronautTest` and `@Requires` to ensure Kubernetes API is available. Configure namespace reuse behavior. ```groovy @MicronautTest @Requires({ TestUtils.kubernetesApiAvailable() }) @Property(name = "kubernetes.client.namespace", value = "kubernetes-micronaut") @Property(name = "spec.reuseNamespace", value = "false") class ApiClientFactorySpec extends KubernetesSpecification { } ``` -------------------------------- ### Match ConfigMaps by Pod Labels Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Include ConfigMaps that share the same Kubernetes labels as the running pod by specifying label keys in `kubernetes.client.config-maps.pod-labels`. This is useful with package managers like Helm. ```yaml kubernetes: client: config-maps: pod-labels: - "app.kubernetes.io/instance" ``` -------------------------------- ### Configure HTTPS for Service Discovery (Labels) Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client-openapi/kubernetes-client-openapi-service-discovery.adoc Configure Kubernetes services to use HTTPS by adding a label 'secure: "true"'. The client will automatically detect and use SSL for services with this label. ```yaml apiVersion: v1 kind: Service metadata: name: secure-deployment labels: secure: "true" spec: ports: - name: http port: 80 targetPort: 8080 ``` -------------------------------- ### Kubernetes Service Discovery Client Usage Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Use `KubernetesDiscoveryClient` to resolve services within the cluster. This can be done declaratively with `@Client` or programmatically using `DiscoveryClient`. ```java // Any @Client with service ID is auto-resolved via KubernetesDiscoveryClient import io.micronaut.http.annotation.Get; import io.micronaut.http.client.annotation.Client; @Client("my-backend-service") // resolves to a Kubernetes Service named "my-backend-service" public interface BackendClient { @Get("/api/health") String health(); } // Programmatic usage via DiscoveryClient import io.micronaut.discovery.DiscoveryClient; import io.micronaut.discovery.ServiceInstance; import jakarta.inject.Inject; import reactor.core.publisher.Flux; import java.util.List; class ServiceLookup { @Inject DiscoveryClient discoveryClient; Flux> findInstances() { return Flux.from(discoveryClient.getInstances("my-backend-service")); // emits: [ServiceInstance{id=my-backend-service, host=10.0.0.5, port=8080}] } Flux> listAllServiceIds() { return Flux.from(discoveryClient.getServiceIds()); // emits: [["my-backend-service","auth-service","postgres",...]] } } ``` -------------------------------- ### Programmatic Controller Creation with ControllerFactory Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Use ControllerFactory to programmatically create Kubernetes controllers, offering full control over informer creation, namespaces, work-queue, and filters. This approach is suitable when advanced customization is required. ```java import io.micronaut.context.annotation.Context; import io.micronaut.kubernetes.client.openapi.informer.SharedIndexInformerFactory; import io.micronaut.kubernetes.client.openapi.model.V1Secret; import io.micronaut.kubernetes.client.openapi.operator.OperatorResourceLister; import io.micronaut.kubernetes.client.openapi.operator.controller.ControllerFactory; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.Request; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.ResourceReconciler; import io.micronaut.kubernetes.client.openapi.operator.controller.reconciler.Result; import io.micronaut.kubernetes.client.openapi.resolver.NamespaceResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Optional; import java.util.Set; @Context public class SecretOperator { private static final Logger LOG = LoggerFactory.getLogger(SecretOperator.class); SecretOperator( SharedIndexInformerFactory informerFactory, ControllerFactory controllerFactory, NamespaceResolver namespaceResolver ) { String namespace = namespaceResolver.resolveNamespace(); // Step 1: create the informer (must happen before creating the controller) informerFactory.sharedIndexInformerFor(V1Secret.class, namespace); // Step 2: create the controller with the reconciler controllerFactory.createController( "secret-operator", // unique controller name V1Secret.class, Set.of(namespace), // null → cluster-wide new SecretReconciler() ); // Step 3: controllers are started automatically by ControllersLifecycleListener } private static class SecretReconciler implements ResourceReconciler { @Override public Result reconcile(Request request, OperatorResourceLister lister) { Optional secret = lister.get(request); if (secret.isPresent()) { LOG.info("Reconciling secret: {}/{}", request.namespace(), request.name()); // perform reconciliation logic here } return new Result(false); } } } ``` -------------------------------- ### OnAddFilter for V1ConfigMap Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/kubernetes-operator.adoc Implement a Predicate to filter newly created V1ConfigMap resources before they are added to the reconciler work queue. ```java package io.micronaut.kubernetes.client.operator; import io.micronaut.kubernetes.client.operator.Operator; import io.micronaut.kubernetes.client.operator.reconciler.ResourceReconciler; import io.kubernetes.client.openapi.models.V1ConfigMap; import jakarta.inject.Singleton; import java.util.function.Predicate; @Singleton public class ConfigMapOnAddFilter implements Predicate { @Override public boolean test(V1ConfigMap v1ConfigMap) { return !v1ConfigMap.getMetadata().getName().startsWith("test-"); } } ``` -------------------------------- ### Listen for Kubernetes Leader Election Events Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Implement listeners for LeaseAcquiredEvent, LeaseLostEvent, and LeaderChangedEvent to manage active controller work based on leadership status. ```java import io.micronaut.kubernetes.client.openapi.operator.leaderelection.event.LeaseAcquiredEvent; import io.micronaut.kubernetes.client.openapi.operator.leaderelection.event.LeaseLostEvent; import io.micronaut.kubernetes.client.openapi.operator.leaderelection.event.LeaderChangedEvent; import io.micronaut.runtime.event.annotation.EventListener; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class LeaderElectionListener { private static final Logger LOG = LoggerFactory.getLogger(LeaderElectionListener.class); // Fired when THIS instance acquires the Kubernetes Lease @EventListener public void onLeaseAcquired(LeaseAcquiredEvent event) { LOG.info("I am the leader! record={}", event.leaderElectionRecord()); // Start active controller work here } // Fired when THIS instance loses the Kubernetes Lease @EventListener public void onLeaseLost(LeaseLostEvent event) { LOG.warn("Leadership lost. record={}", event.leaderElectionRecord()); // Stop active controller work here } // Fired whenever the current leader identity changes @EventListener public void onLeaderChanged(LeaderChangedEvent event) { LOG.info("New leader: {}", event.leaderElectionRecord().holderIdentity()); } } ``` -------------------------------- ### Filter ConfigMaps by Labels Source: https://github.com/micronaut-projects/micronaut-kubernetes/blob/8.0.x/src/main/docs/guide/kubernetes-client/config-client.adoc Use Kubernetes labels to match ConfigMaps by defining `kubernetes.client.config-maps.labels` with key-value pairs. ```yaml kubernetes: client: config-maps: labels: - app: my-app - env: prod ``` -------------------------------- ### Kubernetes Service Discovery Configuration Source: https://context7.com/micronaut-projects/micronaut-kubernetes/llms.txt Configure Kubernetes service discovery in `application.yml`. This enables resolving Kubernetes services as Micronaut `ServiceInstance` objects for load-balanced HTTP client calls. ```yaml # application.yml kubernetes: client: namespace: default discovery: enabled: true mode: endpoint # "endpoint" (default) or "service" # includes: [backend, auth-service] # whitelist # excludes: [legacy-svc] # blacklist # labels: # tier: backend ```