Giter Club home page Giter Club logo

micronaut-kubernetes's Introduction

Micronaut Kubernetes

Maven Central Snapshot Build Status Revved up by Develocity

This project includes integration between Micronaut and Kubernetes.

Documentation

See the Documentation for more information.

See the Snapshot Documentation for the current development docs.

Contributing Code

If you wish to contribute to the development of this project please read the CONTRIBUTING.md

Snapshots and Releases

Snaphots are automatically published to JFrog OSS using Github Actions.

See the documentation in the Micronaut Docs for how to configure your build to use snapshots.

Releases are published to JCenter and Maven Central via Github Actions.

A release is performed with the following steps:

micronaut-kubernetes's People

Contributors

alextu avatar alvarosanchez avatar dependabot-preview[bot] avatar dependabot[bot] avatar dradosevic avatar dstepanov avatar gavrilovsv avatar graemerocher avatar grollinger avatar ilopmar avatar ksnz avatar micronaut-build avatar miguelaferreira avatar mkuchin avatar n0tl3ss avatar nicklarsennz avatar nicronir avatar pgressa avatar rdesgroppes avatar renovate[bot] avatar sdelamo avatar timyates avatar vmahindroo1 avatar wetted avatar xaseron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

micronaut-kubernetes's Issues

Support hot reloading for mounted volume configmaps and secrets

The documentation says that this library supports reading configmaps from mounted volumes. I have not been able to find a way to make it work nor have I seen the code that would make this possible.

Also the library only supports watching for changes of configmaps.

I modified the code to support reading both configmaps and secrets from mounted volumes and also watch for changes to both of them. code

I am not feeling comfortable enough to already make a pull request. The code has lots of replication in it and I have some issues with writing/running tests.

I would like to ask for advice and if there is a need for this besides my own. In my case I am not allowed to use the kubernetes API, so mounted volumes is the only way I can read configmaps or secrets.

Error during application startup - UnknownHostException: None

The following exception is thrown during the application startup.

12:16:47.535 [nioEventLoopGroup-1-4] ERROR i.m.m.health.indicator.HealthResult - Health indicator [compositeDiscoveryClient(kubernetes)] reported exception: io.micronaut.http.codec.CodecException: Error decoding JSON stream for type [T]: None (through reference chain: io.micronaut.kubernetes.client.v1.services.ServiceList["items"]->java.util.ArrayList[2])
io.micronaut.http.codec.CodecException: Error decoding JSON stream for type [T]: None (through reference chain: io.micronaut.kubernetes.client.v1.services.ServiceList["items"]->java.util.ArrayList[2])
        at io.micronaut.jackson.codec.JsonMediaTypeCodec.decode(JsonMediaTypeCodec.java:123)
        at io.micronaut.http.client.DefaultHttpClient.lambda$null$16(DefaultHttpClient.java:895)
        at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:63)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
        at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
        at io.micronaut.http.context.ServerRequestContext.lambda$instrument$0(ServerRequestContext.java:68)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
        at io.micronaut.jackson.parser.JacksonProcessor.lambda$onUpstreamMessage$0(JacksonProcessor.java:153)
        at java.base/java.util.Optional.ifPresent(Optional.java:183)
        at io.micronaut.jackson.parser.JacksonProcessor.onUpstreamMessage(JacksonProcessor.java:149)
        at io.micronaut.jackson.parser.JacksonProcessor.onUpstreamMessage(JacksonProcessor.java:41)
        at io.micronaut.core.async.processor.SingleThreadedBufferingProcessor.doOnNext(SingleThreadedBufferingProcessor.java:56)
        at io.micronaut.core.async.subscriber.SingleThreadedBufferingSubscriber.onNext(SingleThreadedBufferingSubscriber.java:91)
        at io.reactivex.internal.util.HalfSerializer.onNext(HalfSerializer.java:45)
        at io.reactivex.internal.subscribers.StrictSubscriber.onNext(StrictSubscriber.java:97)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
        at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
        at io.micronaut.http.context.ServerRequestContext.lambda$instrument$0(ServerRequestContext.java:68)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
        at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:68)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.lambda$onNext$0(InstrumentedSubscriber.java:80)
        at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
        at io.micronaut.http.context.ServerRequestContext.lambda$instrument$0(ServerRequestContext.java:68)
        at io.micronaut.reactive.rxjava2.InstrumentedSubscriber.onNext(InstrumentedSubscriber.java:84)
        at io.micronaut.http.netty.reactive.HandlerPublisher.publishMessage(HandlerPublisher.java:461)
        at io.micronaut.http.netty.reactive.HandlerPublisher.channelRead(HandlerPublisher.java:417)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        at io.micronaut.http.netty.stream.HttpStreamsHandler.handleReadHttpContent(HttpStreamsHandler.java:239)
        at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:222)
        at io.micronaut.http.netty.stream.HttpStreamsClientHandler.channelRead(HttpStreamsClientHandler.java:180)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:315)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:429)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1475)
        at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1224)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1271)
        at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:505)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:444)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: None (through reference chain: io.micronaut.kubernetes.client.v1.services.ServiceList["items"]->java.util.ArrayList[2])
        at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
        at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:365)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:302)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3984)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2276)
        at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:2758)
        at io.micronaut.jackson.codec.JsonMediaTypeCodec.decode(JsonMediaTypeCodec.java:121)
        ... 69 common frames omitted
Caused by: java.net.UnknownHostException: None
        at java.base/java.net.InetAddress$CachedAddresses.get(InetAddress.java:797)
        at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1505)
        at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1364)
        at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1298)
        at java.base/java.net.InetAddress.getByName(InetAddress.java:1248)
        at com.fasterxml.jackson.databind.deser.std.FromStringDeserializer$Std._deserialize(FromStringDeserializer.java:276)
        at com.fasterxml.jackson.databind.deser.std.FromStringDeserializer.deserialize(FromStringDeserializer.java:145)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
        ... 78 common frames omitted

The app is build with the standard jib image gcr.io/distroless/java:latest and running on GKE with kubernetes version 1.12.8-gke.10

I'll try to provide an example application with that bug.

Use official Kubernetes Java SDK client

Currently we have our own simple implementation of K8s client. In order to implement more complex features (operator, informer, ..) we would have to extend the client in such spread that we would ended duplicating extensively used official k8s client. To not reinvent a wheel we will replace current implementation with official K8s java sdk.

Micronaut-kubernetes project depends of ServiceStartedEvent the is not longer available on core.

Hi guys,

I'm frustrated with the new "way" to Micronaut support service discovery on k8s, in the 1.x version it's much more easy.

Apart of this, it is not working since the project micronaut-kubernetes depends of core class io.micronaut.discovery.event.ServiceStartedEvent that is no longer available.

I suppose that this problem is caused by the follow change that is not applied to the micronaut-kubernetes.

image

Steps to Reproduce

  1. Create a 2.0.0.M3
  2. Add micronaut-kubernetes
  3. Start project

Actual Behaviour

Throws the exception

java.lang.NoClassDefFoundError: io.micronaut.discovery.event.ServiceStartedEvent
	at io.micronaut.kubernetes.configuration.$KubernetesConfigMapWatcherDefinition.getTypeArgumentsMap(Unknown Source)
	at io.micronaut.context.AbstractBeanDefinition.getTypeArguments(AbstractBeanDefinition.java:204)
	at io.micronaut.inject.BeanDefinition.getTypeArguments(BeanDefinition.java:200)
	at io.micronaut.inject.qualifiers.TypeArgumentQualifier.getTypeArguments(TypeArgumentQualifier.java:93)
	at io.micronaut.inject.qualifiers.TypeArgumentQualifier.lambda$reduce$1(TypeArgumentQualifier.java:58)
	at io.micronaut.inject.qualifiers.TypeArgumentQualifier$$Lambda$455.00000000E8F04E70.test(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:489)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:241)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2750)
	at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:723)
	at io.micronaut.context.DefaultBeanContext.publishEvent(DefaultBeanContext.java:1234)
	at io.micronaut.context.DefaultBeanContext.start(DefaultBeanContext.java:231)
	at io.micronaut.context.DefaultApplicationContext.start(DefaultApplicationContext.java:166)
	at io.micronaut.runtime.Micronaut.start(Micronaut.java:64)
	at io.micronaut.runtime.Micronaut.run(Micronaut.java:294)
	at io.micronaut.runtime.Micronaut.run(Micronaut.java:280)
	at user.Application.main(Application.java:8)
Caused by: java.lang.ClassNotFoundException: io.micronaut.discovery.event.ServiceStartedEvent
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:753)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:1032)
	... 24 common frames omitted

Environment Information

  • Operating System: Any
  • Micronaut Version: 2.0.0.M3
  • JDK Version: Any

Knative Service Discovery

Does anyone know how to use kubernetes service discovery with Knative. I want to use the kubernetes service discovery with micronaut here.

https://micronaut-projects.github.io/micronaut-kubernetes/2.0.0/guide/index.html

But as you know knative deploys the service and deployment with just one file, and the service name is auto generated. So won't be able to use @client('service-name') in the Declarative HTTP. Does anyone know how to get around that, any help would be appreciated. Thanks.

Micronaut - Kubernetes plugin not working for https API endpoints

While trying to access kubernetes volume mounted secrets through micronaut application with the below config, I get an error. Do I have the right config?

kubernetes:
  client:
    host: https://my-az-aks-cluster-url
    port: 443
    secure: false
    namespace: default
    secrets:
      enabled: true
      paths:
        - /Users/a871671/Documents/foo

Error while trying to list all Kubernetes Services in the namespace [default] io.micronaut.http.client.exceptions.HttpClientException: Connect error:https

Feature Request: Flexible kubernetes client authentication methods

The current method of authenticating with the kubernetes API via the secret mounted on /var/run/secrets/kubernetes.io/serviceaccount/token makes it very hard to test, or use the kubernetes client low level client outside of a k8s environment. The fabric8 client has a flexible way to provide the token, the ca mount taking the least precedence:

https://github.com/fabric8io/kubernetes-client#configuring-the-client

Would be nice to have a similar way to have a default of reading the file, but allowing an environment variable or use kube config to pull the token.

Micronaut fails to start if configmap is loaded with no data elements

Spotted today on Micronaut 2.0.2 but by looking at the code its likely this issue is also on latest. It looks like when an empty config map is loaded there is a missing null guard on configMapAsPropertySource within KubernetesUtils.java which leads to a null pointer exception on application startup. Specifically:
Map.Entry<String, String> entry = data.entrySet().iterator().next();

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

Create a config map with no data elements in it:

apiVersion: v1
kind: ConfigMap
metadata:
  name: example-cm
  labels:
    app: example-app
data: {}

Load the config map in a micronaut app:
bootstrap.yml

micronaut:
  config-client:
    enabled: true
kubernetes:
  client:
    config-maps:
      watch: true
      includes:
        - example-cm

Expected Behaviour

The application should start

Actual Behaviour

The application fails to start and returns a null exception on startup:

Envoy Ready continuing...
17:03:14[main][][INFO]i.m.c.e.DefaultEnvironment:: Established active environments: [k8s, cloud]
17:03:14[main][][INFO]i.m.c.e.DefaultEnvironment:: Established active environments: [k8s, cloud]
17:03:14[main][][INFO]i.m.c.DefaultBeanContext:: Reading Startup environment from bootstrap.yml
17:03:17[main][][ERROR]i.m.r.Micronaut:: Error starting Micronaut server: null
java.util.NoSuchElementException: null
	at java.base/java.util.HashMap$HashIterator.nextNode(Unknown Source)
	at java.base/java.util.HashMap$EntryIterator.next(Unknown Source)
	at java.base/java.util.HashMap$EntryIterator.next(Unknown Source)
	at io.micronaut.kubernetes.util.KubernetesUtils.configMapAsPropertySource(KubernetesUtils.java:62)

Environment Information

  • Operating System: AKS (Replicated in EKS)
  • Micronaut Version: 2.0.2
  • JDK Version: 11

Helm Support

Helm is the de-facto standard for running and managing applications with Kubernetes. We rely heavily on it and we put our application.yaml inside a configMap.
For each feature branch we deployed our application into the same namespace. Therefore there a lot of configMaps with application.yamls.
e.g.:13:50:45.410 [main] INFO i.m.d.c.c.DistributedPropertySourceLocator - Resolved 21 configuration sources from client: compositeConfigurationClient(kubernetes)
We need an easy mechanism to filter these configMaps.
Currently we have to change the bootstrap.yaml in each branch and don't forget to change it back before merging it. e.g.:

kubernetes:
  client:
    config-maps:
      labels:
        - "app.kubernetes.io/instance" : myapplication-my-feature-branch

It would be awesome to have some native support for Helm.
That we can enable a flag that automatically gets the app.kubernetes.io/instance label from the application pod and uses it for filtering the config-maps and secrets.

GCP Tracing issues on latest version

Steps to Reproduce

  1. I've created a new project using launch. Added following features: config-kubernetes, gcp-cloud-trace, jib, kubernetes.

Sample build.gradle

plugins {
    id "com.diffplug.eclipse.apt" version "3.22.0"
    id "application"
    id "com.google.cloud.tools.jib" version "2.1.0"
}

version "0.1"
group "com.example.tracing"

repositories {
    mavenCentral()
    jcenter()
}

configurations {
    // for dependencies that are needed for development only
    developmentOnly
}

dependencies {
    annotationProcessor(platform("io.micronaut:micronaut-bom:$micronautVersion"))
    annotationProcessor("io.micronaut:micronaut-inject-java")
    annotationProcessor("io.micronaut:micronaut-validation")
    implementation(platform("io.micronaut:micronaut-bom:$micronautVersion"))
    implementation("io.micronaut:micronaut-inject")
    implementation("io.micronaut:micronaut-validation")
    implementation("io.micronaut:micronaut-runtime")
    implementation("javax.annotation:javax.annotation-api")
    implementation("io.micronaut:micronaut-http-server-netty")
    implementation("io.micronaut:micronaut-http-client")
    implementation("io.micronaut:micronaut-management")
    implementation("io.micronaut.kubernetes:micronaut-kubernetes-discovery-client")
    implementation("io.micronaut.gcp:micronaut-gcp-tracing")
    runtimeOnly("ch.qos.logback:logback-classic")
    testAnnotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
    testAnnotationProcessor("io.micronaut:micronaut-inject-java")
    testImplementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
    testImplementation("org.junit.jupiter:junit-jupiter-api")
    testImplementation("io.micronaut.test:micronaut-test-junit5")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}

test.classpath += configurations.developmentOnly

mainClassName = "com.example.tracing.Application"

// use JUnit 5 platform
test {
    useJUnitPlatform()
}

java {
    sourceCompatibility = JavaVersion.toVersion('11')
    targetCompatibility = JavaVersion.toVersion('11')
}

tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
    options.compilerArgs.addAll([
        '-parameters',
        // enables incremental compilation
        '-Amicronaut.processing.incremental=true',
        '-Amicronaut.processing.annotations=com.example.tracing.*',
        "-Amicronaut.processing.group=$project.group",
        "-Amicronaut.processing.module=$project.name",
    ])
}


tasks.withType(JavaExec) {
    classpath += configurations.developmentOnly
    jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote')
    if (gradle.startParameter.continuous) {
        systemProperties(
            'micronaut.io.watch.restart':'true',
            'micronaut.io.watch.enabled':'true',
            "micronaut.io.watch.paths":"src/main"
        )
    }
}


jib.to.image = 'gcr.io/frontend/jib-image'

Added a single controller:

package com.example.tracing.controllers;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.tracing.annotation.ContinueSpan;
import io.reactivex.Single;

@Controller("/drivers")
public class FrontEndController {

    @Get("/")
    @ContinueSpan
    public Single<String> ok() {
        return Single.just("ok");
    }

}

When the application boots an exception is thrown and the application fails to start

Message: brave/http/HttpClientHandler

Path Taken: new NettyHttpServer(NettyHttpServerConfiguration serverConfiguration,ApplicationContext applicationContext,[Router router],RequestArgumentSatisfier requestArgumentSatisfier,MediaTypeCodecRegistry mediaTypeCodecRegistry,NettyCustomizableResponseTypeHandlerRegistry customizableResponseTypeHandlerRegistry,StaticResourceResolver resourceResolver,Provider ioExecutor,ThreadFactory threadFactory,ExecutorSelector executorSelector,ServerSslBuilder serverSslBuilder,List outboundHandlers,EventLoopGroupFactory eventLoopGroupFactory,EventLoopGroupRegistry eventLoopGroupRegistry,HttpCompressionStrategy httpCompressionStrategy,HttpContentProcessorResolver httpContentProcessorResolver,ChannelOptionFactory channelOptionFactory) --> new DefaultRouter([Collection builders])

"io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [io.micronaut.web.router.DefaultRouter]

Caused by: java.lang.NoClassDefFoundError: brave/http/HttpClientHandler at io.micronaut.tracing.brave.instrument.http.$BraveTracingClientFilterDefinition.<init>(Unknown Source) at io.micronaut.tracing.brave.instrument.http.$BraveTracingClientFilterDefinitionClass.load(Unknown Source) at io.micronaut.context.AbstractBeanDefinitionReference.load(AbstractBeanDefinitionReference.java:62) at io.micronaut.context.DefaultBeanContext.lambda$getBeanDefinitions$12(DefaultBeanContext.java:1141) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.concurrent.ConcurrentLinkedQueue.forEachFrom(ConcurrentLinkedQueue.java:1037) at java.base/java.util.concurrent.ConcurrentLinkedQueue$CLQSpliterator.forEachRemaining(ConcurrentLinkedQueue.java:894) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) at io.micronaut.context.DefaultBeanContext.getBeanDefinitions(DefaultBeanContext.java:1144) at io.micronaut.context.AnnotationProcessorListener.onCreated(AnnotationProcessorListener.java:105) at io.micronaut.context.AnnotationProcessorListener.onCreated(AnnotationProcessorListener.java:45) at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1945) at io.micronaut.context.DefaultBeanContext.addCandidateToList(DefaultBeanContext.java:2961) at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2872) at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:1040) at io.micronaut.context.AbstractBeanDefinition.lambda$getBeansOfTypeForConstructorArgument$9(AbstractBeanDefinition.java:1143) at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1820) at io.micronaut.context.AbstractBeanDefinition.getBeansOfTypeForConstructorArgument(AbstractBeanDefinition.java:1138) at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:990) at io.micronaut.web.router.$DefaultRouterDefinition.build(Unknown Source) at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889) ... 19 common frames omitted

Expected Behaviour

App should start :)

What I find really strange is that looks like BraveTracingClientFilter should not really start as the classpath is missing the brave-http-instrumentation jar.

This does look like a classpath/library version issue

Environment Information

  • Operating System: alpine14jdk
  • Micronaut Version: 2.0.1
  • JDK Version: 14 openjdk

Example Application

  • TODO: link to github repository with example that reproduces the issue

When there's service without endpoins the service discovery throws NPE

11:33:07.174 [default-nioEventLoopGroup-1-13] ERROR i.m.k.d.p.KubernetesServiceInstanceEndpointProvider - Error while processing discovered endpoints [consumer-service]
java.lang.NullPointerException: Cannot invoke "java.util.List.stream()" because the return value of "io.micronaut.kubernetes.client.v1.endpoints.EndpointsSubset.getAddresses()" is null
        at io.micronaut.kubernetes.discovery.provider.KubernetesServiceInstanceEndpointProvider.lambda$null$8(KubernetesServiceInstanceEndpointProvider.java:99)
        at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:271)
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
        at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1624)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
        at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
        at io.micronaut.kubernetes.discovery.provider.KubernetesServiceInstanceEndpointProvider.lambda$getInstances$9(KubernetesServiceInstanceEndpointProvider.java:100)
        at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:63)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableFilter$FilterSubscriber.tryOnNext(FlowableFilter.java:74)
        at io.reactivex.internal.operators.flowable.FlowableFilter$FilterSubscriber.onNext(FlowableFilter.java:52)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableFlattenIterable$FlattenIterableSubscriber.drain(FlowableFlattenIterable.java:312)
        at io.reactivex.internal.operators.flowable.FlowableFlattenIterable$FlattenIterableSubscriber.onNext(FlowableFlattenIterable.java:174)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableFilter$FilterSubscriber.tryOnNext(FlowableFilter.java:74)
        at io.reactivex.internal.operators.flowable.FlowableFilter$FilterSubscriber.onNext(FlowableFilter.java:52)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableOnErrorNext$OnErrorNextSubscriber.onNext(FlowableOnErrorNext.java:80)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableOnErrorNext$OnErrorNextSubscriber.onNext(FlowableOnErrorNext.java:80)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.drain(FlowableSwitchMap.java:307)
        at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapInnerSubscriber.onNext(FlowableSwitchMap.java:391)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:68)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.micronaut.jackson.parser.JacksonProcessor.publishNode(JacksonProcessor.java:209)
        at io.micronaut.jackson.parser.JacksonProcessor.onUpstreamMessage(JacksonProcessor.java:176)
        at io.micronaut.jackson.parser.JacksonProcessor.onUpstreamMessage(JacksonProcessor.java:47)
        at io.micronaut.core.async.processor.SingleThreadedBufferingProcessor.doOnNext(SingleThreadedBufferingProcessor.java:56)
        at io.micronaut.core.async.subscriber.SingleThreadedBufferingSubscriber.onNext(SingleThreadedBufferingSubscriber.java:91)
        at io.reactivex.internal.util.HalfSerializer.onNext(HalfSerializer.java:45)
        at io.reactivex.internal.subscribers.StrictSubscriber.onNext(StrictSubscriber.java:97)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:68)
        at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:59)
        at io.micronaut.http.netty.reactive.HandlerPublisher.publishMessage(HandlerPublisher.java:378)
        at io.micronaut.http.netty.reactive.HandlerPublisher.access$600(HandlerPublisher.java:65)
        at io.micronaut.http.netty.reactive.HandlerPublisher$ChannelSubscription.flushBuffer(HandlerPublisher.java:487)
        at io.micronaut.http.netty.reactive.HandlerPublisher$ChannelSubscription.receivedDemand(HandlerPublisher.java:534)
        at io.micronaut.http.netty.reactive.HandlerPublisher$ChannelSubscription.lambda$request$0(HandlerPublisher.java:474)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:832)

`kubernetes.client.read-idle-timeout` setting does not seem to be taken into account by `KubernetesConfigMapWatcher`

Steps to Reproduce

  1. Observe that KubernetesConfigMapWatcher installed stream always times out after exactly 5 minutes without event:
    io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | io.micronaut.http.client.exceptions.ReadTimeoutException: Read Timeout
    
  2. Try setting kubernetes.client.read-idle-timeout to 0s or a negative duration, in either bootstrap.yml or application.yml
  3. Redeploy.

Expected Behaviour

The KubernetesConfigMapWatcher installed stream doesn't time out.

Actual Behaviour

The KubernetesConfigMapWatcher installed stream still times out after 5 minutes without event.

Are Configuration Properties for KubernetesConfiguration applicable to the KubernetesClient used by KubernetesConfigMapWatcher?

Environment Information

  • Micronaut Version: 2.5.3

Fail to publish snapshots with new build plugins

After upgrading to the internal build plugins 3.0.1 the snapshot publications fail with:

To honour the JVM settings for this build a single-use Daemon process will be forked. See docs.gradle.org/6.8.2/userguide/gradle_daemon.html#sec:disabling_the_daemon.
Daemon will be stopped at the end of the build 
> Task :initializeSonatypeStagingRepository SKIPPED
> Task :kubernetes-discovery-client:compileJava UP-TO-DATE
> Task :kubernetes-discovery-client:compileGroovy NO-SOURCE
> Task :kubernetes-discovery-client:processResources NO-SOURCE
> Task :kubernetes-discovery-client:classes UP-TO-DATE
> Task :kubernetes-discovery-client:jar UP-TO-DATE

> Task :kubernetes-discovery-client:generateMetadataFileForMavenPublication FAILED

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':kubernetes-discovery-client:generateMetadataFileForMavenPublication'.
> Invalid publication 'maven':
    - Publication only contains dependencies and/or constraints without a version. You need to add minimal version information, publish resolved versions (docs.gradle.org/6.8.2/userguide/publishing_maven.html#publishing_maven:resolved_dependencies) or reference a platform (docs.gradle.org/6.8.2/userguide/platforms.html)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at help.gradle.org

BUILD FAILED in 9s
See docs.gradle.org/6.8.2/userguide/command_line_interface.html#sec:command_line_warnings
3 actionable tasks: 1 executed, 2 up-to-date

Log: https://github.com/micronaut-projects/micronaut-kubernetes/runs/1926614709?check_suite_focus=true#step:8:27

Graalvm is not supported out of the box

To make possible to use micronaut-kubernetes with graalvm is necessary to add the following typehint

@TypeHint(
        value = {
                io.micronaut.kubernetes.client.v1.Port.class,
                io.micronaut.kubernetes.client.v1.Address.class,
                io.micronaut.kubernetes.client.v1.KubernetesObject.class,
                io.micronaut.kubernetes.client.v1.Metadata.class,
                io.micronaut.kubernetes.client.v1.endpoints.Endpoints.class,
                io.micronaut.kubernetes.client.v1.endpoints.EndpointsList.class,
                io.micronaut.kubernetes.client.v1.endpoints.EndpointsSubset.class,
                io.micronaut.kubernetes.client.v1.services.Service.class,
                io.micronaut.kubernetes.client.v1.services.ServiceList.class,
                io.micronaut.kubernetes.client.v1.services.ServiceSpec.class,
                io.micronaut.kubernetes.client.v1.pods.ContainerStatus.class,
                io.micronaut.kubernetes.client.v1.pods.Pod.class,
                io.micronaut.kubernetes.client.v1.pods.PodStatus.class,
                io.micronaut.kubernetes.client.v1.secrets.Secret.class,
                io.micronaut.kubernetes.client.v1.secrets.SecretList.class,
                io.micronaut.kubernetes.client.v1.configmaps.ConfigMap.class,
                io.micronaut.kubernetes.client.v1.configmaps.ConfigMapList.class,
                io.micronaut.kubernetes.client.v1.configmaps.ConfigMapWatchEvent.class,
        },
        typeNames = {
                "io.micronaut.caffeine.cache.SSAW",
                "io.micronaut.caffeine.cache.PSAW"
        },
        accessType = {
                TypeHint.AccessType.ALL_DECLARED_CONSTRUCTORS,
                TypeHint.AccessType.ALL_PUBLIC_METHODS,
                TypeHint.AccessType.ALL_DECLARED_FIELDS
        }
)
public class Application {

    public static void main(String[] args) {
        Micronaut.run(Application.class);
    }
}

it would be great to add this settings to reflection-config.json to make it easier to use.

Remove assumption on cluster domain name

Not all Kubernetes clusters use cluster.local as their domain.

At least in my cluster kubernetes.default.svc is one of the Subject Alternate Names in the TLS certificate.

For safety, you can check by executing the following from a container inside the cluster which has openssl:

echo | openssl s_client -showcerts -connect kubernetes.default.svc:443 2> /dev/null | openssl x509 -noout -text | grep DNS

[KubernetesDiscoveryClient] Kubernetes api server called on each client request

Every client request triggers a call to the KubernetesDiscoveryClient.getInstances which in turn queries the k8s api to get a list of endpoints.
That behavior causes performance and robustness degradation. The service-instances can be cached by using micronaut-caching, but that seems like a bad solution when pod-ip's are used.
An option would be for the discovery-client to listen to pod state changes and update the service-instance list.

Noisy Logging on Kubernetes RDS mysql client

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Expected Behaviour

Clients that do not expose anything in a running pod should not spam logs with Error messages

Actual Behaviour

KubernetesDiscoveryClient is spamming log with error message.

Environment Information

  • Operating System: NA
  • Micronaut Version: 1.2.0
  • JDK Version: 8

Here is the full stack trace.

14:53:55.471 [nioEventLoopGroup-3-3] ERROR i.m.k.d.KubernetesDiscoveryClient - Error while trying to get Kubernetes Endpoints for the service [mysql] in the nam │
│ io.micronaut.http.client.exceptions.HttpClientResponseException: Not Found                                                                                       │
│     at io.micronaut.http.client.DefaultHttpClient$9.channelRead0(DefaultHttpClient.java:1657)                                                                    │
│     at io.micronaut.http.client.DefaultHttpClient$9.channelRead0(DefaultHttpClient.java:1594)                                                                    │
│     at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)                                                            │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)                                                    │
│     at io.micronaut.http.netty.reactive.HandlerPublisher.channelRead(HandlerPublisher.java:434)                                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)                                                    │
│     at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:219)                                                                │
│     at io.micronaut.http.netty.stream.HttpStreamsClientHandler.channelRead(HttpStreamsClientHandler.java:180)                                                    │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)                                                    │
│     at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)                                                              │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)                                                    │
│     at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)                      │
│     at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)                                                                │
│     at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:315)                                                                │
│     at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:429)                                                                     │
│     at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)                                                                    │
│     at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)                                                          │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)                                                    │
│     at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1475)                                                                                              │
│     at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1224)                                                                                 │
│     at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1271)                                                                                              │
│     at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:505)                                                 │
│     at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:444)                                                                     │
│     at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)                                                                    │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)                                                    │
│     at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)                                                         │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)                                                  │
│     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)                                                  │
│     at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)                                                                  │
│     at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)                                                           │
│     at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)                                                                               │
│     at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)                                                                     │
│     at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)                                                                              │
│     at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)                                                                                              │
│     at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)                                                              │
│     at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)                                                                                 │
│     at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)                                                                     │
│     at java.lang.Thread.run(Thread.java:748)               

[KubernetesDiscoveryClient] Support cluster-ip as service-instance

Hi,
In Micronaut 2.0.x the Kubernetes discovery get pod ip's in the service-instance list that is returned from the discovery-client. In one of our cases where we have a few thousand requests per second to another service we get problems when pods are recycled, because the pod list is apparently not up to date.
On the other hand, with Micronaut 1.2.x that we also run, which uses cluster-ip's, we dont have that same issue. So it seems that the cluster-ip has a more up-to-date pod state.

Would it be possible to make the k8s discovery client configurable wrt returning cluster-ip's or pod-ip's in the service-instance list?

k8s cold boot time super slow due too many ENV_VARS_USING_UNDESCORES

Because the number of properties generated is exponential based on the number of _ characters in the environment variable, it is recommended to refine which, if any, environment variables are included in configuration if the number of environment variables with a large number of underscores is high.

Above is a quote from official docs describing how env variables are treated. Even tough well documented there it took me a while to understand why my projects were taking longer than expected during boot time and a way to work it around.

If you deploy micro services in a K8s cluster you may have seen variables similar to bellow ones when executing env command from inside a container:

V1_SERVICE_XPTO_SERVICE_HOST=172.20.232.70
V1_SERVICE_XPTO_PORT_8080_TCP_ADDR=172.20.232.70
V1_SERVICE_XPTO_PORT_8080_TCP=tcp://172.20.232.70:8080
V1_SERVICE_XPTO_SERVICE_PORT_HTTP=8080

A bunch of envs like above will be added for every deployment that belongs to the same cluster. You may have performance issues while deploying micronaut apps in a large k8s cluster because of how it handle env variables composed by many underscores. It will also consume more memory to index many combinations that were completely useless for my use cases.

I have solved this problem by creating a custom PropertySource that skips the garbage produced by k8s:

public class MicronautEnvPropertySource extends MapPropertySource {

    public static final MicronautEnvPropertySource INSTANCE = new MicronautEnvPropertySource();

    private MicronautEnvPropertySource() {
        super("filtered-envs", filter(System.getenv()));
    }

    @Override
    public PropertyConvention getConvention() {
        return ENVIRONMENT_VARIABLE;
    }

    @VisibleForTesting
    static final Map<String, String> filter(Map<String, String> envs) {

        var props = new HashMap<String, String>();

        for (var entry : envs.entrySet()) {
            // Filter out K8S boilerplate envs due to how micronaut resolve envs.
            // https://docs.micronaut.io/latest/guide/index.html#propertySource
            if (!entry.getKey().endsWith("80_TCP")
                    && !entry.getKey().endsWith("_TCP_PORT")
                    && !entry.getKey().endsWith("_TCP_PROTO")
                    && !entry.getKey().endsWith("_TCP_ADDR")
                    && !entry.getKey().endsWith("_UDP_PORT")
                    && !entry.getKey().endsWith("_UDP_PROTO")
                    && !entry.getKey().endsWith("_UDP_ADDR")
                    && !entry.getKey().endsWith("_SERVICE_PORT")
                    && !entry.getKey().endsWith("_SERVICE_PORT_HTTP")
                    && !entry.getKey().endsWith("_SERVICE_HOST")
                    && (!entry.getKey().endsWith("_PORT") && !entry.getValue().startsWith("tcp://"))
            ) {
                props.put(entry.getKey(), entry.getValue());
            }
        }

        return props;
    }
}

Next step is to disable built in env property source and plug the new one:

Micronaut.build(args)
     .mainClass(Application.class)
     .environmentPropertySource(false)
     .propertySources(MicronautEnvPropertySource.INSTANCE)
     .start();

I have opened this issue so we can discuss if there is a better way to have this problem solved. If there is no other way than whoever is suffering from the same issue can benefit from the work around explained above. Please note that environmentVariableIncludes and environmentVariableExcludes didn't work for me because the patterns I have are related to sufixes and I don't know all variable names in advance.

Feature Request: Service Discovery across multiple namespaces

From my understanding the discovery client only discovers services within the single namespace that's configured, either by default value or explicitly setting the config. We have a use case where we would need service discovery across multiple namespaces. For example:

FooService named foo running in namespace A
BarService named bar running in namespace A
BazService named baz running in namespace B

From FooService we want to use a @Client("${bar.clientid:bar}") BarClient to call BarService and @Client("${baz.clientid:baz}") BazClient to call BazService.

Is this something can could be achieved solely by extending the kubernetes discovery client or would it require some underlying changes in the kubernetes cluster?

Manual service configuration not read from boostrap.yml

I'm trying to configure service discovery in kubernetes for a GRPC service.
The service I'm trying to discover is a multi-port service and is therefore in need of manual service confguration.
However, I cannot get micronaut to pick-up my service config.

I have followed the guide available here

This is what my boostrap.yml looks like

kubernetes:
  client:
    discovery:
      includes:
        - foo-service
      services:
        - foo-service:
            port: grpc
            mode: endpoint
    config-maps:
      watch: false

But nonetheless I'm seeing the following errors in the logs,

"Fetching Endpoints KubernetesServiceConfiguration{serviceId='foo-service', name='foo-service', namespace='default', mode='endpoint', port='null', manual=false}
"The resource [foo-service] has multiple ports declared [grpc,http] if you want to to use it in micronaut you have to configure it manually.

Am I doing something wrong here or is there some issue in micronaut itself?
Any help is appreciated, thank you for your awesome work with micronaut.

Environment Information

  • **Operating System: Docker(adoptopenjdk/openjdk11:jdk-11.0.11_9-slim)
  • **Micronaut Version: 2.5.3
  • **JDK Version: 11

Question: GraalVM and Kubernetes

What is relation is to be between GraalVM and Kubernetes?

Graal is JVM based with runtime images just jar file.
While Kubernetes has been container managing runtime, starting as docker alternative.

It seems to me that they are offerings from different vendors: Oraclle and Google,
and maybe will not always work well together, if backing companies relation deteriorates again.

Enable config option for KubernetesConfigMapWatcher

We have a CI/CD Jenkins Pipeline that runs the build and test tasks on an OpenShift pod. This pod does not have the access rights to list the configMaps. It would be great to disable the ConfigMapWatcher.
So we can get rid off these exceptions in the Unit Tests:

 13:20:50.441 [nioEventLoopGroup-3-3] ERROR i.m.k.c.KubernetesConfigMapWatcher - Error while watching ConfigMap events
    io.micronaut.http.client.exceptions.HttpClientResponseException: Forbidden

Using Micronaut as an Operator framework

Although Quarkus and CDI is a great option for building operators on Kubernetes, I would really like to see an Operator framework for Micronaut that would enable a developer to implement an Operator to control their application(s) using the same framework they build their service layer with.

To be clear: this is not proposing a framework to allow applications to integrate with Kubernetes like with service discovery but to integrate an Operator with the Kubernetes environment like managing custom resources, being notified of changes via watches, creating new resources with a cluster based on templated specs, etc... All those things an Operator typically does by just creating a client (e.g. Fabric8) and manipulating the cluster manually. We have built an Operator on Quarkus and I think there are some meaningful abstractions that could be extracted into a reusable Micronaut component that would make writing Operators using Micronaut really, really easy.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.