【问题标题】:How to load several environment variables without cluttering the Dockerfile?如何在不弄乱 Dockerfile 的情况下加载多个环境变量?
【发布时间】:2018-04-05 16:22:26
【问题描述】:

我正在开发一个包含大量环境变量的简单 Docker 映像。你能像 docker-compose 一样导入环境变量文件吗?我在 docker 文件文档中找不到任何关于此的内容。

Dockerfile

FROM python:3.6

ENV ENV1 9.3
ENV ENV2 9.3.4
...

ADD . /

RUN pip install -r requirements.txt

CMD [ "python", "./manager.py" ]

我想改写这个问题的一个好方法是:如何在 Dockerfile 中有效地加载多个环境变量?如果您无法加载文件,您将无法将 docker 文件提交到 GitHub。

【问题讨论】:

  • 根据您要执行的操作,--build-arg 标志到 docker build 可能有用。
  • 构建镜像需要环境变量,还是运行镜像时需要环境变量?
  • 我在运行映像时需要它们。
  • 您可以在docker run 期间执行此操作,而不是docker build。您可以使用docker run --env-file [path-toenv-file] 将环境变量从.env 文件提供给容器。

标签: docker


【解决方案1】:

是的,有几种方法可以做到这一点。

Docker 编写

在 Docker Compose 中,您可以在文件本身中提供环境变量,或指向外部 env 文件:

# docker-compose.yml
version: '2'
services:

  service-name:
    image: service-app
    environment:
    - GREETING=hello
    env_file:
    - .env

顺便说一下,一个与此相关的好功能是您可以使用多个 Compose 文件,每个后续文件都可以相互添加。因此,如果上面要定义一个基础,那么您可以这样做(例如,每个运行时环境):

# docker-compose-dev.yml
version: '2'
services:

  service-name:
    environment:
    - GREETING=goodbye

你可以这样运行它:

docker-compose -f docker-compose.yml -f docker-compose-dev.yml up

仅 Docker

要仅在 Docker 中执行此操作,请使用您的入口点或命令来运行中间脚本,因此:

#Dockerfile

....

ENTRYPOINT ["sh", "bin/start.sh"]

然后在你的启动脚本中:

#!/bin/sh

source .env

python /manager.py

我过去曾将 used this related answer 作为对自己有用的参考。

PID 1 更新

为了放大我在 cmets 中的评论,如果您将入口点设为 shell 或 Python 脚本,Unix signals(停止、杀死等)可能不会传递到您的进程。这是因为该脚本将变为 process ID 1,这使其成为容器中所有其他进程的父进程 - 在 Linux/Unix 中,期望此 PID 将信号转发给它的子进程,但除非您明确实现,它不会发生。

要解决这个问题,您可以安装一个 init 系统。我使用dumb-init from Yelp。如果您想更好地理解它,这个 repo 还包含大量详细信息,或者如果您只想“安装并忘记”,则提供简单的安装说明。

【讨论】:

  • 但问题是如果没有 docker-compose 这是否可能?如果我想要的只是这个 .env 文件,这似乎有点矫枉过正......
  • @hY8vVpf3tyR57Xib:啊,我明白你的意思了。我想知道,也许RUN source .env?或者在启动 Python 程序之前执行 CMD ["sh", "start.sh"] 执行该源命令。
  • @halfer 实际上,我会对您关于“如何正确处理 unix 信号”的建议感兴趣。我不知道你所说的愚蠢的初始化系统是什么意思。
  • @RichardKiefer:回答已编辑,如果您还有其他问题,请告诉我。
【解决方案2】:

如果您需要环境变量运行时,最简单的方法是创建一个启动器脚本,该脚本使用多个 export 语句设置环境,然后启动您的进程。

如果您需要它们的构建时间,请查看 ARGENV 语句。每个变量都需要一个。

【讨论】:

    【解决方案3】:

    有多种选择:
    https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e-env-env-file

    docker run -e MYVAR1 --env MYVAR2=foo --env-file ./env.list ubuntu bash
    

    (您也可以只引用以前的exported 变量,参见下面的USER。)

    回答您关于 .env 文件问题的答案是:

    cat env.list
    # This is a comment
    VAR1=value1
    VAR2=value2
    USER
    
    docker run --env-file env.list ubuntu env | grep VAR
    VAR1=value1
    VAR2=value2
    
    docker run --env-file env.list ubuntu env | grep USER
    USER=denis
    

    您还可以从文件中加载环境变量。此文件应使用语法variable=value(将变量设置为给定值)或variable(从本地环境获取),# 用于cmets。

    关于(图像)构建时或(容器)运行时所需的变量之间的差异以及如何将 ENVARG 组合为动态构建参数,您可以尝试以下操作:
    ARG or ENV, which one to use in this case?

    【讨论】:

      【解决方案4】:

      我真的很喜欢@halfers 的方法,但这也可以。 docker run 接受一个名为 --env-file 的可选参数,这非常有用。

      所以你的 docker 文件可能看起来像这样。

      COPY .env .env
      

      然后在构建脚本中使用:

      docker build -t my_docker_image . && docker run --env-file .env my_docker_image
      

      【讨论】:

      • VOLUME ["/conf.d", "/mnt/logs"] - 这是什么意思?
      • 啊,好球!这会将卷安装到您的 docker 容器中。这两卷将专门用于记录和监控 DataDog 等工具。
      • 是否要删除 FROM 和 VOLUME 字符串以使答案更具可读性?
      • 为什么我需要COPY .env .env? docker run 引用的 --env-file 可以有任何名称,对吗?例如。 docker run --env-file .local.env my_docker_image。我在这里遗漏了什么吗?
      猜你喜欢
      • 1970-01-01
      • 2019-09-20
      • 2013-07-28
      • 2023-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      相关资源
      最近更新 更多