【问题标题】:How to add EnvironmentFile directive to systemctl using Docker with centos7/httpd base image如何使用带有 centos7/httpd 基础镜像的 Docker 将 EnvironmentFile 指令添加到 systemctl
【发布时间】:2016-09-18 20:58:39
【问题描述】:

如果不创建我自己的基本映像,我不确定这是否可行,但我在我们的服务器上使用 /etc/environment 中的环境变量,并且通常通过执行以下操作使 apache 可以访问它们:

$ printf "HTTP_VAR1=var1-value\n\
HTTP_VAR2=var2-value"\
 >> /etc/environment
$ mkdir /usr/lib/systemd/system/httpd.service.d
$ printf "[Service]\n\
EnvironmentFile=/etc/environment"\
 > /usr/lib/systemd/system/httpd.service.d/environment.conf
$ systemctl daemon-reload
$ systemctl restart httpd
$ reboot

然后,这些变量可在对getenv('HTTP_VAR1'); 等的任何 PHP 调用中使用。但是,在从 docker 文件运行它时,我在 systemctl 命令上遇到 dbus 错误。如果没有 systemctl 命令,apache 似乎无法使用这些变量,因为新的 EnvironmentFile 指令似乎没有生效。我的docker文件sn-p:

FROM centos/httpd:latest

RUN printf "HTTP_VAR1=var1-value\n\
HTTP_VAR2=var2-value"\
 >> /etc/environment

RUN mkdir /usr/lib/systemd/system/httpd.service.d &&\
 printf "[Service]\n\
EnvironmentFile=/etc/environment"\
 > /usr/lib/systemd/system/httpd.service.d/environment.conf

RUN systemctl daemon-reload &&\
 systemctl restart httpd

COPY entrypoint.sh /entrypoint.sh

【问题讨论】:

  • 尝试删除“RUN systemctl daemon-reload &&\ systemctl restart httpd”..
  • 就是这样,如果我删除它们,我的 EnvironmentFile 似乎不会被 apache 加载。在实时服务器上,我必须运行这两个命令才能使 EnvironmentFile 生效。
  • 好的..通常 docker 镜像的软件配置不同..您可能需要查看 httpd 镜像以了解如何注入变量a
  • 那么我是否相信您认为添加 EnvironmentFile 应该在没有守护程序重新加载的情况下被拾取?因为在真实服务器上肯定不会发生这种情况,所以您必须在此之后重新加载并重新加载 apache。不知道为什么 docker 服务器会有所不同。
  • docker 环境中唯一的区别是进程在前台运行,因此某些配置可能会有所不同。但它不应该有太大的不同。查看基础镜像的 dockerfile 应该会给你很好的线索。

标签: apache docker centos dockerfile systemd


【解决方案1】:

所以我今天偶然发现了这个问题的答案。似乎 systemd 在单引号内删除了反斜杠,但从我在测试中看到的情况来看,它也可能会影响双引号。我找到了systemd development mailing list thread from April 2014 where patching the issue was being discussed。似乎修复程序从未成功。所以我们必须解决它。

在尝试解决它时,我注意到实际读取变量时存在一些问题。似乎 Apache 或 php-cli 都可以获得正确的变量,有时根本没有,需要进行一些调查才能弄清楚发生了什么。然后我开始阅读systemd's EnvironmentFile directive,看看是否有更多可以从文档中获得。事实证明它不评估 bash 所以导出不起作用。它需要一个带有变量赋值的文本文件,这可能是导致此问题无法解决的主要问题之一。

然后我设计了一个可行的解决方案。利用systemd's ExecStartPre directive 我可以在httpd 服务启动时运行脚本。然后我读入环境文件并编写一个新的纯文本文件,然后 httpd 的 systemd 单元将使用该文件。代码如下:

首先,我将变量移动到/etc/profile.d/ 目录而不是/etc/environment 文件。

文件: /etc/profile.d/environment.sh
这是我们存储所有环境变量的地方,这很容易从所有交互式 shell 登录中获取。在极少数情况下,我们需要以非交互方式提供这些变量,我们可以将 --login 标志提供给 /bin/bash 或手动获取它。

export HTTP_VAR1=var1-value-with-a-back\slash
export HTTP_VAR2=var2-value

文件: /usr/lib/systemd/system/httpd.service.d/environment.conf
我们的插入单元文件,用于扩展 httpd 服务的工作方式。我添加了一个在 httpd 启动之前运行的脚本。这会在所有 httpd 重新启动和启动时运行。运行的脚本会在 /etc/profile.d/environment.env 处生成一个纯文本文件,我们随后告诉 systemd 将其作为 EnvironmentFile 加载。

[Service]
ExecStartPre=/usr/bin/bash -c "/usr/local/bin/generate-plain-environment-file"
EnvironmentFile=/etc/profile.d/environment.env

文件: /usr/local/bin/generate-plain-environment-file
这是我正在使用的脚本,我非常快速地将它组合在一起,我真的不认为它那么健壮而且它可能会更好。它只是从行的开头删除export,然后转义任何反斜杠,因为 systemd 删除了单个反斜杠。更合适的解决方案可能是使用 bash 评估每一行并在实际 bash 变量中使用变量或其他 bash 的情况下获取变量值,然后将它们输出为纯文本 name=value 赋值,但这不是我的用例,所以我没有打扰。

#!/bin/bash

cd /etc/profile.d/
rm -rf "./environment.env"

while IFS='' read -r line || [[ -n "$line" ]]; do
  echo $(echo "${line}" | sed 's/^export //' | sed 's/\\/\\\\/g') >> "./environment.env";
done < "./environment.sh"

文件: /etc/profile.d/environment.env
这是所描述的脚本生成的结果文件。

HTTP_VAR1=var1-value-with-a-back\\slash
HTTP_VAR2=var2-value

结论是我现在有两个文件,里面有相同的东西,但我只需要维护一个,另一个是每次我们重新启动 httpd 时生成的。此外,我们修复了过程中的反斜杠问题。万岁!

【讨论】:

    猜你喜欢
    • 2017-12-31
    • 1970-01-01
    • 2020-01-20
    • 2017-04-24
    • 2022-12-12
    • 1970-01-01
    • 2017-09-29
    • 2020-02-26
    • 2021-12-11
    相关资源
    最近更新 更多