Kubernetes 云日志认证问题

Kubernetes Cloud Logging Authentication Issue

我一直在尝试将我的应用程序切换为使用 Google 云日志记录(又名 Stackdriver)。我已经构建了一个使用 Google Java 云日志库的自定义 Logback appender。

当我 运行 我的应用程序在 IDE 中时,它会正确记录到 Google Cloud Logging。当我 运行 它在 GKE 上的 Kubernetes 容器中时,我收到身份验证错误。但是,在这两种情况下,我都使用相同的 GCP 服务帐户。

我什至从 Google 凭据对象输出密钥来证明它们在每个环境中都是相同的。他们是。

有人知道我可能遗漏了什么吗?是否有任何类型的上下文相关设置可能导致身份验证从容器内部失败?有人知道接下来要尝试什么吗?


更新: 这是堆栈跟踪:

java.lang.RuntimeException: java.util.concurrent.ExecutionException: com.google.cloud.logging.LoggingException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: 凭据应该使用 fail() 而不是在 java.lang.RuntimeException 处抛出异常:java.util.concurrent.ExecutionException: com.google.cloud.logging.LoggingException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: 凭证应该使用 fail() 而不是在 com.google.cloud.logging.LoggingImpl.flush(LoggingImpl.java:579) 在 [=60= 处抛出异常](LoggingImpl.java:560) 在 uk.co.processflows.platform.util.StackdriverAppender.append(StackdriverAppender.kt:135) 在 uk.co.processflows.platform.util.StackdriverAppender.append(StackdriverAppender.kt:18) 在 ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend( UnsynchronizedAppenderBase.java:84) 在 ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51) 在 ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:270) 在 ch.qos.logback.classic.Logger.callAppenders(Logger.java:257) 在 ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:421) 在 ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383) 在 ch.qos.logback.classic.Logger.error(Logger.java:538) 在 uk.co.processflows.platform.pushnotification.PushNotificationClient.forward(PushNotificationClient.kt:58) 在 uk.co.processflows.platform.push.PushMessagingConnectionHandlerImpl.broadcast(PushMessagingConnectionHandlerImpl.kt:257) 在 uk.co.processflows.platform.push.PushMessagingConnectionHandlerImpl.broadcastMessageToTenant(PushMessagingConnectionHandlerImpl.kt:153) 在 java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 java.base/jdk。 internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.base/java.lang.reflect.Method.invoke(Method.java:567) 在 com.google.inject.internal.DelegatingInvocationHandler.invoke(DelegatingInvocationHandler.java:50) 在 com.sun.proxy.$Proxy69.broadcastMessageToTenant(未知来源)在 uk.co.processflows.platform.workflow.TaskLockControllerImpl$lockTask$2.run(TaskLockControllerImpl.kt:94) 在 java.base/java.util.concurrent.Executors$ RunnableAdapter.call(Executors.java:515) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java。 base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:835) 原因:java.util.concurrent.ExecutionException: com.google.cloud.logging.LoggingException: io.grpc.StatusRuntimeException: 未经验证:凭据应使用 fail( ) 而不是在 com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:552) 在 com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:431) 在 com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get 抛出异常(AbstractFuture.java:97) 在 com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:68) 在 com.google.cloud.logging.LoggingImpl.flush(LoggingImpl.java:577) 在 ... 省略了 25 个公共帧by: com.google.cloud.logging.LoggingException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: 凭证应该使用 fail() 而不是在 com.google.cloud.logging.spi.v2.GrpcLoggingRpc$2.apply(GrpcLoggingRpc.java:190) 在 com.google.cloud.logging.spi.v2.GrpcLoggingRpc$2.apply(GrpcLoggingRpc.java:184) 在 com.google.api.core.ApiFutures$GaxFunctionToGuavaFunction.apply(ApiFutures.java:204) 在 com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:206) 在 com.google.common.util.concurrent.AbstractCatchingFuture$CatchingFuture.doFallback(AbstractCatchingFuture.java:194) 在com.google.common.util.concurrent.AbstractCatchingFuture.运行(AbstractCatchingFuture.java:107) 在 com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30) 在 com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1138) 在 com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:958) 在 com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:748) 在 com.google.api.core.AbstractApiFuture$InternalSettableFuture.setException(AbstractApiFuture.java:95) 在 com.google.api.core.AbstractApiFuture.setException(AbstractApiFuture.java:77) 在 com.google.api.gax.rpc.BatchedFuture.setException(BatchedFuture.java:55) 在 com.google.api.gax.rpc.BatchedRequestIssuer.sendResult(BatchedRequestIssuer.java:84) 在com.google.api.gax.rpc.BatchExecutor$1.onFailure(BatchExecutor.java:98) 在 com.google.api.core.ApiFutures$1.onFailure(ApiFutures.java:68) 在 com.google.common.util.concurrent.Futures$ CallbackListener.run(Futures.java:1056) 在 com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30) 在 com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1138) 在com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:958) 在 com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:748) 在 com.google.api.gax.retrying.BasicRetryingFuture.handleAttempt(BasicRetryingFuture.java:179)在 com.google.api.gax.retrying.CallbackChainRetryingFuture$AttemptCompletionListener.handle(CallbackChainRetryingFuture.java:135) 在 com.google.api.gax.retrying.CallbackChainRetryingFuture$AttemptCompletionListener.run(CallbackChainRetryingFuture.java:117) 在 com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30) 在 com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1138) 在 com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:958) 在 com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:748) 在 com.google.api.core.AbstractApiFuture$InternalSettableFuture.setException(AbstractApiFuture.java:95) 在 com.google.api.core.AbstractApiFuture.setException(AbstractApiFuture.java:77) 在 com.google.api.gax.grpc.GrpcExceptionCallable$ExceptionTransformingFuture.onFailure(GrpcExceptionCallable.java:97) 在 com.google.api.core.ApiFutures$1.onFailure(ApiFutures.java:68) 在com.google.common.util.concurrent.Futures$CallbackListener.run(Futures.java:1056) 在 com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30) 在 com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1138) 在 com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:958) 在 com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:748) 在 io.grpc.stub.ClientCalls$GrpcFuture.setException(ClientCalls.java:515) 在 io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:490) 在 io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)在 io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) 在 io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) 在 io.grpc.internal.CensusStatsModule$StatsClientIntercept或 $1$1.onClose(CensusStatsModule.java:699) 在 io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39) 在 io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) 在在 io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) 在 io.grpc.internal.CensusTracingModule$TracingClientInterceptor$1$1.onClose(CensusTracingModule.java:397) 在 io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:459) 在 io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:63) 在 io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:546 ) 在 io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$600(ClientCallImpl.java:467) 在 io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:584) 在io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) 在 io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) 在 java.base/java.util.concurrent.Executors$ RunnableAdapter.call(Executors.java:515) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java。 base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at ... 省略了 3 个公共帧 Caused by: com.google.api.gax.rpc.UnauthenticatedException: io.grpc.StatusRuntimeException: UNAUTHENTICATED:凭证应该使用 fail() 而不是在 com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:73) 在 com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:72) 在 com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:60) at ... 省略了 30 个公共帧 Caused by: io.grpc.StatusRuntimeException: UNAUTHENTICATED: Credentials should use fail() 而不是在 io.grpc.Status.asRuntimeException(Status.java:532) at ... 省略了 22 个公共帧 Caused by: java.lang.NoSuchMethodError: io.grpc.MethodDescriptor.getServiceName()Ljava/lang/String;在 io.grpc.auth.GoogleAuthLibraryCallCredentials.serviceUri(GoogleAuthLibraryCallCredentials.java:162) 在 io.grpc.auth.GoogleAuthLibraryCallCredentials.applyRequestMetadata(GoogleAuthLibraryCallCredentials.java:103) 在 io.grpc.CallCredentials2.applyRequestMetadata(CallCredentials2.java:58) 在 io.grpc.internal.CallCredentialsApplyingTransportFactory$CallCredentialsApplyingTransport.newStream(CallCredentialsApplyingTransportFactory.java:107) 在 io.grpc.internal.ForwardingConnectionClientTransport.newStream(ForwardingConnectionClientTransport.java:49) 在 io.grpc.internal.InternalSubchannel$CallTracingTransport.newStream(InternalSubchannel.java:690) 在 io.grpc.internal.ClientCallImpl.start(ClientCallImpl.java:245) 在io.grpc.internal.CensusTracingModule$TracingClientInterceptor$1.start(CensusTracingModule.java:392) 在 io.grpc.internal.CensusStatsModule$StatsClientInterceptor$1.start(CensusStatsModule.java:694) 在 io.grpc.ForwardingClientCall.start(ForwardingClientCall.java:32) 在 com.google.api.gax.grpc.GrpcHeaderInterceptor$1.start(GrpcHeaderInterceptor.java:94) 在 io.grpc.stub.ClientCalls.startCall(ClientCalls.java:310) 在 io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:282) 在 io.grpc.stub.ClientCalls.futureUnaryCall(ClientCalls.java:191) 在 com.google.api.gax.grpc.GrpcDirectCallable.futureCall( GrpcDirectCallable.java:58) 在 com.google.api.gax.grpc.GrpcExceptionCallable.futureCall(GrpcExceptionCallable.java:64) 在 com.google.api.gax.rpc.AttemptCallable.call(AttemptCallable.java:86) 在 com.google.api.gax.rpc.RetryingCallable.futureCall( RetryingCallable.java:63) 在 com.google.api.gax.rpc.RetryingCallable.futureCall(RetryingCallable.java:41) 在 com.google.api.gax.tracing.TracedBatchingCallable.futureCall(TracedBatchingCallable.java:82) 在 com.google.api.gax.rpc.UnaryCallable$1.futureCall(UnaryCallable.java:126) 在 com.google.api.gax.rpc.UnaryCallable.futureCall(UnaryCallable.java:87) 在 com.google.api.gax.rpc.BatchExecutor.processBatch(BatchExecutor.java:82) 在[=1 64=].processBatch(BatchExecutor.java:53) 在 com.google.api.gax.batching.ThresholdBatcher.pushCurrentBatch(ThresholdBatcher.java:233) 在 com.google.api.gax.batching.ThresholdBatcher$1.run(ThresholdBatcher.java: 76) 在 ... 省略了 6 个公共帧


更新二:

我刚刚在堆栈跟踪的层次结构的深处发现了这条消息。

原因:java.lang.NoSuchMethodError:io.grpc.MethodDescriptor.getServiceName()Ljava/lang/String;在 io.grpc.auth.GoogleAuthLibraryCallCredentials.serviceUri(GoogleAuthLibraryCallCredentials.java:162)

这听起来不像是身份验证问题。

更新 我最初回答这个问题时没有看到堆栈跟踪,这让我相信您的问题根本不在于身份验证。我的回答可能与那些在 GKE 中看到 GCP API 的身份验证问题有关,所以我会把原文留在这里。

原文 如果您遇到身份验证错误,可能是您没有正确使用服务帐户密钥。您可以阅读此 tutorial 以了解应该如何完成。简而言之,您需要将服务帐户密钥导出为 JSON 文件并将其挂载为机密。

考虑到您在使用该库时遇到的问题,您可能希望直接写入您的日志。关于创建结构化日志的 doc 可能会有帮助。

事实证明 GRPC jar 存在依赖兼容性问题。我们的应用程序使用 GRPC,显然 Google Could Logging 库也是如此。更改我们的应用程序以使用旧版本的 GRPC,Google 云日志库是针对该问题构建的。

当容器中的 运行 jar 文件以不同于本地 运行 的顺序加载时出现。这就是为什么这只发生在 Kubernetes 内部。