공부/프로그래밍

[springboot] aws sdk 에러(SdkClientException: Failed to connect to service endpoint) 안띄우기

demonic_ 2021. 2. 19. 08:00

aws에 사용하는 애플리케이션을 연동해야할때 spring-cloud-start-aws 의 패키지를 쓰는 편인데, build.gradle을 설정하고 앱을 실행하면 다음 에러가 보인다.

com.amazonaws.SdkClientException: Failed to connect to service endpoint: 
	at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:100) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:70) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.readResource(InstanceMetadataServiceResourceFetcher.java:75) ~[aws-java-sdk-core-1.11.792.jar:na]
...
Caused by: java.net.SocketTimeoutException: connect timed out
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:na]

 

사실 넘어갈 수 있는 에러긴 한데, timed out 하는동안 다음 프로세스를 진행하지 못하기 때문에 몇초아니지만 계속 거슬렸다. 그래서 해당 부분을 검토하는 로직을 꺼두는게 목적이다.

 

단순히 로그를 안보이게 하는거라면 다음 옵션을 application.properties에 추가하면 된다.

logging.level.com.amazonaws.util.EC2MetadataUtils: error

 

 

그러나 이 방법은 로그를 안보이게 할 뿐 딜레이 되는건 여전하다.

 

그럼 시작.

 

 

해당 오류는 InstanceMetadataServiceResourceFetcher 클래스의 readResource를 호출하면서 발생한 에러다. 서비스의 endpoint를 연결하지 못해 발생하는 에러인데, 이건 EC2의 메타데이터를 읽다가 발생하는 에러로써, EC2인스턴스가 아닌 곳에서는 의미가 없는 에러다.

 

InstanceMetadataServiceResourceFetcher 내부를 보면 다음 부분이 있다

@SdkInternalApi
public final class InstanceMetadataServiceResourceFetcher extends EC2ResourceFetcher {
...
    @Override
    public String readResource(URI endpoint, CredentialsEndpointRetryPolicy retryPolicy, Map<String, String> headers) {
        if (SDKGlobalConfiguration.isEc2MetadataDisabled()) {
            throw new AmazonClientException("EC2 Instance Metadata Service is disabled");
        }

        Map<String, String> newHeaders = addDefaultHeaders(headers);
        String token = getToken();

        if (token != null) {
            newHeaders.put(TOKEN_HEADER, token);
        }

        return doReadResource(endpoint, retryPolicy, newHeaders);
    }
...

 

코드에서 SDKGlobalConfiguration.isEc2MetadataDisabled() 부분이 있는데, 즉 Disable을 할 수 있다면 AmazonClientException("EC2 Instance Metadata Service is disabled"); 을 던지고 더이상 진행하지 않을 것이다.

 

그럼 그 옵션은 어떻게 주면 될까? 따라올라가면 다음이 있다

public class SDKGlobalConfiguration {
...
    public static final String AWS_EC2_METADATA_DISABLED_SYSTEM_PROPERTY = "com.amazonaws.sdk.disableEc2Metadata";
...
    public static boolean isEc2MetadataDisabled() {
        return isPropertyTrue(System.getProperty(AWS_EC2_METADATA_DISABLED_SYSTEM_PROPERTY)) ||
               isPropertyTrue(System.getenv(AWS_EC2_METADATA_DISABLED_ENV_VAR));
    }
...

 

AWS_EC2_METADATA_DISABLED_SYSTEM_PROPERTY 를 끄면(false) 된다는 것을 알 수 있다.

 

그럼 이걸 어떻게 꺼야할까?

흔히 옵션을 설정할때 쓰는 application.properties에 이 설정을 넣을 순 없다. 이걸 실행하는 순서가 application.properties를 읽기 전, 그러니까 환경변수에 따라가기 때문이다.

 

그럼 어떻게 해야할까? 첫번째는 VM options에 다음을 추가하면 된다.

-Dcom.amazonaws.sdk.disableEc2Metadata=true

 

Intellij는 다음처럼 설정하고 실행하면 된다.

 

이클립스의 경우 Open launch configuration => VM Arguments 에 추가한다.

 

그럼 이제 설정한대로 수행해보자.

om.amazonaws.AmazonClientException: EC2 Instance Metadata Service is disabled
	at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.readResource(InstanceMetadataServiceResourceFetcher.java:65) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.EC2ResourceFetcher.readResource(EC2ResourceFetcher.java:66) ~[aws-java-sdk-core-1.11.792.jar:na]

 

의도한대로 "EC2 Instance Metadata Service is disabled" 를 볼 수 있다.

 

 

마지막으로 테스트를 작성때 방법이다.

static으로 System Property를 지정하면 된다.

@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
class CustomUserDetailsServiceTest {
    static {
        System.setProperty("com.amazonaws.sdk.disableEc2Metadata", "true");
    }
...

 

 

끝.