Docker容器中GoogleCredential.GetApplicationDefault无报错超时,如何排查?
我在Compute Instance的Docker容器中运行.NET应用,尝试调用另一个Compute Instance。已将凭据文件credentials.json放在容器内,且设置了GOOGLE_APPLICATION_CREDENTIALS环境变量指向该文件。
执行代码时,在GoogleCredential.GetApplicationDefault()处超时,既无错误抛出,也没有任何超时原因提示。本地运行时曾遇到类似问题,通过反编译Google.Apis.Auth.OAuth2库并断点调试解决了凭据文件相关问题,但容器内无法这么做,没法诊断问题。
精简后的代码
public class TextToVectorService : ITextToVectorService { private readonly string audience = "<DESTINATION_PRIVATE_CLOUDRUN_URL>"; // e.g. "https://text-to-vector-fs4g3759-ts.a.run.app" private readonly IMyLogger _logger; private readonly Lazy<Task<OidcToken>> _token; // ... public TextToVectorService(IMyLogger logger) { _logger = logger; _token = new Lazy<Task<OidcToken>>(async () => { try { _logger.LogMessage("Beginning token generation"); var credential = GoogleCredential.GetApplicationDefault(); // <--- 超时位置 _logger.LogMessage("Got credential"); var tokenOptions = OidcTokenOptions.FromTargetAudience(audience) .WithTokenFormat(OidcTokenFormat.Standard); _logger.LogMessage($"Got credential type {credential.UnderlyingCredential.GetType().Name}"); var oidcToken = await credential.GetOidcTokenAsync(tokenOptions).ConfigureAwait(false); return oidcToken; } catch (Exception e) { _logger.LogError(e); throw; } }); } public async Task<IEnumerable<float>> EncodeText(string text) { _logger.LogMessage("Very start of Service call"); // 设置API调用... try { _logger.LogMessage("Getting auth"); var authHeader = await GenerateAuthHeader(); _logger.LogMessage("Starting to make API call"); // 永远到不了这里 // 发起API调用,返回结果... } catch (Exception e) { _logger.LogError(e); return Array.Empty<float>(); } } private async Task<AuthenticationHeaderValue> GenerateAuthHeader() { var tokenValue = await _token.Value; var token = await tokenValue.GetAccessTokenAsync().ConfigureAwait(false); // 永远到不了这里 _logger.LogMessage($"Got token: {token}"); return new AuthenticationHeaderValue("bearer", token); } }
日志输出
2023-04-19T14:08:16.441 message Very start of Service call 2023-04-19T14:08:16.441 message Getting auth 2023-04-19T14:08:16.441 message Beginning token generation
没有其他日志输出,也没有抛出错误,随后请求超时。请问该如何获取更多问题相关信息?
以下是几种能获取更多诊断信息的实用方法:
启用Google客户端库详细日志
在应用启动时添加配置,开启Google.Apis相关组件的调试日志,捕获凭据获取过程中的底层请求细节:using Google.Apis.Logging; // 应用初始化阶段添加 var logger = new ConsoleLogger(LogLevel.Debug); Google.Apis.Logging.Logger.SetLogger(logger);也可以通过
appsettings.json配置日志级别,将Google.Apis相关日志设为Debug或Trace,查看库内部的请求、重试等细节。手动加载凭据并添加前置检查
不要依赖自动加载,改为手动读取凭据文件,同时添加文件存在性、权限检查的日志:var credPath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"); _logger.LogMessage($"凭据文件路径:{credPath}"); _logger.LogMessage($"文件是否存在:{File.Exists(credPath)}"); if (File.Exists(credPath)) { var fileInfo = new FileInfo(credPath); _logger.LogMessage($"文件权限:{fileInfo.GetAccessControl()}"); } // 手动加载凭据 var credential = GoogleCredential.FromFile(credPath);先确认容器能否正常读取凭据文件,排除路径或权限问题。
添加超时控制强制触发异常
给凭据获取操作加上超时包装,触发超时异常并捕获上下文:var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); try { var credentialTask = Task.Run(() => GoogleCredential.GetApplicationDefault(), cts.Token); var credential = await credentialTask.WaitAsync(cts.Token).ConfigureAwait(false); } catch (OperationCanceledException ex) { _logger.LogError($"凭据获取超时:{ex.Message}\n堆栈信息:{ex.StackTrace}"); throw; }容器内测试网络连通性
进入运行中的Docker容器,测试关键端点的连通性:# 测试元数据服务(使用Compute Instance默认服务账号时需要) curl -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token # 测试OAuth2令牌端点 curl https://oauth2.googleapis.com/token若网络不通,说明容器存在网络配置问题,比如防火墙规则、VPC peering限制等。
验证容器环境与文件挂载
在容器内执行以下命令,确认环境变量和凭据文件状态:echo $GOOGLE_APPLICATION_CREDENTIALS cat $GOOGLE_APPLICATION_CREDENTIALS检查环境变量是否正确,文件内容是否完整无格式错误。
内容的提问来源于stack exchange,提问作者pjpscriv

