gRPC over TLS 使用 Netty/Kortlin/Ktor 引发错误并阻止 gNMI 工作

Posted

技术标签:

【中文标题】gRPC over TLS 使用 Netty/Kortlin/Ktor 引发错误并阻止 gNMI 工作【英文标题】:gRPC over TLS using Netty/Kortlin/Ktor raises error and prevents gNMI to work 【发布时间】:2019-04-13 06:17:40 【问题描述】:

目前正在使用 gRPC/gNMI + Kotlin 和 Ktor HTTP 开发一个模块。 卡在安全的依赖库 tc-native netty-tcnative-boringssl-static 2.0.19-Final

Ktor 在 1.0.0-beta3 中

  // ktor
    implementation "io.ktor:ktor-server-core:$ktor_version"
    implementation "io.ktor:ktor-server-netty:$ktor_version"
    implementation "io.ktor:ktor-html-builder:$ktor_version"
    implementation "io.ktor:ktor-gson:$ktor_version"
    implementation "io.ktor:ktor-metrics:$ktor_version"
    implementation "io.ktor:ktor-locations:$ktor_version"
    implementation "ch.qos.logback:logback-classic:$logback_version"

    // tpl
    implementation "io.ktor:ktor-freemarker:$ktor_version"
    implementation "org.freemarker:freemarker:$freemarker_version"

    // Security
    //implementation "io.netty:netty-tcnative:$netty_tcnative_version"
    implementation "io.netty:netty-tcnative-boringssl-static:$netty_tcnative_version".

使用 gRPC 请求时

fun Route.routeFilesystem() 
get("/test") 
    call.respondHtml 
        head 
            title  +"gRPC/gNMI" 
        
        body 
            p 
                +"[ Capabilities Test ] "
                TLSConnection("xxx.xxx.xxx.xxx",8448).capabilities()
            
        
    

它给出以下错误(堆栈跟踪):

[DEBUG] 2018-11-09 16:50:36.789 [nettyCallPool-4-4] DEBUG i.n.u.internal.NativeLibraryLoader - netty_tcnative_linux_x86_64 cannot be loaded from java.libary.path, now trying export to -Dio.netty.native.workdir: /tmp
java.lang.UnsatisfiedLinkError: no netty_tcnative_linux_x86_64 in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38)
        at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:243)
        at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:124)
        at io.netty.util.internal.NativeLibraryLoader.loadFirstAvailable(NativeLibraryLoader.java:85)
        at io.netty.handler.ssl.OpenSsl.loadTcNative(OpenSsl.java:440)
        at io.netty.handler.ssl.OpenSsl.<clinit>(OpenSsl.java:97)
        at io.grpc.netty.GrpcSslContexts.defaultSslProvider(GrpcSslContexts.java:244)
        at io.grpc.netty.GrpcSslContexts.configure(GrpcSslContexts.java:171)
        at io.grpc.netty.GrpcSslContexts.forClient(GrpcSslContexts.java:120)
        at sdn.client.cli.console.TLSConnection.<init>(TLSConnection.kt:38)
        at sdn.client.ui.ApplicationKt$routeFilesystem$1$1$2$1.invoke(Application.kt:125)
        at sdn.client.ui.ApplicationKt$routeFilesystem$1$1$2$1.invoke(Application.kt)
        at kotlinx.html.ApiKt.visit(api.kt:80)
        at kotlinx.html.Gen_tag_groupsKt.p(gen-tag-groups.kt:125)
        at kotlinx.html.Gen_tag_groupsKt.p$default(gen-tag-groups.kt:125)
        at .sdn.client.ui.ApplicationKt$routeFilesystem$1$1$2.invoke(Application.kt:123)
        at .sdn.client.ui.ApplicationKt$routeFilesystem$1$1$2.invoke(Application.kt)
        at kotlinx.html.ApiKt.visit(api.kt:80)
        at kotlinx.html.Gen_tags_hKt.body(gen-tags-h.kt:164)
        at kotlinx.html.Gen_tags_hKt.body$default(gen-tags-h.kt:164)
        at .sdn.client.ui.ApplicationKt$routeFilesystem$1$1.invoke(Application.kt:122)
        at sdn.client.ui.ApplicationKt$routeFilesystem$1$1.invoke(Application.kt)
        at kotlinx.html.ApiKt.visit(api.kt:80)
        at kotlinx.html.ApiKt.visitAndFinalize(api.kt:93)
        at kotlinx.html.Gen_consumer_tagsKt.html(gen-consumer-tags.kt:317)
        at kotlinx.html.Gen_consumer_tagsKt.html$default(gen-consumer-tags.kt:317)
        at io.ktor.html.HtmlContent.writeTo(RespondHtml.kt:32)
        at io.ktor.server.engine.BaseApplicationResponse$respondWriteChannelContent$2.invokeSuspend(BaseApplicationResponse.kt:155)
        at io.ktor.server.engine.BaseApplicationResponse$respondWriteChannelContent$2.invoke(BaseApplicationResponse.kt)
        at io.ktor.util.cio.ReadersKt.use(Readers.kt:33)
        at io.ktor.server.engine.BaseApplicationResponse.respondWriteChannelContent$suspendImpl(BaseApplicationResponse.kt:149)
        at io.ktor.server.engine.BaseApplicationResponse.respondWriteChannelContent(BaseApplicationResponse.kt)
        at io.ktor.server.engine.BaseApplicationResponse.respondOutgoingContent$suspendImpl(BaseApplicationResponse.kt:119)
        at io.ktor.server.engine.BaseApplicationResponse.respondOutgoingContent(BaseApplicationResponse.kt)
        at io.ktor.server.netty.NettyApplicationResponse.respondOutgoingContent$suspendImpl(NettyApplicationResponse.kt:37)
        at io.ktor.server.netty.NettyApplicationResponse.respondOutgoingContent(NettyApplicationResponse.kt)
        at io.ktor.server.engine.BaseApplicationResponse$$special$$inlined$apply$lambda$1.invokeSuspend(BaseApplicationResponse.kt:36)
        at io.ktor.server.engine.BaseApplicationResponse$$special$$inlined$apply$lambda$1.invoke(BaseApplicationResponse.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.util.pipeline.PipelineContext.proceedWith(PipelineContext.kt:39)
        at io.ktor.server.engine.DefaultTransformKt$installDefaultTransformations$1.invokeSuspend(DefaultTransform.kt:26)
        at io.ktor.server.engine.DefaultTransformKt$installDefaultTransformations$1.invoke(DefaultTransform.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
        at io.ktor.html.RespondHtmlKt.respondHtml(RespondHtml.kt:37)
        at io.ktor.html.RespondHtmlKt.respondHtml$default(RespondHtml.kt:15)
        at sdn.client.ui.ApplicationKt$routeFilesystem$1.invokeSuspend(Application.kt:116)
        at .sdn.client.ui.ApplicationKt$routeFilesystem$1.invoke(Application.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
        at io.ktor.routing.Routing.executeResult(Routing.kt:110)
        at io.ktor.routing.Routing.interceptor(Routing.kt:29)
        at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:75)
        at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:60)
        at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.features.StatusPages$intercept$3.invokeSuspend(StatusPages.kt:88)
        at io.ktor.features.StatusPages$intercept$3.invoke(StatusPages.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:82)
        at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:162)
        at io.ktor.features.StatusPages.intercept(StatusPages.kt:87)
        at io.ktor.features.StatusPages$Feature$install$1.invokeSuspend(StatusPages.kt:121)
        at io.ktor.features.StatusPages$Feature$install$1.invoke(StatusPages.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.features.CallLogging$Feature$install$2.invokeSuspend(CallLogging.kt:124)
        at io.ktor.features.CallLogging$Feature$install$2.invoke(CallLogging.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:80)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
        at io.ktor.util.pipeline.PipelineContext.proceed(PipelineContext.kt:53)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:31)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:54)
        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:111)
        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:160)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:54)
        at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
        at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:22)
        at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:16)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:38)
        at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:353)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:464)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)
        Suppressed: java.lang.UnsatisfiedLinkError: no netty_tcnative_linux_x86_64 in java.library.path
                at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
                at java.lang.Runtime.loadLibrary0(Runtime.java:870)
                at java.lang.System.loadLibrary(System.java:1122)
                at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:498)
                at io.netty.util.internal.NativeLibraryLoader$1.run(NativeLibraryLoader.java:263)
                at java.security.AccessController.doPrivileged(Native Method)
                at io.netty.util.internal.NativeLibraryLoader.loadLibraryByHelper(NativeLibraryLoader.java:255)
                at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:233)
                ... 90 common frames omitted

请问有什么办法解决这个问题吗? 谢谢

【问题讨论】:

【参考方案1】:

见https://github.com/netty/netty-tcnative/issues/331

这是一个 DEBUG 级别的打印,这表明它可能不是一个实际的错误,只是 netty 尝试加载但未能加载的东西。加载boringssl .so 以后可能会成功。

【讨论】:

以上是关于gRPC over TLS 使用 Netty/Kortlin/Ktor 引发错误并阻止 gNMI 工作的主要内容,如果未能解决你的问题,请参考以下文章

Akka-CQRS(10)- gRPC on SSL/TLS 安全连接

Android grpc 错误:TLS ALPN 协商失败,协议:[grpc-exp,h2]

Kong 1.3发布,原生gRPC代理上游TLS交叉认证

为 SSL / TLS 配置 Proton 引发 openssl 错误版本号和 gRPC 客户端错误

续:Grpc over http2 PK WebApi over http2

mqtt使用WebSocket over TLS(wss)握手失败