AWS XRay SDK не может прочитать переменные среды в контейнере докеров

AWS XRay - это сервис трассировки, который позволяет отслеживать запросы в распределенных системах и даже профилировать ваши сервисы. Не вдаваясь в подробности того, как работает XRay, он в основном отслеживает ваш сервис и отправляет данные о каждом запросе к сервису через UDP демону, который собирает эти данные и отправляет их в AWS.

Этот демон, когда он запущен локально или в EC2, является локальным по отношению к машине, на которой запущена служба, и доступен через порт 2000. Это конфигурация по умолчанию для расположения хоста демона.

При работе в Kubernetes вам необходимо настроить демон для работы на каждом узле. Согласно документации по настройке XRay с Kubernetes, вы можете переопределить значение по умолчанию, установив переменную среды AWS_XRAY_DAEMON_ADDRESS с требуемым хостом, или вы можете установить системную переменную JVM com.amazonaws.xray.emitters.daemonAddress. Также имеется ссылка на это в SDK. документация.

Из-за моего варианта использования и того, как мы делимся конфигурациями в моей организации, я хотел бы использовать метод установки переменной среды.

Согласно документации, мы устанавливаем его при развертывании с помощью наших диаграмм управления:

env:
  - name: AWS_XRAY_DAEMON_ADDRESS
    value: aws-xray-daemon.default

Выполнив выполнение в модуле, в котором запущена служба, и запустив printenv, мы видим, что это значение успешно установлено при развертывании.


Проблема:

Когда XRay пытается профилировать и отправлять данные демону, выдается SdkClientException:

com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to 127.0.0.1:2000 [/127.0.0.1] failed: Connection refused (Connection refused)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleRetryableException(AmazonHttpClient.java:1201) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1147) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:796) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:764) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:738) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:698) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:680) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:544) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:524) ~[aws-java-sdk-core-1.11.739.jar!/:na]
        at com.amazonaws.services.xray.AWSXRayClient.doInvoke(AWSXRayClient.java:1607) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
        at com.amazonaws.services.xray.AWSXRayClient.invoke(AWSXRayClient.java:1574) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
        at com.amazonaws.services.xray.AWSXRayClient.invoke(AWSXRayClient.java:1563) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
        at com.amazonaws.services.xray.AWSXRayClient.executeGetSamplingRules(AWSXRayClient.java:800) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
        at com.amazonaws.services.xray.AWSXRayClient.getSamplingRules(AWSXRayClient.java:771) ~[aws-java-sdk-xray-1.11.739.jar!/:na]
        at com.amazonaws.xray.strategy.sampling.pollers.RulePoller.pollRule(RulePoller.java:65) ~[aws-xray-recorder-sdk-core-2.4.0.jar!/:na]
        at com.amazonaws.xray.strategy.sampling.pollers.RulePoller.lambda$start$0(RulePoller.java:46) ~[aws-xray-recorder-sdk-core-2.4.0.jar!/:na]
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[na:na]
        at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source) ~[na:na]
        at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) ~[na:na]
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na]
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:na]
        at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
        ...

Это означает, что AWS SDK не использует эту переменную среды, как указано в документации, а просто использует значение по умолчанию 127.0.0.1:2000.

Затем я покопался в коде SDK, чтобы узнать, как он извлекает эту переменную, и обнаружил, что код, который ее запускает, использует System.getenv("AWS_XRAY_DAEMON_ADDRESS"), как показано ниже:

    /**
     * Environment variable key used to override the address to which UDP packets will be emitted. Valid values are of the form `ip_address:port`. Takes precedence over any system property,
     * constructor value, or setter value used.
     */
    public static final String DAEMON_ADDRESS_ENVIRONMENT_VARIABLE_KEY = "AWS_XRAY_DAEMON_ADDRESS";

    /**
     * System property key used to override the address to which UDP packets will be emitted. Valid values are of the form `ip_address:port`. Takes precedence over any constructor or setter value
     * used.
     */
    public static final String DAEMON_ADDRESS_SYSTEM_PROPERTY_KEY = "com.amazonaws.xray.emitters.daemonAddress";

    public DaemonConfiguration() {
        String environmentAddress = System.getenv(DAEMON_ADDRESS_ENVIRONMENT_VARIABLE_KEY);
        String systemAddress = System.getProperty(DAEMON_ADDRESS_SYSTEM_PROPERTY_KEY);

        if (setUDPAndTCPAddress(environmentAddress)) {
            logger.info(String.format("Environment variable %s is set. Emitting to daemon on address %s.", DAEMON_ADDRESS_ENVIRONMENT_VARIABLE_KEY, getUDPAddress()));
        } else if (setUDPAndTCPAddress(systemAddress)) {
            logger.info(String.format("System property %s is set. Emitting to daemon on address %s.", DAEMON_ADDRESS_SYSTEM_PROPERTY_KEY, getUDPAddress()));
        }
    }

Я подумал, может, я неправильно установил переменную окружения? Поэтому я добавил журнал получения переменной среды при запуске службы и обнаружил, что JVM действительно может найти значение:

Код:

System.out.println("System.getenv(\"AWS_XRAY_DAEMON_ADDRESS\")" + " = " + System.getenv("AWS_XRAY_DAEMON_ADDRESS")) 

Вывод:

System.getenv("AWS_XRAY_DAEMON_ADDRESS") = aws-xray-daemon.default

Насколько я могу судить, этот код в точности соответствует тому, что должен запускаться AWS SDK, и тем не менее, кажется, что он никогда не запускается, и если это так, он не дает такого же результата, как то, что я тестировал с помощью своего журналы.

Работая локально, я не могу воспроизвести эту проблему, поскольку он выбирает хост, который я указал из переменных моей локальной среды. Я также подтвердил, что вставленный выше код AWS SDK достигается при локальном запуске с использованием точек останова.

Любые идеи?


Фрагмент Gradle:

ext {
    ...
    springCloudVersion = "Greenwich.RELEASE"
    awsCoreVersion = '1.11.739'
    awsXrayVersion = '2.4.0' 
    ...
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        mavenBom "com.amazonaws:aws-java-sdk-bom:${awsCoreVersion}"
        mavenBom "com.amazonaws:aws-xray-recorder-sdk-bom:${awsXrayVersion}"
    }
}

dependencies {
    ...

    implementation "com.amazonaws:aws-java-sdk-core"
    implementation "com.amazonaws:aws-xray-recorder-sdk-core" 
    implementation "com.amazonaws:aws-xray-recorder-sdk-aws-sdk" 
    implementation "com.amazonaws:aws-xray-recorder-sdk-spring" 
    implementation "com.amazonaws:aws-xray-recorder-sdk-apache-http" 
    implementation "com.amazonaws:aws-xray-recorder-sdk-sql-postgres" 

    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'

    ...

}

Другая информация:

  • Запуск в Spring Boot v2.2.1
  • OpenJDK v11.0.4
  • Gradle v6.0.1

Другие попытки: - Я попытался установить переменную среды через Dockerfile. Результат был тот же.


person J Hamm    schedule 10.03.2020    source источник


Ответы (1)


Оказалось, что в блоге Я связал нехороший пост в блоге. В примере они не указывают порт с хостом:

env:
- name: AWS_XRAY_DAEMON_ADDRESS 
  value: xray-service.default

Изменение переменной среды для включения порта устранило проблему:

env:
- name: AWS_XRAY_DAEMON_ADDRESS 
  value: xray-service.default:2000
person J Hamm    schedule 10.03.2020