【问题标题】:How to use docker-compose environment variables to populate config file如何使用 docker-compose 环境变量来填充配置文件
【发布时间】:2017-08-03 17:47:19
【问题描述】:

我是 docker-compose 的新手。
我试图了解如何在Dockerfile 的构建阶段通过 docker-compose 传递环境变量以填充配置文件中缺少的变量值,因此在运行阶段,我将运行服务-rabbitmq它的配置填充了环境变量值。

在 docker-compose yml 文件中,我有一个 env_file:environment:,我该如何将它们传递给配置文件。

任何帮助,一个简单的例子将不胜感激 当然。

示例 rabbitmq 配置文件(环境变量需要用 $SSL_PORT 的值填充):

[{rabbit,
  [
    {loopback_users, []},
    {ssl_listeners, [$SSL_PORT]},
    {ssl_options, [{cacertfile,"/etc/rabbitmq/ca/cacert.pem"},
                   {certfile,"/etc/rabbitmq/server/cert.pem"},
                   {keyfile,"/etc/rabbitmq/server/key.pem"},
                   {verify,verify_none},
                   {fail_if_no_peer_cert,false}]}
  ]}
].

【问题讨论】:

  • @TarunLalwani:如何将源自 env_file:environment: 部分的环境变量传递给 docker build 阶段的配置文件?
  • 如果您在构建过程中传递它,那么您需要使用构建参数。 docs.docker.com/engine/reference/commandline/build/…
  • @JavaSa: ...但请注意,如果您在构建过程中尝试生成该配置,那么放弃很多灵活性就会有问题。这(生成配置文件)通常在运行时更有用,因为您运行容器的位置通常与构建映像的位置完全不同。此外,让容器中的 ssl 端口可配置似乎没有必要:容器网络是隔离的,您可以使用端口映射将服务暴露在任意主机端口。
  • @larsks:除了端口我需要传入我想为rabbitmq创建的用户和密码,在这个特定的例子中,它将使用默认用户。所以我仍然需要模板机制来填充conf。

标签: bash docker rabbitmq docker-compose


【解决方案1】:

问题可以分为两部分:

  1. 在容器内注入配置值
  2. 让目标软件使用这样的配置值

第一个问题是通过使用环境变量解决的:正如您所说,您可以指示 docker 使用 env 文件 (--env-file file.env) 或指定单个环境变量 (--env VARIABLE=value),docker 将使它们在容器。

第二个问题根据使用的配置框架有不同的解决方案。

例如,如果您使用 Typesafe configSpring 之类的东西,您可以在配置本身中放置对环境变量的引用,配置框架会自动扩展它。

如果您正在配置不支持环境变量扩展的第三方软件,则需要在目标软件执行之前进行一些预处理。

这通常通过使用自定义 entrypoint 创建一个 docker 映像来完成。该入口点负责修改目标软件的配置,扩展已知环境变量,然后启动软件。

这种入口点脚本的一个例子可能是:

#!/bin/sh

sed -i "s/\$SSL_PORT/$SSL_PORT/g" /etc/software.conf

exec $@

以这种方式修改配置文件可能很危险且容易出错,因此在编写此类脚本时要小心。

更新

如果您只想在原始入口点开始之前执行一些预处理,您可以遵循以下简单模式:假设原始入口点称为docker-entrypoint.sh,您需要做的就是创建@987654329 @有这个内容:

#!/bin/bash

# Perfom all the needed preprocessing here...

# Invoke the original entrypoint passing the command and arguments
exec /docker-entrypoint.sh $@ 

如果您使用新入口点构建 docker 映像并使用以下命令启动容器:

docker run --rm test-image echo "This is a test"

将会发生的情况是docker-entrypoint-pre.sh 将使用参数echoThis is a test 进行调用。预处理完成后,原始入口点docker-entrypoint.sh 将使用相同的参数调用,从而保持原始图像的行为。

更新 2: 为了添加新的入口点,您必须创建一个继承自原始入口点的新 Docker 映像。假设原始图像是rabbit:latest,您需要创建一个具有以下内容的Dockerfile

FROM rabbit:latest

COPY docker-entrypoint-pre.sh /docker-entrypoint-pre.sh

ENTRYPOINT ["/docker-entrypoint-pre.sh"]

然后使用包含Dockerfiledocker-entrypoint-pre.sh 的目录中的docker build -t myrabbit:latest . 构建您的映像。

此时,您有了一个带有预处理逻辑的新图像myrabbit:latest

【讨论】:

  • 您能否指定 bellow bash 脚本命令的翻译,另外我怎么能不覆盖我现有的 rabbitmq docker-entrypoint.sh 而只是用我自己的脚本扩展它以在此之前运行。 Docker-entrypoint.sh 正在使用配置,所以我需要在它启动之前做一些修改
  • 我作为示例发布的 bash 脚本只是使用 sed 将每次出现的 $SSL_PORT 替换为该环境变量的值。这是我的 goto 方法,因为 sed 存在于许多基础映像中。入口点脚本的最后一行是启动软件的实际调用。 Docker 将使用最终命令(及其参数)作为参数调用入口点脚本。鉴于这种情况,如果你想做一些预处理,你可以让你的入口点调用原始入口点。我将更新答案以提供示例。
  • 好的,我有一个带有预处理的新脚本,我如何覆盖这个 dockerfile 以首先启动我的预处理,然后是所有其他指令:github.com/docker-library/rabbitmq/blob/…
  • @JavaSa 为了做到这一点,您必须创建一个继承自原始镜像的新 Docker 镜像并替换入口点。有关详细信息,请参阅更新的答案。如果你觉得它足够完整,也请接受答案。
  • 从 pre-entrypoint 脚本启动 docker-entrypoint.sh 时还需要传递 rabbitmq 服务器参数。
【解决方案2】:

假设您的配置文件在容器内部使用变量$SSL_PORT,并且您希望从要使用的主机机器传递环境变量在构建时,这可以在您的 docker-compose.yml 中完成。 YAML 支持使用环境变量,因此,您可以使用 environment: 后跟要在运行时传递给容器的变量数组。

例如:

version: '3'
services:
  your-app:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - "SSL_PORT=${PORT_VARIABLE_FROM_HOST}"

要排除故障并确保您的变量实际上是在您的容器运行中分配的:

docker exec -it <container_name_or_id> printenv

这应该列出容器内的所有环境变量

【讨论】:

  • 我在构建时而不是运行时需要它,这意味着在dockerfile 中,如果我执行 printenv 我看不到环境变量..
猜你喜欢
  • 1970-01-01
  • 2015-06-17
  • 2019-08-02
  • 2015-05-29
  • 2018-02-11
  • 2022-11-10
  • 2019-07-26
  • 1970-01-01
相关资源
最近更新 更多