Springboot、Micrometer 和 Aws Lambda 函数

Springboot, Micrometer and Aws Lambda function

我正在尝试使用千分尺将指标发送到 AWS cloudwatch,但是,我遇到了 AWS 凭据问题。

ERROR i.m.c.CloudWatchMeterRegistry - error sending metric data. 
com.amazonaws.SdkClientException: Unable to load AWS credentials from any provider in the chain: 
[com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper@b23c49d: Failed to connect to service endpoint: , com.amazonaws.auth.profile.ProfileCredentialsProvider@7edf67de: profile file cannot be null]
    at com.amazonaws.auth.AWSCredentialsProviderChain.getCredentials(AWSCredentialsProviderChain.java:136)r 
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.getCredentialsFromContext(AmazonHttpClient.java:1257)r   
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.runBeforeRequestHandlers(AmazonHttpClient.java:833)r 
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:783)r    
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770)r 
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744)r  
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access0(AmazonHttpClient.java:704)r   
    at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686)r  at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550)r  
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530)r  at com.amazonaws.services.cloudwatch.AmazonCloudWatchClient.doInvoke(AmazonCloudWatchClient.java:2587)r 
    at com.amazonaws.services.cloudwatch.AmazonCloudWatchClient.invoke(AmazonCloudWatchClient.java:2554)r   
    at com.amazonaws.services.cloudwatch.AmazonCloudWatchClient.invoke(AmazonCloudWatchClient.java:2543)r   
    at com.amazonaws.services.cloudwatch.AmazonCloudWatchClient.executePutMetricData(AmazonCloudWatchClient.java:2297)r 
    at com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClient.call(AmazonCloudWatchAsyncClient.java:1215)r    
    at com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClient.call(AmazonCloudWatchAsyncClient.java:1209)r    
    at java.base/java.util.concurrent.FutureTask.run(Unknown Source)r   
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)r at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)r    
    at java.base/java.lang.Thread.run(Unknown Source)r

AmazonHttpClient 正在尝试使用 EC2ContainerCredentialsProviderWrapperProfileCredentialsProvider 检索凭据,但在 lambda 环境中,凭据可通过执行角色获得,而且我们还有特定的环境变量,称为 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY.

那么,有什么方法可以告诉 Micrometer 使用不同的 AwsCredentials 提供商,例如 EnvironmentVariableCredentialsProvider

您是否尝试过使用 Configuration 文件为此更改 Bean

@Configuration
public class ManualAWSCredentialProviderConfiguration {
  @Value("${AWS_ACCESS_KEY_ID}")
  protected String accessKey;

  @Value("${AWS_SECRET_ACCESS_KEY}")
  protected String secretKey;

  @Bean
  @Primary
  public AWSCredentialsProvider buildAWSCredentialsProviderManually() {
    return new AWSStaticCredentialsProvider(
      new BasicAWSCredentials(accessKey, secretKey)
    );
  }
}

经过一些研究,我能够通过创建自定义 CloudWatchMeterRegistry bean 来发送指标,如下所示:

@Bean
@Primary
public CloudWatchMeterRegistry customCloudWatchMeterRegistry(
        CloudWatchConfig config, Clock clock, AwsRegionProperties awsRegionProperties) {

    AmazonCloudWatchAsync amazonCloudWatchAsync = AmazonCloudWatchAsyncClient
            .asyncBuilder()
            .withCredentials(new EnvironmentVariableCredentialsProvider())
            .withRegion(awsRegionProperties.getStatic())
            .build();

    return new CloudWatchMeterRegistry(config, clock, amazonCloudWatchAsync);
}

如您所见,现在我可以配置自定义凭据提供程序,在我的例子中是 EnvironmentVariableCredentialsProvider

重要提示: bean 的名称不应该是 cloudWatchMeterRegistry 因为这个 class org.springframework.cloud.aws.autoconfigure.metrics.CloudWatchExportAutoConfiguration 已经有一个声明的 bean那个名字。

当您将 aws-java-sdk-sts 添加到您的依赖项(并将其放在您的类路径中)时,将导致扩展的提供者链。然后应该使用执行角色。

对于行家:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-sts</artifactId>
    <version>1.12.52</version>
</dependency>

对于gradle:

implementation group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.12.52'