如何从docker-compose将环境变量传递给Docker RUN命令?

12

我有一个Docker化的应用程序,我希望在代理和非代理主机环境中都能运行。我正在尝试通过在容器中复制普通环境变量(例如http_proxy),仅在主机中存在时才进行复制,以解决此问题。

通过运行以下命令,我可以完成90%的工作:

set | grep -i _proxy=>proxies.env

在一个顶层脚本中编写,然后在我的docker-compose.yml文件中包含:

myserver:
  build: ./myserver
  env_file:
   - proxies.env

如果有主机的环境代理变量,该命令会将这些变量复制到服务器容器中,并且这些变量在容器运行时可用。换句话说,在Dockerfile CMD或ENTRYPOINT执行阶段时,这些变量是存在的。

然而,我有一个容器需要在Dockerfile中通过RUN命令运行npm构建步骤,但是似乎在此阶段这些变量并不存在,因此npm无法找到代理并停止运行。换句话说,如果我有:

RUN set

在我的Dockerfile中,我看不到来自proxies.env的任何变量,但如果我执行

docker exec -it myserver /bin/bash

然后运行set命令,我可以从proxies.env中看到所有内容。

有人可以推荐一种方法,在容器构建时使这些变量可见,而无需硬编码它们,以便我的docker-compose.yml和Dockerfile仍然适用于具有代理和没有代理的主机吗?

(在centos 7,docker-compose 1.3.1和docker 1.7.0下运行)


用预定义的环境变量生成Docker文件对我来说似乎是最简单的方式。 - Abdullah Jibaly
你说得很对。如果没有更好的建议,我会编写一个shell脚本,使用sed命令来填充或注释硬编码的NPM sed设置,这样我就可以在云端和公司主机上使用同一个Dockerfile。 - Francis Norton
2
更新:使用 docker-compose.yml 版本 2(docker 1.10+),现在您有更好的选择:build:/args:。请参见我的答案 - VonC
5个回答

32

更新于2016年,docker-compose 1.6.2,docker 1.10+,使用 docker-compose.yml 版本2:

现在有了build:部分中的子部分 args:其中包括了非常有趣的可能性:

仅有键的构建参数会被解析为Compose所运行机器上的环境变量值。.

参见PR 2653(2016年1月)

因此,一种在docker-compose.yml文件中不需要硬编码引入代理变量的方法是使用精确的语法:

version: '2'
services:
  myservice:
    build:
      context: .
      args:
        - http_proxy
        - https_proxy
        - no_proxy
在调用docker-compose up之前,您需要确保设置了代理环境变量:
export http_proxy=http://username:password@proxy.com:port
export https_proxy=http://username:password@proxy.com:port
export no_proxy=localhost,127.0.0.1,company.com

docker-compose up

然后您的Dockerfile将由docker-compose过程构建,自动获取代理变量值,即使docker-compose.yml没有包含任何硬编码的特定值。


1
如果主机环境无法提供构建参数并且未通过命令行界面提供,会发生什么? - Meki

6

也许你可以使用 "environment" 选项来解决问题。在你的 Docker Compose 文件中应该如下所示:

myserver:
   build: ./myserver
   environment:
   - HTTP_PROXY=192.168.1.8
   - VARIABLE=value
   - ...

请问 YML 的版本是哪个? - Jaroslav Záruba

3
也许你可以尝试这样做:
在调用 RUN 之前,将 .env 文件添加到镜像中。
ADD proxies.env proxies.env

然后在你的RUN语句前面加上前缀:

RUN export `cat proxies.env` && echo "FOO is $FOO and BAR is $BAR"

这将产生以下输出:
root@armenubuntudev:~/Dockers/set-env# docker build -t ashimoon/envtest .
Sending build context to Docker daemon 3.584 kB
Sending build context to Docker daemon 
Step 0 : FROM ubuntu
 ---> 91e54dfb1179
Step 1 : ADD proxies.env proxies.env
 ---> Using cache
 ---> 181d0e082e65
Step 2 : RUN export `cat proxies.env` && echo "FOO is $FOO and BAR is $BAR"
 ---> Running in 30426910a450
FOO is 1 and BAR is 2
 ---> 5d88fcac522c
Removing intermediate container 30426910a450
Successfully built 5d88fcac522c

我们不能这样做 ENV ENV JAVA_HOME $(alternatives --list | grep javac | awk '{print $3}' | sed -e "s//bin/javac//g") 吗? - Marcello DeSales
这对我来说解决了问题 - 它使得容器在构建时可以使用环境变量。 - FeifanZ
1
这个答案解决了问题,只是需要注意这破坏了创建 docker images 的理念... - nanounanue
我必须在每个需要env文件值的单独“RUN”中进行导出。希望我们将来能找到更好的解决方案,但现在让它工作对我来说已经足够好了。 - Jared Chmielecki

2

docker-compose.yml

...
server:
  build: .
  args:
    env: $ENV
...

Dockerfile

ARG env

ENV NODE_ENV $env

这是迄今为止最好的答案。 - noun

0

这个例子修复了YUM。

version: '2'
services:  
  example-service:
    build:
      context: .
      args:
        http_proxy: proxy.example.com:80

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接