环境变量未能通过php-fpm和ECS传递。

huangapple go评论79阅读模式
英文:

Environment variables not getting passed through with php-fpm and ECS

问题

以下是您要翻译的内容:

我有一个任务定义,看起来像这样(为了可读性进行了截断)。我需要在PHP容器内动态获取可用的主机IP地址。这对Datadog的工作是必需的。

这是一个运行Symfony应用程序的容器,使用php-fpm。因此,我的entrypoint.sh看起来像这样:

#!/bin/sh

export TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
export DD_AGENT_HOST=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4)

echo "Datadog agent host: ${DD_AGENT_HOST}"

php-fpm -F

在CloudWatch日志中,echo调试打印出了正确的值。然而,在容器启动后登录并使用php -i检查环境变量时,变量不在其中。

我确保我的www.conf中有clear_env = no。但是没有成功。

这是我的Dockerfile,供参考:

# 多阶段构建。首先运行composer install,然后在第二个镜像中复制它
FROM composer:2 as vendor

WORKDIR "/app/platform"

COPY ["./app/composer.json", "./app/composer.lock*", "/app/platform/"]

RUN composer install --no-interaction --no-dev --prefer-dist --ignore-platform-reqs

FROM php:8.1-fpm-buster as platform

RUN \
    # Symfony需要对某些文件夹进行写访问。我们需要预生成这些文件夹
    mkdir -p "/app/platform/var" \
    && chmod 777 -R "/app/platform/var" \
    # 安装必要的二进制文件和软件包
    && apt-get update \
    && apt-get install -y gnupg g++ procps openssl git unzip zlib1g-dev libzip-dev libfreetype6-dev libpng-dev libjpeg-dev libicu-dev  libonig-dev libxslt1-dev acl libjpeg62-turbo-dev libmcrypt-dev zip vim \
    # 安装php扩展
    #&& pecl install redis \
    #&& docker-php-ext-enable redis \
    && docker-php-ext-install pdo pdo_mysql zip xsl gd intl opcache exif mbstring soap \
    # 安装Composer
    && curl -sS https://getcomposer.org/installer | php -- --install-dir="/usr/local/bin" --filename=composer && chmod +x "/usr/local/bin/composer"

# Datadog
ARG DD_ENV_ARG=placeholder
ENV DD_ENV=$DD_ENV_ARG

ENV DD_VERSION=1
ENV DD_SERVICE=platform-aws
ENV DD_PROFILING_ENABLED=true

COPY "./.docker-prod/platform/datadog-setup.php" "/app/platform/datadog-setup.php"
RUN php /app/platform/datadog-setup.php --php-bin=all --enable-profiling

COPY "./app" "/app/platform"
RUN perl -pi -e 's#^(?=access\.log\b)#;#' /usr/local/etc/php-fpm.d/docker.conf
COPY "./.docker-prod/platform/php.ini" "/usr/local/etc/php/conf.d/docker-php-config.ini"
COPY "./.docker-prod/platform/www.conf" "/usr/local/etc/php-fpm.d/www.conf"
COPY --from=vendor "/app/platform/vendor" "/app/platform/vendor"

WORKDIR "/app/platform"

RUN \
    composer dump-autoload --optimize --classmap-authoritative \
    && composer run-script post-install-cmd

# 入口点
COPY "./.docker-prod/platform/entrypoint.sh" "/usr/local/bin/entrypoint.sh"
RUN chmod +x "/usr/local/bin/entrypoint.sh"

我真的尽力使其工作,但没有成功。即使Datadog的文档使用了相同的方法,但使用了相同的示例也没有成功:https://docs.datadoghq.com/containers/amazon_ecs/apm/?tab=ec2metadataendpoint&code-lang=php

有人有什么想法吗?

英文:

I have a task definition that looks like this (truncated for readability). And I need to get the host IP address dynamically available inside the PHP container. It's required for Datadog to work.

[
{
...
"entryPoint": [
"/usr/local/bin/entrypoint.sh"
],
"portMappings": [
{
"hostPort": 0,
"protocol": "tcp",
"containerPort": 9000
}
],
...

This is a container that runs a Symfony application, with php-fpm. So my entrypoint.sh looks like this:

#!/bin/sh
export TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
export DD_AGENT_HOST=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4)
echo "Datadog agent host: ${DD_AGENT_HOST}"
php-fpm -F

The echo debug prints the correct value in the cloudwatch logs. However when I log into this container after it starts en check the environment variables with php -i, the variable is not in there.

I made sure clear_env = no is in my www.conf. But no success.

Here's my Dockerfile, for reference:

# Multi stage build. We first run composer install, and later copy it over in the 2nd image
FROM composer:2 as vendor
WORKDIR "/app/platform"
COPY ["./app/composer.json", "./app/composer.lock*", "/app/platform/"]
RUN composer install --no-interaction --no-dev --prefer-dist --ignore-platform-reqs
FROM php:8.1-fpm-buster as platform
RUN \
# Symfony needs write access to some folders. We need to pre generate these
mkdir -p "/app/platform/var" \
&& chmod 777 -R "/app/platform/var" \
# Install necessary binaries and packages
&& apt-get update \
&& apt-get install -y gnupg g++ procps openssl git unzip zlib1g-dev libzip-dev libfreetype6-dev libpng-dev libjpeg-dev libicu-dev  libonig-dev libxslt1-dev acl libjpeg62-turbo-dev libmcrypt-dev zip vim \
# Install php extensions
#&& pecl install redis \
#&& docker-php-ext-enable redis \
&& docker-php-ext-install pdo pdo_mysql zip xsl gd intl opcache exif mbstring soap \
# Install Composer
&& curl -sS https://getcomposer.org/installer | php -- --install-dir="/usr/local/bin" --filename=composer && chmod +x "/usr/local/bin/composer"
# Datadog
ARG DD_ENV_ARG=placeholder
ENV DD_ENV=$DD_ENV_ARG
ENV DD_VERSION=1
ENV DD_SERVICE=platform-aws
ENV DD_PROFILING_ENABLED=true
COPY "./.docker-prod/platform/datadog-setup.php" "/app/platform/datadog-setup.php"
RUN php /app/platform/datadog-setup.php --php-bin=all --enable-profiling
COPY "./app" "/app/platform"
RUN perl -pi -e 's#^(?=access\.log\b)#;#' /usr/local/etc/php-fpm.d/docker.conf
COPY "./.docker-prod/platform/php.ini" "/usr/local/etc/php/conf.d/docker-php-config.ini"
COPY "./.docker-prod/platform/www.conf" "/usr/local/etc/php-fpm.d/www.conf"
COPY --from=vendor "/app/platform/vendor" "/app/platform/vendor"
WORKDIR "/app/platform"
RUN \
composer dump-autoload --optimize --classmap-authoritative \
&& composer run-script post-install-cmd
# Entrypoint
COPY "./.docker-prod/platform/entrypoint.sh" "/usr/local/bin/entrypoint.sh"
RUN chmod +x "/usr/local/bin/entrypoint.sh"

I honestly tried everything to make this work, but no success. Even the documentation of datadog using the same kind of approach, but using that exact example also didn't work: https://docs.datadoghq.com/containers/amazon_ecs/apm/?tab=ec2metadataendpoint&code-lang=php

Anyone any ideas?

答案1

得分: 1

以下是要翻译的代码部分:

Let me first repeat your question, what my understanding of it is, and then, provide a solution and explanation:

That's correct, the php binary invoked by docker-exec(1) in the container doesn't have the environment of php-fpm(1) invoked in the entrypoint.

For php-fpm(1) you wrote you've solved the original problem of DD_AGENT_HOST parameter unavailability by doing two things:

  1. You configured the php-fpm pool with the clear_env directive setting it to "no" (clear_env = no). Please note that this takes in the whole environment, I'd highly recommend to set each environment parameter explicitly[¹][¹], I'd consider this is because you wanted to share how you were able to enable it for this example material and you're aware of the pool configuration directives, and you're interested in the exemplary DD_AGENT_HOST parameter only.
  2. You exported the DD_AGENT_HOST parameter in the entrypoint with the export shell built-in (export PARAMETER=VALUE).

For php(1), the binary of the PHP CLI SAPI, you were not yet able to make the DD_AGENT_HOST parameter available.

So much for my understanding of your question, the answer to it is that your entrypoint is not yet complete.
Which is good news, because it means you were already close and can easily go on at that place.

While all sub-processes of the entrypoint (you should use exec for php-fpm btw., compare with the original entrypoint) will have the DD_AGENT_HOST parameter bootstrapped, php(1) (CLI) does not have it yet, docker-exec will not add it there.

Therefore, you need to bootstrap the php process with the environment whenever you invoke it, and that bootstrapping must be seeded within the entrypoint so that the container is prepared completely (technically, you could do it during the build of the container, but for the property you're looking for it likely does not exist then).

This works by replacing php(1) with a stub that takes care to initialize the environment and then passing it over to the original binary.

I created a git repository that has a complete test-stand and shows the production for the Dockerfile, here an excerpt for that relevant part for a php:8.1-fpm-buster base image, quoted from the COPY[²][²] section of the entrypoint docker build[³][³]. The example is in the sh syntax, I added some callouts:

## HK: setup /usr/local/bin/php for PHP docker exec default environment
mv -n /usr/local/bin/php /usr/local/bin/php-cli.bin # <1>
<<STUB cat > /usr/local/bin/php
#!/bin/bash
export DD_AGENT_HOST="${DD_AGENT_HOST:?}" # <2>
exec -a "$0" /usr/local/bin/php-cli.bin "$@"
STUB
chmod --reference=/usr/local/bin/php-cli.bin /usr/local/bin/php

<sup><1> The original binary is moved, as it will be started again</sup>

<sup><2> Parameters need to be "re-exported", the :? parameter substitution is used to exit early by giving a precise parameter error when unset or empty. You can find this also in some of my answers in the CI collective, I highly recommend this for builds and CI pipelines of different kinds.</sup>

<sup>Note: If the required parameter is non-empty but with a wrong or of a faulty value, you may want to add additional checks before you apply these changes as this can quickly become cumbersome when you rely on it otherwise. That is, do your own build checks.</sup>

<sup><3> This is where some magic comes in, note that this form of exec constitutes a bash requirement and buster has you covered – just FYI.</sup>

So that's all the magic. If we now run the tests with diverse forms of invocation, we can see it working (omissions for readability, you can run the full tests yourself):

$ make clean test
...
./build.sh: now building "build"...
...
./build.sh: container-id: 81dc410de4a3 ...
./build.sh: [XX-XXX-XXXX XX:XX:XX] NOTICE: datadog agent host DD_AGENT_HOST: "FAKE-IT"
./build.sh: [XX-XXX-XXXX XX:XX:XX] NOTICE: fpm is running, pid 1
./build.sh: [XX-XXX-XXXX XX:XX:XX] NOTICE: ready to handle connections
./build.sh: done build "build" (id: 81dc410de4a3); entrypoint: /usr/local/bin/app-docker-php-entrypoint
...
./test.sh: initializing and running 5 test/s in "build"...

[1/5] php -i (non-interactive)

  • docker exec build php -i
    [1] DD_AGENT_HOST => FAKE-IT
    [1] $_SERVER['DD_AGENT_HOST'] => FAKE-IT
    [1] $_ENV['DD_AGENT_HOST'] => FAKE-IT

[2/5] php -i (non-interactive, within PHP itself)

  • docker exec build php -r 'passthru("php -i");'
    [2] DD_AGENT_HOST => FAKE-IT
    ...

[3/5] /bin/sh (non-interactive)

  • docker exec build /bin/sh -c 'php -i'
    [3] DD_AGENT_HOST => FAKE-IT
    ...

[4/5] /bin/sh (interactive; no tty)

  • docker exec build /bin/sh -ic 'php -i'
    /bin/sh: 0: can't access tty; job control turned off
    [4] DD_AGENT_HOST => FAKE-IT
    ...

[5/5] /bin/sh (interactive)

  • docker exec -t build /bin/sh -ic 'php -i'
    [5] DD_AGENT_HOST => FAKE-IT
    ...

As the build tests show, with the modified entrypoint the parameter is available within the PHP CLI SAPI in the diverse forms of invocations available with docker-exec(1).

The value FAKE-IT is just a test value for the parameter to show it's a solution independent to Amazon Web Services and relies on standard Debian GNU Linux.

希望这些翻译能对您有所帮助。

英文:

Let me first repeat your question, what my understanding of it is, and then, provide a solution and explanation:

> When I log into this container [FROM php:8.1-fpm-buster, and] after it starts [, when I] check the environment variables with php -i, the variable is not in there.

That's correct, the php binary invoked by docker-exec(1) in the container doesn't have the environment of php-fpm(1) invoked in the entrypoint.

For php-fpm(1) you wrote you've solved the original problem of DD_AGENT_HOST parameter unavailability by doing two things:

  1. You configured the php-fpm pool with the clear_env directive setting it to "no" (clear_env = no). Please note that this takes in the whole environment, I'd highly recommend to set each environment parameter explicitly[¹][¹], I'd consider this is because you wanted to share how you were able to enable it for this example material and you're aware of the pool configuration directives, and you're interested in the exemplary DD_AGENT_HOST parameter only.
  2. You exported the DD_AGENT_HOST parameter in the entrypoint with the export shell built-in (export PARAMETER=VALUE).

For php(1), the binary of the PHP CLI SAPI, you were not yet able to make the DD_AGENT_HOST parameter available.


So much for my understanding of your question, the answer to it is that your entrypoint is not yet complete.
Which is good news, because it means you were already close and can easily go on at that place.

While all sub-processes of the entrypoint (you should use exec for php-fpm btw., compare with the original entrypoint) will have the DD_AGENT_HOST parameter bootstrapped, php(1) (CLI) does not have it yet, docker-exec will not add it there.

Therefore, you need to bootstrap the php process with the environment whenever you invoke it, and that bootstrapping must be seeded within the entrypoint so that the container is prepared completely (technically, you could do it during the build of the container, but for the property you're looking for it likely does not exist then).

This works by replacing php(1) with a stub that takes care to initialize the environment and then passing it over to the original binary.

I created a git repository that has a complete test-stand and shows the production for the Dockerfile, here an excerpt for that relevant part for a php:8.1-fpm-buster base image, quoted from the COPY[²][²] section of the [entrypoint docker build³][³]. The example is in the sh syntax, I added some callouts:

> ~~~Shell
> ## HK: setup /usr/local/bin/php for PHP docker exec default environment
> mv -n /usr/local/bin/php /usr/local/bin/php-cli.bin # <1>
> <<STUB cat > /usr/local/bin/php
> #!/bin/bash
> export DD_AGENT_HOST="${DD_AGENT_HOST:?}" # <2>
> exec -a "$0" /usr/local/bin/php-cli.bin "$@" # <3>
> STUB
> chmod --reference=/usr/local/bin/php-cli.bin /usr/local/bin/php
> ~~~

<sup><1> The original binary is moved, as it will be started again</sup>

<sup><2> Parameters need to be "re-exported", the :? parameter substitution is used to exit early by giving a precise parameter error when unset or empty. You can find this also in some of my answers in the CI collective, I highly recommend this for builds and CI pipelines of different kinds.</sup>

<sup>Note: If the required parameter is non-empty but with a wrong or of a faulty value, you may want to add additional checks before you apply these changes as this can quickly become cumbersome when you rely on it otherwise. That is, do your own build checks.</sup>

<sup><3> This is where some magic comes in, note that this form of exec constitutes a bash requirement and buster has you covered – just FYI.</sup>


So that's all the magic. If we now run the tests with diverse forms of invocation, we can see it working (omissions for readability, you can run the full tests yourself):

$ make clean test
...
./build.sh: now building &quot;build&quot;...
...
./build.sh: container-id: 81dc410de4a3 ...
./build.sh: [XX-XXX-XXXX XX:XX:XX] NOTICE: datadog agent host DD_AGENT_HOST: &quot;FAKE-IT&quot;
./build.sh: [XX-XXX-XXXX XX:XX:XX] NOTICE: fpm is running, pid 1
./build.sh: [XX-XXX-XXXX XX:XX:XX] NOTICE: ready to handle connections
./build.sh: done build &quot;build&quot; (id: 81dc410de4a3); entrypoint: /usr/local/bin/app-docker-php-entrypoint
...
./test.sh: initializing and running 5 test/s in &quot;build&quot;...

[1/5] php -i (non-interactive)
+ docker exec build php -i
  [1] DD_AGENT_HOST =&gt; FAKE-IT
  [1] $_SERVER[&#39;DD_AGENT_HOST&#39;] =&gt; FAKE-IT
  [1] $_ENV[&#39;DD_AGENT_HOST&#39;] =&gt; FAKE-IT

[2/5] php -i (non-interactive, within PHP itself)
+ docker exec build php -r &#39;passthru(&quot;php -i&quot;);&#39;
  [2] DD_AGENT_HOST =&gt; FAKE-IT
  ...

[3/5] /bin/sh (non-interactive)
+ docker exec build /bin/sh -c &#39;php -i&#39;
  [3] DD_AGENT_HOST =&gt; FAKE-IT
  ...

[4/5] /bin/sh (interactive; no tty)
+ docker exec build /bin/sh -ic &#39;php -i&#39;
/bin/sh: 0: can&#39;t access tty; job control turned off
  [4] DD_AGENT_HOST =&gt; FAKE-IT
  ...

[5/5] /bin/sh (interactive)
+ docker exec -t build /bin/sh -ic &#39;php -i&#39;
  [5] DD_AGENT_HOST =&gt; FAKE-IT
  ...

As the build tests show, with the modified entrypoint the parameter is available within the PHP CLI SAPI in the diverse forms of invocations available with docker-exec(1).

The value FAKE-IT is just a test value for the parameter to show it's a solution independent to Amazon Web Services and relies on standard Debian GNU Linux.


¹ <sup>Cf. [Example #1 Passing environment variables and PHP settings to a pool][¹]</sup>

² <sup>docker build as docker buildx version: github.com/docker/buildx v0.11.2 9872040</sup>

³ <sup>Cf. [build.sh:L35-L66 Docker full ENTRYPOINT production in Dockerfile][³]</sup>

[¹]: https://www.php.net/manual/en/install.fpm.configuration.php#example-24 "Passing environment variables and PHP settings to a pool in List of pool directives – Example in: Configuration – FastCGI Process Manager (FPM) – Installation and Configuration – PHP Manual"

[²]: https://localhost/ "docker build as docker buildx version: github.com/docker/buildx v0.11.2 9872040"

[³]: https://github.com/hakre/so76831368/blob/master/build.sh#L35-L66 "Docker full ENTRYPOINT production in Dockerfile"

答案2

得分: 0

然而,当我登录到这个容器并在启动后使用 php -i 检查环境变量时,该变量并不在其中。

但是... 当你直接从命令行运行 php -i(或任何 PHP 脚本)时,你正在调用 PHP 命令行界面(CLI)二进制文件,而不是 PHP-FPM 进程。在 php-fpm 配置中设置的环境变量(如 /usr/local/etc/php-fpm.d/www.conf)不一定在此上下文中可用。

如果你正在为 PHP-FPM 特别设置环境变量,你需要在由 PHP-FPM 提供并通过 web 请求访问的 PHP 脚本上测试它们。

所以,要真正检查 DD_AGENT_HOST 是否可用于 PHP-FPM,请创建一个像这样的 PHP 脚本:

<?php

$envName = 'DD_AGENT_HOST';
$envValue = getenv($envName);

echo "Environment Variable Name: {$envName}\n";
echo "Value: '{$envValue}'\n";

if (empty($envValue)) {
    echo "The value appears to be empty or not set.";
} else {
    echo "The value is set and not empty.";
}
?>

然后使用 PHP-FPM 和你的 web 服务器(Nginx、Apache 等)提供它。
通过 web 请求访问它。

这将为你提供一个明确的答案,即环境变量是否在 PHP-FPM 上下文中可用。

英文:

> However, when I log into this container after it starts en check the environment variables with php -i, the variable is not in there.

But... when you run php -i (or any PHP script) directly from the command line, you are invoking the PHP CLI (Command Line Interface) binary, not the PHP-FPM process. Environment variables set in php-fpm configurations (like /usr/local/etc/php-fpm.d/www.conf) will not necessarily be available in this context.

If you are setting environment variables specifically for PHP-FPM, you will need to test them in the context of a PHP script that is being served by PHP-FPM and accessed via a web request.

So, to truly check if DD_AGENT_HOST is available to PHP-FPM, create a PHP script like this:

&lt;?php

$envName = &#39;DD_AGENT_HOST&#39;;
$envValue = getenv($envName);

echo &quot;Environment Variable Name: {$envName}\n&quot;;
echo &quot;Value: &#39;{$envValue}&#39;\n&quot;;

if (empty($envValue)) {
    echo &quot;The value appears to be empty or not set.&quot;;
} else {
    echo &quot;The value is set and not empty.&quot;;
}
?&gt;

Then serve it using PHP-FPM and your web server (Nginx, Apache, etc.).
And Access it through a web request.

That will give you a definitive answer whether the environment variable is available in the PHP-FPM context.

答案3

得分: 0

然而,当我登录到这个容器之后,它启动并检查环境变量。

由于这是一个单独的登录会话,具有与运行entrypoint.sh的任何会话不同的环境变量,也许将DD_AGENT_HOST添加到/etc/profile.d中会解决这个问题?

#!/bin/sh

export TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
export DD_AGENT_HOST=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4)
echo "export DD_AGENT_HOST=$DD_AGENT_HOST" > /etc/profile.d/dd_agent_host.sh

echo "Datadog agent host: ${DD_AGENT_HOST}"

php-fpm -F
英文:

>However when I log into this container after it starts en check the environment variables

well since it's a separate login session, with separate enviorment variables from whatever session is running your entrypoint.sh, maybe adding DD_AGENT_HOST to /etc/profile.d would fix it?

#!/bin/sh

export TOKEN=$(curl -s -X PUT &quot;http://169.254.169.254/latest/api/token&quot; -H &quot;X-aws-ec2-metadata-token-ttl-seconds: 21600&quot;)
export DD_AGENT_HOST=$(curl -s -H &quot;X-aws-ec2-metadata-token: $TOKEN&quot; http://169.254.169.254/latest/meta-data/local-ipv4)
echo &quot;export DD_AGENT_HOST=$DD_AGENT_HOST&quot; &gt; /etc/profile.d/dd_agent_host.sh

echo &quot;Datadog agent host: ${DD_AGENT_HOST}&quot;

php-fpm -F

huangapple
  • 本文由 发表于 2023年8月4日 04:14:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76831368.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定