【问题标题】:How to substitute environment variable in command of service in docker-compose.yml at runtime of container?如何在容器运行时替换 docker-compose.yml 中服务命令中的环境变量?
【发布时间】:2021-10-26 04:39:22
【问题描述】:

下面的docker-compose.yml定义了command,其中包含一个环境变量FOO

version: '3.7'
services:
  tmp:
    image: alpine
    environment:
      FOO: foo
    command: ["echo", "${FOO:-foobar}"]

如果你跑了

docker-compose -p app up

并使用查看容器的日志

docker logs app_tmp_1

你看

foobar

由于环境变量FOO 被替换,当/之前docker-compose.yml 被解析/读取。如果环境变量FOO 将在容器app_tmp_1 的运行时被替换,则输出将是

foo

因为为容器配置了环境变量FOO=foo

如何配置command 以在容器app_tmp_1 运行时替换/评估环境变量(即示例中的输出foo)?

【问题讨论】:

  • 可以放到.env文件中。
  • 这里不使用容器中/的环境变量。它只使用.env 的值,而不是docker-compose.yml 中指定的默认值。替换完成的时间是相同的(当解析docker-compose.yml 时)。
  • 为什么要在容器运行时评估docker-compose.yml 中编写的内容?即使你以某种方式完成了这项工作,它也会非常混乱。尝试使用结构/系统,而不是随心所欲地弯曲它。
  • 无论哪种方式都令人困惑;)这取决于您的假设/背景。例如,Docker Compose 中的command 与 Dockerfile 中的CMD 的处理方式不同(请参阅reference)。 CMD [ "sh", "-c", "echo $HOME" ] 在容器运行时替换,但 command: [ "sh", "-c", "echo $HOME" ] 不替换。
  • 此外,很高兴知道替换实际上是如何起作用的,或者什么不起作用。例如,嵌套替换可能在 Docker Compose 中不起作用(请参阅my answer)。

标签: docker docker-compose environment-variables


【解决方案1】:

在使用 docker-compose 创建容器时,docker-compose 中的环境变量似乎不可用。

同样的问题是将环境变量放入 docker-compose 并期望它们在 Dockerfile 的构建阶段可用(在 docker-compose 的构建阶段)。 那么它们也不可用。

你可以做的是:

docker-compose.yml

version: '3.7'
services:
  tmp:
    image: alpine
    container_name: fooContainer
    volumes:
      - ./start.sh:/root/start.sh:ro
    environment:
      FOO: foo
    command: ["/root/start.sh"]

start.sh

由于 start.sh 脚本在容器内运行,您将获得可用的环境变量。 start.sh 看起来像这样:

#!/bin/sh
echo $FOO

结果

$ docker-compose up
Creating fooContainer ... done
Attaching to fooContainer
fooContainer | foo
fooContainer exited with code 0

【讨论】:

  • 这是一种可行的解决方法(在大多数情况下),但它需要在主机上定义另一个文件,这可能不起作用(例如,如果您将DOCKER_HOST 更改为在远程主机上运行,文件不存在的地方)。
  • 你是对的,这是一种解决方法。还有一个没有阅读过文档,抱歉 :-) 见这里:docs.docker.com/compose/environment-variables
  • 您参考了文档的哪一部分?我是否忽略了针对我所描述问题的解决方案(没有解决方法)?
  • 右上方:“在 Compose 文件中替换环境变量”。
  • 我还没有找到解决我在该部分中描述的问题的解决方案(没有解决方法)。我应该吗?
【解决方案2】:

编辑:

您可以在docker-compose.yml 中转义环境变量(双美元符号$$ 而不是一个$),以防止它在容器的命令中被替换。但是,由于替换应该在运行时完成,因此必须在容器中运行一个 shell(命令)来进行替换,例如

version: '3.7'
services:
  tmp:
    image: alpine
    environment:
      FOO: foo
    command: sh -c 'echo "$${FOO:-foobar}"'

旧答案:

我刚刚发现嵌套的环境变量没有被替换。

version: '3.7'
services:
  tmp:
    image: alpine
    environment:
      FOO: foo
    command: sh -c 'echo FOO is "${FOO_OVERWRITE:-${FOO:-foobar}}" && env'

如果你跑了

docker-compose -p app up

你得到

# echo output
FOO is foo
# env output
FOO=foo

即使你运行,你也会得到相同的结果

FOO=ignored docker-compose -p app up

但是,如果你运行

FOO_OVERWRITE=overwritten docker-compose -p app up

你得到

# echo output
FOO is overwritten}
# env output
FOO=foo

覆盖可能不起作用,因为} 是输出的一部分。考虑到这一点,您不应使用此解决方案;)

注意:如果您在 shell 中运行相同的命令(不涉及 Docker),您不会得到 }

$ sh -c 'echo FOO is "${FOO_OVERWRITE:-${FOO:-foobar}}"' 
FOO is foobar

如果容器中没有定义环境变量,即移除

    environment:
      FOO: foo

来自docker-compose.yml,即

version: '3.7'
services:
  tmp:
    image: alpine
    command: sh -c 'echo FOO is "${FOO_OVERWRITE:-${FOO:-foobar}}" && env'

你会得到命令中定义的默认值

# echo output
FOO is foobar
# env output does not contain FOO

Docker Compose 版本 1.26.0

【讨论】:

    猜你喜欢
    • 2022-11-17
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 2016-07-16
    • 2022-06-24
    相关资源
    最近更新 更多