Compose: 在docker-compose.yml中插值环境变量

创建于 2015-04-30  ·  109评论  ·  资料来源: docker/compose

(我为此创造了一个新的问题,因为旧的积累了很多行李。)

应该可以将环境变量传递到docker-compose.yml的任何*配置条目的值。 很多人都想这样做,这对便携性有好处,我很满意,这不会造成混乱。

我有一些估计。

必需变量和可选默认值

能够指定环境中必须存在的_must_变量是很有用的,即,如果没有,则Compose将拒绝运行。 但是,当您拥有很多时,这将很痛苦,因此它应该是您明确启用的功能,或者应该可以指定默认值。

MVP实现不需要具有任何功能,但是应该有一条向后兼容的方式来实现这两个功能。

句法

只要它不是重量级的,就有充分的理由实施已建立的标准-我们对功能的要求是最低的。

  • POSIX参数扩展正常。 它具有太多功能,但是我们可以实现其中的一个子集:

    • ${VARIABLE} -如果未设置VARIABLE则输出空字符串

    • ${VARIABLE-default} -如果未设置VARIABLE则输出default

    • ${VARIABLE?} -如果未设置VARIABLE则会出错

https://github.com/docker/compose/pull/845实现了Bash风格的${VARIABLE:default}语法,类似于POSIX参数扩展,但略有不同。

实作

Python的os.path.expandvars函数实现了POSIX参数扩展的最基本情况:

>>> from os.path import expandvars
>>> expandvars('${HOME}')
'/Users/aanand'

但是,它至少有两个问题:

  1. 未设置的变量不会扩展为空字符串-而是不会扩展:

```

expandvars('$ {UNSET}')
“ $ {UNSET}”
```

  1. 语法错误不会出错-相反,它也不会导致扩展:

```

expandvars('$ {HOME')
“ $ {HOME”
```

到目前为止, https://github.com/docker/compose/pull/845是我们所拥有的最接近的产品,但是从根本上我对依赖正则表达式的实现持谨慎态度。 模板化是一项不平凡的工作,人们将把各种各样的坏物放入其中,因此我们需要一些健壮,严格和错误的信息,并提供有用的信息。 两个重要要求:

  • 如果有人放入格式错误的内容,则Compose将无法运行。
  • 可以转义模板语法中使用的任何特殊字符。

可能已经有类似Bash的变量插值的良好Python实现了-如果没有,创建独立的东西比膨胀Compose代码库要好得多。

*实际上,是否有我们不应该允许插值的配置键?

kinenhancement kinfeature

最有用的评论

我的用例是在volumes允许$PWD ,这样团队中的每个开发人员都可以将仓库克隆到任何地方,并且路径仍然可以正确安装。

elasticsearch:
  image: zinvoice/elasticsearch
  volumes:
    - $PWD:/app

所有109条评论

您想使用这些已建立的UNIX标准到什么程度? (FWIW,这不是实际标准,而是实际标准。)

由于偶尔会偶然尝试在Dockerfile中使用POSIX参数扩展的人,如果docker-compose.yml完全支持

@kojiromike Hmm,所以POSIX参数扩展实际上是我想要的,但是仔细阅读文档,似乎我记错了语法/语义。

编辑:我已经更新了我对描述中语法的看法。

我一直沿用旧线程,我们迫切希望拥有此功能。 最终,痛苦太大了,我们创建了一个Yaml预处理程序bahs脚本来替换POSIX风格的变量。 它工作正常,但最终我们停止使用它,因为它有一个问题。 您必须先运行预处理器并设置所有参数,然后才能获得最终解决方案。 现在,我们正在使用docker yaml扩展功能。 因为它允许我们签入实际配置并仅在目标上执行它。 我们更清楚会发生什么。

即使我是docker-compose传递变量的支持者,我现在也不是很确定。

作为理想的解决方案,我宁愿看到Docker扩展正确。 从某种意义上说,这将是一个适合两者的解决方案。 那么Doc​​ker扩展中发生了什么? 基本上,您必须在继承的文件中写入所有条目。 它不是仅输入要覆盖的内容的合并。

看一下实际示例及其详细程度。 只有两行很重要。

#Common 
elasticsearch:
  image: zinvoice/elasticsearch
  hostname: elasticsearch
  restart: always
  dns: 172.17.42.1
  ports:
    - "9200:9200"
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro
    - /data/elasticsearch:/opt/elasticsearch/data/elasticsearch

logstash:
  image: zinvoice/logstash
  hostname: logstash
  dns: 172.17.42.1
  restart: always
  ports:
    - "5000:5000"
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro

kibana:
  image: zinvoice/kibana
  hostname: kibana
  dns: 172.17.42.1
  restart: always
  ports:
    - "5601:5601"
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro

logspout:
  image: zinvoice/logspout
  hostname: logspout
  command: logstash://logstash.docker:5000
  restart: always
  dns: 172.17.42.1
  ports:
    - "8003:8000"
  volumes:
    - /var/run/docker.sock:/tmp/docker.sock

doorman:
  image: zinvoice/doorman
  hostname: doorman
  restart:  always
  dns: 172.17.42.1
  ports:
    - "8085:8085"
# inherited
elasticsearch:
  extends:
    file: ../common.yml
    service: elasticsearch

logstash:
  extends:
    file: ../common.yml
    service: logstash

kibana:
  extends:
    file: ../common.yml
    service: kibana

logspout:
  extends:
    file: ../common.yml
    service: logspout

doorman:
  environment:
    - DOORMAN_GITHUB_APPID=xxxxxxxx
    - DOORMAN_GITHUB_APPSECRET=xxxxxx
  links:
    - nginxtrusted
  extends:
    file: ../common.yml
    service: doorman

因此,我的建议修复泊坞窗扩展了它的详细程度。 您甚至不必编写太多代码,因为YAML提供了您需要的所有功能。 如果您坚持使用标准YAML,则可以通过其他工具和UI来分析或创建文件。

看一下YAML“节点锚点”和YAML“文件合并”,它可能是完美的解决方案。

仅供参考:这种讨论现在在#1380上持续进行

@ Vad1mo我同意extends与您的情况不符。 我们可以做很多事情来改善这种体验-您可以为此另开一个问题,所以我们在这里不会被束缚吗?

当然! 我只是想强调一下这可能是一个简单而优雅的选择。
如果composeextends使您无法通过变量传递的一半,那么改进的compose-extends将使变量传递过时。 少了一些要理解的概念会使用户更容易。

我的用例是在volumes允许$PWD ,这样团队中的每个开发人员都可以将仓库克隆到任何地方,并且路径仍然可以正确安装。

elasticsearch:
  image: zinvoice/elasticsearch
  volumes:
    - $PWD:/app

@mattes我相信已经支持了,我认为也支持.:/app

@aanand作为PoC,我使用Python编程。 对于星期六。

@kojiromike看起来很棒。 让我知道您是否打算继续进行下去。

@aanand我打算这样做,但是现在肯定有一些错误(并且我认为使用shlex可能不是一个好主意)。 当然,欢迎提供错误报告和P​​R。

@dnephin $HOME / ~怎么样?

@nafg卷的主机路径均支持这两种方式

@dnephin有趣,b / c最终以一个名为“ $ HOME”的目录结束了...

@aanand像“ $ { VARIABLE:default }”建议一样,使用global_extends(或“ import”),这将变得非常强大。

问:这是否允许指定暴露给主机的端口号? 像-“ $ {WEB_ PORT:80 }:80”?
用例是为了能够轻松启动同一台计算机/集群上某个应用程序的多个实例,通常侦听不同的端口或分配给不同的本地域名。

是的,您将能够做到这一点。

我想与docker-compose scale my_app=3一起在卷中使用vars。 我有这个docker-compose.yml

server:
  image: alexanderilyin/docker-teamcity-server
  ports:
   - "8111:8111"
  volumes:
    - .TeamCity:/root/.BuildServer
  links:
   - mysql
mysql:
  image: alexanderilyin/docker-mysql
  volumes:
    - .MySQL:/var/lib/mysql
  environment:
    MYSQL_DATABASE: teamcity
    MYSQL_USER: teamcity
    MYSQL_PASSWORD: teamcity
    MYSQL_ALLOW_EMPTY_PASSWORD: yes
agent:
  image: alexanderilyin/docker-teamcity-agent
  links:
   - server

我希望能够为代理使用scale并为它们使用动态卷以在两次启动之间保留数据,例如:

agent:
  image: alexanderilyin/docker-teamcity-agent
  volumes:
    - .agent_{$AGENT_INSTANCE_ID}:/opt/buildAgent
  links:
   - server

我希望也可以将变量插值作为图像名称的一部分
我们正在使用https://github.com/openshift/source-to-image在CI上为每个分支构建本地容器,然后使用docker-compose在其上运行测试。
使用docker-compose运行带有动态图像的测试非常复杂,并且需要手动渲染模板..:-1:

但是您可以设置COMPOSE_PROJECT_NAME来控制每次运行的前缀,这样就可以做到了吗? 如果是这样,则无需在名称周围使用复杂的逻辑和不可读的yml文件。

@andrerom不要关注。 根据控制以下Sets the project name, which is prepended to the name of every container started by Compose文档,而我们尝试设置image属性:

web:
  image: <I_AM_DYNAMIC>

啊,我的错。

以为你的意思

<I_AM_DYNAMIC>:
  image: nginx

动态图像(和构建)参考确实很有意义。 例如,在您的编程语言的调试和非调试基础容器之间进行切换将是一个很好的用例。

其他用例_(这可能是@ Maxim-Filimonov想到的)_:能够覆盖要使用图像的标签,因此默认情况下可以使用:latest,但可以更改以轻松测试其他内容而无需更改yml文件_(基本上是CI用例所需)_。

@andrerom正是我们的用例:+1:

这也适用于类似的事情吗?

web:
  environment:
    - FOO=${whoami}

@ k0377我认为它们不会,因为那确实是由Shell处理的,但是您可以将结果添加到环境变量中并使用它。

在这种情况下, $USER环境变量可能会给您相同的效果。

@aanand为什么不使用任何现有的现有模板引擎? Jinja2在那并且工作正常。

如前所述-实现我们自己的模板并非易事(正则表达式也不是很酷),因此我们应该使用已经存在的,证明可靠的模板。

另外,我们可以使用YAML ancors和参考https://gist.github.com/bowsersenior/979804

但是,然后我们就限制了变量的使用(将变量名称注入内容的中间)。

+1为Jinja2:它肯定适合模具,并且可以将其用于
正是该用例(在yml文件中进行模板制作)

在2015年5月26日星期二下午1点25分,tonnzor [email protected]写道:

@aanand https://github.com/aanand为什么不使用任何现有模板
已经存在的引擎? Jinja2在那并且工作正常。

如前所述-实现我们自己的模板并非易事
(而regexp不是那么酷),所以我们应该使用已经存在的,
被证明是可靠的。

-
直接回复此电子邮件或在GitHub上查看
https://github.com/docker/compose/issues/1377#issuecomment -105493447。

Jinja2比我们需要做的更多:

  • 有条件的
  • 循环播放
  • 扩展/继承
  • 评论
  • 过滤器

我们不会在Compose中添加任何内容。 如果Jinja2可以配置为仅插值变量,则它可能是候选值。

实际上,循环可能很有趣。

假设您有一个要为其启动容器的客户列表
在其中将一些客户特定的变量放入环境中。

扩展/继承可能对增强当前功能很有趣
基本的扩展机制。

过滤器可以很好地处理现有变量。

2015年5月26日星期二,下午1:56,Aanand Prasad [email protected]
写道:

Jinja2比我们需要做的更多:

  • 有条件的
  • 循环播放
  • 扩展/继承
  • 评论
  • 过滤器

我们不会在Compose中添加任何内容。 如果可以配置Jinja2
只是插值变量,那么它可能是一个候选者。

-
直接回复此电子邮件或在GitHub上查看
https://github.com/docker/compose/issues/1377#issuecomment -105498909。

它们可能是有趣的功能,但是它们带来的复杂性远比我舒适地介绍Compose和文件格式时要复杂得多,并且我们都将它们与特定的模板语言(据我所知)绑定在一起而且没有规格。 这根本不可行。

@aanand这里的一些注释:

  1. Jinja2是可靠的,并且需要几分钟来进行YAML的预处理:

从jinja2导入模板
template = Template('你好{{name}}!')
template.render(name =“ Aanand”)
你好阿南德!

如果需要更高的安全性,可以使用不可变的沙箱:

从jinja2.sandbox导入ImmutableSandboxedEnvironment
env = ImmutableSandboxedEnvironment()
template = env.from_string('你好{{name}}!')
template.render(name =“ Aanand”)
你好阿南德!

在我们的情况下是:

导入操作系统
从jinja2.sandbox导入ImmutableSandboxedEnvironment
env = ImmutableSandboxedEnvironment()
template = env.from_string('你好{{name}}!')
template.render(** os.environ)

  1. 我们不想要过滤器吗? 使用过滤器,您可以轻松定义默认值({{value | default(“ default”)}})
  2. 我们真的需要关心使用扩展Jinja功能来固定YAML文件的用户吗? 以相同的方式,用户可以手动生成无效的YAML文件。 我认为我们应该保持简单-尝试处理给定的Jinja模板,如果出现错误或产生的YAML无效,则返回错误(与现在相同)。
  3. 如果您不认为Jinja2是解决方案,那么至少使用{{variable}}作为语法会更好。
  4. Django使用regexp解析并生成模板。 它是生产级的,并且可以长期使用。

导入操作系统
汇入
template =“你好{{name}}!”
re.sub(“ {{\ s _([a-zA-Z0-9 _] +?)\ s_}}”,lambda m:os.environ.get(m.group(1),''),模板)

无论如何-无论采取什么解决方案,我们都需要滚动此功能。

如果考虑使用模板,我+1使用通用模板解决方案。 例如http://mustache.github.io ,它可以使用多种语言。 这只是一个例子,其他模板引擎也可以同样考虑

@aanand我完全理解你的意思。 我也喜欢简单和
撰写dsl的简洁性。

元作者说,也许这应该作为一个外部项目来完成。 它
接受compose.tpl.yml和variables.yml,创建docker-compose.yml
然后我们走了。
正如@tonnzor所示,可以用

这将为有需要的人提供强大的模板
为简单任务引入复杂性。

2015年5月26日,星期二,下午4:52,Sebastiaan van Stijn <
[email protected]>写道:

如果模板是,我+1使用_generic_模板解决方案
考虑过的。 例如http://mustache.github.io ,许多版本都有
语言。 这只是一个例子,其他模板引擎可以
平等地考虑

-
直接回复此电子邮件或在GitHub上查看
https://github.com/docker/compose/issues/1377#issuecomment -105551631。

嗯……所以现在的提议是在compose.yml中使用模板语言(这是用于构成Docker容器的描述性语言),用于commandentrypoint ,它们已经接受了execsh -c样式值? 这可能会造成混淆,因为在模板渲染之后,仍然可以解释生成的shell命令,因此,如果变量碰巧扩展到* ,它将进一步进行全局扩展。 当您具有如此多的穿插式解释层时,用一种或另一种语言转义序列变得棘手。

@kojiromike我不确定是否需要模板引擎,但是如果要使用它的

2015年5月26日星期二,上午11:02 Christoph Witzany [email protected]
写道:

@aanand我完全理解你的意思。 我也喜欢简单和
撰写dsl的简洁性。

元作者说,也许这应该作为一个外部项目来完成。 它
接受compose.tpl.yml和variables.yml,创建docker-compose.yml
然后我们走了。

您无需任何新项目即可立即完成操作。 我相信神社可以
从命令行以某种方式调用。 我个人只是使​​用envsubst
命令。

真正有用的是,如果compose可以从stdin中读取文件。
那将消除对中间文件的需要。

正如@tonnzor所示,可以用

这将为有需要的人提供强大的模板
为简单任务引入复杂性。

2015年5月26日,星期二,下午4:52,Sebastiaan van Stijn <
[email protected]>写道:

如果模板是,我+1使用_generic_模板解决方案
考虑过的。 例如http://mustache.github.io ,许多版本都有
语言。 这只是一个例子,其他模板引擎可以
平等地考虑

直接回复此电子邮件或在GitHub上查看
https://github.com/docker/compose/issues/1377#issuecomment -105551631。

直接回复此电子邮件或在GitHub上查看
https://github.com/docker/compose/issues/1377#issuecomment -105554730。 src =“
https://ci6.googleusercontent.com/proxy/iSBXyl7D8PwFM4p1mGPHCR7bQctunieGbhyGkvo0QIMIjmAYE3I0Mt96yl1fGrqcuOzxV4APP8ZRIw-5_qd6nzps9Mpr6jTAydCC4xs8JDgqm93aIbWvN1eMlxykrz7iwYooyAQdqL4RFJokeEbnBkZm5mhgKg=s0-d-e1-ft#https://github.com/notifications/beacon/AAGAUO8xqz29B2SUoG7QFPUy848_JJW9ks5oNIJlgaJpZM4EMysO.gif
“>

+1用于从stdin读取文件。 我使用外部模板解决方案没有问题,但是周围没有中间文件会很好。

这听起来像迈出了第一步,也是许多cli工具的共同特征。 来做吧

:+1:

所以举个例子

envsubst compose.tmpl.yml | docker-compose -f - up -d

wfm。 :+1:

刚刚注意到docker / distribution通过环境变量处理yml文件中的重载值,但是使用了不同的方法https://github.com/docker/distribution/blob/master/docs/configuration.md#override -configuration-options

^^ @aanand

@thaJeztah也对我们

DOCKER_COMPOSE_IMAGE_NAME='my_image:is_dynamic'

有趣的方法,但我不喜欢-冗长的环境变量名称,如果要在多个位置使用一个值,则要进行很多重复,所有内容都是隐式的,字符串中没有内插。

@aanand也没有真正采用这种方法,但是想指出这一点,因为它是“ Docker”组织中的另一个项目。

刚在https://github.com/kelseyhightower/confd上偶然发现,可能会很感兴趣。 它使用http://golang.org/pkg/text/template/#pkg -overview

不幸的是, @olalonde

@aanand我对您的原始建议+20,但有一点调整,即使是图像,尤其是标签也应该可以注入。 只是去做,将为我们所有人节省大量包装器和不必要的配置处理;)

我写了一个小小的python软件包来帮助我。 计划是将所有命令通过隧道传送到docker compose,以便您可以等效地使用它。
https://github.com/webcrofting/meta-compose/中查看

元组成看起来真的很好。 它应该集成到docker-compose!

这里的大+1 -我对模板预处理并不感到兴奋,但是以一种或另一种方式拉动环境变量会很棒。 POSIX扩展可能比Jinja2干净,但是任何一种方式都可以。

也是这里的大+1。 我的用例更多是为kafka容器添加动态广告ID支持,这对数据生产者(可能是其他容器)至关重要。

我也对此功能感到兴奋。

POSIX扩展可能比Jinja2干净,但是任何一种方式都可以。

我认为支持POSIX扩展的另一个论点是它没有逻辑。 Jinja2支持某种程度的条件/循环逻辑(就像大多数模板引擎一样,甚至声称是“无逻辑”的引擎)。 根据我的经验,将模板逻辑与YAML混合使用非常奇怪。 有人能想到这种逻辑的用例吗? 如果没有,那么最好最好是暂时避免支持。

希望开发人员对此功能有一个明确的答案。 阅读各种问题和PR,尚不清楚您是否真的想实现它。

如果可以,采用哪种机制? 如果您不这样做,人们可以开始构建一些第三方工具来管理该功能。

谢谢 !

好的,我刚刚看到https://github.com/docker/compose/pull/76。 我想答案就在那里...

在链接的问题/ PR上走了几个周期。

AFAIK,nginx社区拒绝为配置文件采用任何模板引擎,即使是简单的变量替换。 为什么? 也许,他们仍然在选择理想的模板引擎:微笑:。 结果? 疼痛(相对)!

@哈迪姆

阅读各种问题和PR,尚不清楚您是否真的想实现它。

本问题应该为该问题提供明确的答案,所以对不起我未能弄清楚:是的,我们要使用POSIX样式的语法来实现它。

谢谢@aanand

谢谢,@ aanand。

为我+1。 我需要传递--dns =(docker0网桥的地址),并且如果将来的docker版本发生更改,我需要它工作,因此环境变量和/或shell是完美的。 meta-compose对我不起作用,因为它应该支持远程DOCKER_HOST,例如通过docker-swarm支持,而不仅限于本地。

:+1:这将非常好。 目前,我要么最终通过另一个脚本生成了.yml文件,要么就是完全不使用docker-compose,而是手动--link-ing dockers。

:竖起大拇指:

我认为基本环境变量插值对于简单的事情将非常有用。

几个简单的用例:

  • 能够动态指定要从远程存储库提取的图像标签。
  • 能够设置容器的端口映射。

像Ansible这样的工具已经可以很好地进行模板化,因此我不确定是否需要完整的模板引擎。 但是在comose.yml文件中不能包含任何动态内容是非常有限的。

关于合并的PR#1488,我特别希望将配置文件传送到docker-compose 。 我不明白为什么docker-compose无法从节点进程中提取。

var spawn = require('child_process').spawn;

var compose = spawn('docker-compose', ['--file' + '-' + 'up']);

compose.stdin.setEncoding = 'utf-8';

compose.stdout.on('data', function (data) {
    console.log('"docker-compose --file - up" stdout: "%s".', data);
});

compose.stderr.on('data', function (data) {
    console.log('"docker-compose --file - up" returned an error: "%s".', data);
});

compose.on('close', function (code) {
    if (code !== 0) {
        console.log('"docker-compose --file - up" existed with an erroneous code: "%s".', code);
    } else {
        console.log('"docker-compose --file - up" existed with code: "%s". SUCCESS!', code);
    }
});

compose.stdin.write("redis: {\"image\": \"redis\"}\n");
compose.stdin.end();

关于如何从Node.js传递数据的任何示例?

我发现的另一件事是docker-compose 1.4.0-RC1正在向stderr而不是stdout发送一些看似正常的消息,例如Starting...Attaching... stdout

@kadishmal请问您可以为这些问题单独打开吗?

另一个候选语法/实现: PEP 0292中指定并在string.Template中实现的Python字符串模板。

与POSIX参数扩展非常相似:

  • $foo扩展为foo
  • ${foo}扩展为foo
  • $${$}${}${foo$ {foo}${ foo}${foo }是错误

缺点:

  • 没有默认值或“必需值”语法。 不过,我们可以稍后决定是否需要编写自己的模板代码的优点。
  • 错误消息不会公开任何有关语法错误位置的机器可读信息(即,不对错误字符串执行正则表达式匹配)。
  • 转义语法与POSIX不同: $$而不是\$

这实际上可能是变相的祝福:YAML不喜欢\$ ,并且要求您两次转义。 我认为告诉人们输入\\$只是为了获得一个美元符号不会飞。

我已经在#1765中实现了一个实现。

+1

我不确定这是否是正确的选择,还是应该发行新刊物。

我认为env优先级应该是相反的,也就是说,shell中调用docker-compose的变量应覆盖docker-compose.yml中的任何变量,而后者又应覆盖容器定义的任何变量。

这是我尝试时当前发生的情况:

docker-compose.yml:

test:
    image: ubuntu
    environment:
        - FOO="from compose"

然后使用env命令运行它:

docker-compose run test env | grep FOO

给出FOO="from compose" ,如预期的那样。 但是之后:

FOO="from shell" docker-compose run test env | grep FOO

还给出了FOO="from compose" ,但是在这里我期望的是FOO="from shell"

某些人可能还需要在其他用例中使用变量插值,但更改此选项将满足“默认”用例-docker-compose.yml中的environment:定义/值实际上是默认值,可以覆盖它如果需要,可以在运行时运行,而无需任何其他YAML语法。

@fazy您没有考虑到env命令是在隔离的test容器中执行的,其中FOO的值为from compose (只是(应在docker-compose文件中配置)。 但是在该容器之外,如果docker-compose进程为您设置的环境变量提供了某种打印功能,那么在该命令将“从外壳”打印出来之前,它是主机的值(以及docker-compose进程)中运行它。 在这种情况下,您可能希望FOO价值为from shell ,但就我个人而言,如果真的如此,我会感到非常惊讶。 (我希望尽管我英语也能理解我的意思)。

@smileart谢谢,我想我明白您的意思。

但是, test容器不是完全隔离的,它是从docker-compose获得其环境的(或者至少docker-compose能够将环境变量设置到启动的容器中),而docker-compose本身可以看到“外部”环境变量。

您可以通过以下docker-compose.yml查看:

test:
    image: ubuntu
    environment:
        - FOO

然后命令:

FOO="from shell" docker-compose run test env | grep FOO

确实给出了“ from shell”的结果。

所以我的问题是关于优先权。 通过仅在此处指定变量名- FOO ,我可以从外部注入变量。 但是,如果我指定- FOO=something _and_从外部注入变量,哪个应该优先? 恕我直言,在命令行上指定的变量应优先于配置文件。

@fazy哦,对不起,我没有尝试FOO="from shell" docker-compose run test env | grep FOO而不在docker-compose.yml指定它的值,而且我不知道它给了我们主机的FOO值。 所以这不仅对我来说已经很奇怪了:笑脸:我认为在docker-compose之前设置一个环境变量只会影响docker-composedocker-compose而不会将其扔到容器。 现在我明白你的意思了。

我只是偶然发现了转义https://github.com/docker/compose/issues/1377#issuecomment -124571722中提到的$缺点。 首先,我只做了FOO=ba$e然后是FOO='ba$e' (忘记了它是“裸”),然后是FOO=ba\$e ,然后是FOO=ba\\$e ,然后我放弃了,去了文档,只是惊讶地发现“ $$的转义字符”。 对我来说,这并不是特别“最少的惊喜”。

但是,我不知道好的解决方案是什么。

@ ct-clearhaus Compose不是唯一使用$来转义$ 。 您还将在makefiles中找到它。 因此,对于某些人来说,这种习语非常熟悉。

我喜欢现有的变量替换实现。 但是我真的可以根据@aanand的原始建议使用设置默认值的功能。 我认为POSIX语法是完美的:

${ENV-default}

我的特定用法是我希望能够指定运行该服务的主机端口:

PORT=8123 docker-compose up

通过将其添加到我的docker-compose.yml

web:
  ports:
    - "${PORT-8000}:5000"

该功能仍在计划中吗?

我尝试通过extends解决我的问题,但是它很混乱。 我不仅要复制几乎所有docker-compose.yml只是为了更改一个设置,还没有办法更改暴露的端口设置,您只能add to暴露的端口列表,对我来说并不理想。

当未设置环境变量时,为什么docker-compose不会失败? 它只是记录警告并继续。 不仅仅是返回错误是更好的方法...
WARNING: The FOO variable is not set. Defaulting to a blank string.

+1用于POSIX语法以声明默认值

也许我缺少明显的东西,但是我希望能够使用env_file中的环境变量来设置环境变量的值,例如:

docker-compose.env:

DB_PASSWORD=test

docker-compose.yaml:

...
service:
    database:
        env_file:
            - ./docker-compose.env
        environment:
            - MYSQL_PASSWORD=${DB_PASSWORD}
    webserver:
        env_file:
            - ./docker-compose.env
        environment:
            - WORDPRESS_DB_PASSWORD=${DB_PASSWORD}

可以通过其他方式完成吗? 我不想有一个需要通过envsubst传递的Yaml模板文件。

为什么不按照您希望的方式直接将这个值放在env_file中呢?

2636将支持环境文件的默认值

这意味着在两个地方都必须有一个值必须相同的变量,如果只需要更改一个,它会变得更加容易。 #2636看起来很有前途。

现在迫切需要一种机制来支持默认变量,因为现有的限制迫使我们使用包装器脚本来帮助docker-compose。 我需要像NODE_ENV=${NODE_ENV:-dev}这样的东西来工作,为了方便起见,最好让SOME_NUMBER=$((96*60))来工作。 这是预定即将发布的版本吗?

+1为默认值

+1为默认值。 这对我们来说变得至关重要。

我同意@ darkn3rd-我需要获取用户ID和用户组ID才能在容器中进行设置。 我发现的唯一方法是强制我的团队导出2个变量...或使用我制作的makefile导出设置它们。

如果可以的话:

    user: $((id -u)):$((id -g))

可以解决我所有的问题

@mgor听起来就像您可以将其传递给envsubst吗?

env $(cat docker-compose.env | xargs) envsubst < docker-compose.tmpl > docker-compose.yml

我认为应该这样做(不污染持久性环境)。

@OJFord @mgor无意劫持线程,但我构建了一些CLI工具来envsetslv

envset development -- slv docker-compose.tpl > docker-compose.yml

envset会将变量从env文件加载到当前的shell会话中,slv使用环境变量进行模板替换。

我同意@OJFord,但这不是我所需要的...
让我精确地说:我们是一个由40个开发人员组成的团队,他们使用不同的docker-compose堆栈。 我们正在使用git来获取代码。

如果我要求他们修改git传递的docker-compose.yml,那么我确定有人会推送修改后的docker-compose.yml文件...相信我,情况就是如此。

我可以“生成一个基本的作曲家文件”,它会被git忽略,并被docker-compose.yml扩展,但是要生成它,我需要给它们一个Makefile或bashscript。 docker file”需要更改,并且团队不会意识到他们将需要重新运行生成。

同样适用于“ env”文件,非常好,但是它不适用于“ build”,因此我需要请我的团队生成此文件。

真的,如果docker-compose可以从yaml文件中的bash(或其他返回ENV var的其他解决方案)中获取值,则可以解决很多需求。

在上一个命令中,我的示例是一个完美的示例:我需要获取用户ID和GID,而这些值不是由ENV vars设置的。 因此,我需要请我的团队将其ID写入.env文件中。

精确地说:我需要提供一个docker-compose文件,该文件不应由团队更改,因为它位于git存储库中。

这个pull-request是一个对我有用的简单示例。 也许您可以帮助我做得更好。

我尝试使用docker-compose.yml文件中的环境和用户指令。 目前运作良好。

默认值应该在那里...非常有用...开发人员和OPS正在使用docker日志或syslog ...因此,他们通常必须创建如下所示的默认

default:
  extends:
    file: base.yml
    service: base-${LOG_FORMAT:docker}
  labels:
    - "net.company.npmjs.datacenter=${DATA_CENTER}"
    - "net.company.npmjs.env=${ENV}"
    - "net.company.npmjs.hostname=${HOSTNAME}"
    - "net.company.npmjs.role=${NPMO_ROLE}"
    - "net.company.npmjs.log=${LOG_FORMAT}"

base-syslog:
  log_driver: syslog
  log_opt:
    tag: "{{.ImageName}}/{{.Name}}/{{.ID}}"

base-docker:
  log_driver: json-file
  log_opt:
    max-size: "128m"
    max-file: "4"

什么时候可用? 我在撰写1.7.0,这仍然不存在:(

请请给我们默认值!

@marcellodesales :也许您可以通过某种方式利用docker-compose.override.yml文件。 检查该功能。

同时在环境变量上+1。 这是当今使用docker-compose的主要痛点。

我会坚持要求我的PR#3367能够从主机获取某些值。 :)

@pataquets我不认为我想创建其他覆盖文件...我们的base.yml文件,如上所示,显示了记录程序驱动程序等所有受支持的内容...我只想切换并具有默认值。 我认为我们需要维护更多的yml文件。 但是我会记住这一点,以防万一。

+1

+1

+1

+1

关于docker-compose中使用环境变量的任何通知吗?

+1

+1

仅供参考:从1.7.0版开始,用于docker-compose的环境变量。 您还可以在根目录docker-compose.yml所在目录的.env中设置docker-compose默认变量。 这不要与docker engine envfiles混淆,因为那是另一回事。

有没有一种方法可以将服务名称设置为变量?

而不是写这个

services:
   site_db:
     image: mysql:5.7

我们可以写

services:
   ${CONTAINER_NAME}:
     image: mysql:5.7

我的目标是在多个站点中保持相同的docker-compose.yml ,并且只更改.env文件。 现在,我仍然需要修改容器名称,因为我正在同一主机上运行多个应用程序。 为了清楚起见,我希望每个服务都有自己的名称。

您可以使用@LouWii

services:
    site_db:
      container_name: "${CONTAINER_NAME}"
      image: mysql:5.7

或(撰写文件格式为2.1及更高版本)

services:
    site_db:
      container_name: "${CONTAINER_NAME:-defaultname}"
      image: mysql:5.7

但是为什么不设置项目名称呢? 为此,项目名称为_intended_,因为它为创建的容器名称加上前缀/名称空间,以防止与同一主机上的其他项目发生冲突。 参见https://docs.docker.com/compose/reference/envvars/#/composeprojectname

@thaJeztah谢谢! 我仍在学习Docker和docker的工作方式。 设置项目名称似乎是一个更好的选择,在我的使用中完全有意义。

有没有什么办法可以在插补括号内编写脚本? 例如${HOST_PORT + 1}

您可以通过Jinja或其他方式通过管道传输文件...

2017年1月24日星期二,上午5:36 Sam A.Horvath-Hunt [email protected]
写道:

有没有什么办法可以在插补括号内编写脚本? 例如$ {HOST_PORT

  • 1}。

-
您收到此邮件是因为有人提到您。
直接回复此电子邮件,在GitHub上查看
https://github.com/docker/compose/issues/1377#issuecomment-274767368
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAGAUN5ZrU39dnVVVASwIHr5mGqJFxh3ks5rVdRIgaJpZM4EMysO

我能逃脱$吗?

environment:
   PATH: "$PATH:/home/appuser/.bundler/bin"

当前,这导致插值主机的PATH变量,而不插值容器

是仅找到一个docker-compose.yml文件吗?
我如何添加或修改它?
提前致谢

@logicminds虽然我找不到任何地方的文档,但我发现$$插值到一个逃逸的$

environment:
   PATH: "$$PATH:/home/appuser/.bundler/bin"

@elquimista有一个我发现有用的解决方案https://github.com/mhart/alpine-node/issues/48#issuecomment -430902787

此页面是否有帮助?
0 / 5 - 0 等级