【问题标题】:Docker on EC2, RUN command in dockerfile not reading environment variableEC2上的Docker,dockerfile中的RUN命令未读取环境变量
【发布时间】:2017-03-18 14:03:10
【问题描述】:

我在 AWS 上有两个 elastic-beanstalk 环境:开发和生产。我在每个实例上运行 glassfish 服务器,并要求在生产和开发环境中部署相同的应用程序包,而不需要两个不同的 .EAR 文件。两个实例的大小不同:开发人员有一个微型实例虽然生产有一个中等实例,因此我需要为 glassfish 部署两个不同的配置文件,每个环境一个。

主要问题是该文件必须在服务器启动之前位于 glassfish 配置目录中,因此我认为在创建容器时移动它会更好。

当然每个环境都使用一个 docker 容器来托管 glassfish 实例,所以我的第一个想法是为 elastic-beanstalk 配置一个环境变量。在这种情况下

ypenvironment = dev

用于开发环境和

ypenvironment = pro

用于生产环境。然后在我的 DOCKERFILE 中,我将这条语句放在 RUN 命令中:

    RUN if [ "$ypenvironment"="pro" ] ; then \
        mv --force /var/app/GF_domain.xml /usr/local/glassfish/glassfish/domains/domain1/config/domain.xml ; \
    elif  [ "$ypenvironment"="dev" ] ; then \
        mv --force /var/app/GF_domain.xml.dev /usr/local/glassfish/glassfish/domains/domain1/config/domain.xml ; \
    fi

很遗憾,启动完成后,两个 GF_domain 文件都还在var/app

然后我发现 RUN 命令在容器完全加载之前运行东西,可能缺少 elastic-beanstalk-injected 变量。所以我试图将代码移动到 ENTRYPOINT 指令。再次没有运气,容器启动失败。也试过了

ENTRYPOINT ["command", "param"]

语法,但给出一个

不起作用
System error: exec: "if": executable file not found in $PATH

所以我被卡住了。

【问题讨论】:

    标签: amazon-web-services docker amazon-elastic-beanstalk


    【解决方案1】:

    你需要:

    1/ 使用入口点(或至少使用sh -c 'if...' 语法):即用于运行时执行,而不是编译时映像构建。

    2/ 使用build-time variables (--build-arg):

    您可以在 Dockerfile 中使用 ENV 指令来定义变量值。这些值保留在构建的映像中。
    然而,坚持往往不是你想要的。用户希望根据他们构建映像的主机来指定不同的变量。

    一个很好的例子是http_proxy 或用于拉取中间文件的源版本。 ARG 指令允许 Dockerfile 作者定义用户可以在构建时使用 --build-arg 标志设置的值:

    $ docker build --build-arg HTTP_PROXY=http://10.20.30.2:1234 .
    

    在您的情况下,您的 Dockefile 应包括:

    ENV ypenvironment
    

    然后docker build --build-arg ypenvironment=dev ... myDevImage

    您将构建 2 个不同的镜像(基于相同的 Dockerfile)


    我需要能够在开发和专业环境中使用相同的 EAR 包,

    然后您希望您的 ENTRYPOINT 在运行时根据环境变量的值移动文件。

    你的 Dockerfile 仍然需要包含:

    ENV yp环境

    但您需要使用

    运行您的一张图片
    docker run -x ypenvironment=dev ...
    

    确保您的脚本(由您的入口点引用)包含您在问题中提到的 if [ "$ypenvironment"="pro" ] ; then...,以及您的应用的实际启动(在前台)。
    您的脚本需要立即退出,否则您的容器将在启动后立即切换到退出状态。

    【讨论】:

    • 对不起,不清楚,但我试图避免两种不同的构建。我需要能够在开发和专业环境中使用相同的 EAR 包,但是在 elastic-beanstalk 中您只能部署一个 EAR 文件,而该文件又必须包含 DOCKERFILE。也许有一种方法可以在运行 docker build 命令的上下文中获取环境变量值,但我不知道。我会尽快修改我的问题,谢谢!
    • @Gabber 所以你说的是运行时,而不是构建时间(Dockerfile)?
    • @Gabber 我已经编辑了我的答案以包含运行时语法
    【解决方案2】:

    使用 Docker 时,您必须区分构建时操作和运行时操作。 Dockerfile 用于构建 Docker 映像,而不是用于部署容器。这意味着 Dockerfile 中的所有命令都会在您构建 Docker 映像时执行,而不是在您从该映像部署容器时执行。

    CMDENTRYPOINT 命令是特殊的构建时命令,它们告诉 Docker 在从该映像部署容器时要执行什么命令。

    现在,在您的情况下,更好的方法是检查 Glassfish 是否支持 domain.xml(或其他地方)内的环境变量。如果是这样,您可以在两个环境中使用相同的 domain.xml 文件,并为这两个环境使用相同的 Docker 映像。然后,您可以通过在本地运行时使用 docker run -e "VAR=value"run-time 环境变量注入容器来区分环境,并在部署时使用 Environment Properties 配置部分弹力豆茎。

    编辑:如果您不能在 domain.xml 中使用环境变量,您可以通过使用读取运行时环境变量并将其值放入使用seddomain.xml 中正确放置,然后照常启动您的应用程序。您可以在this post 中找到示例。

    【讨论】:

    • 这不是我要求的,而是我需要的。谢谢:)
    • 对不起,我尝试了这个解决方案但是没有用,恐怕无法让 Glassfish domain.xml 文件从 aws 环境中读取变量,因此无法接受作为正确答案
    • 那么对于这些​​情况还有另一种解决方案。我已经更新了我的答案。祝你好运:-)
    • 我已经检查了解决方案(尚未测试),但我不确定我是否理解正确。我有一个疑问:在 dockerfile 中,我放置了一个命令来根据环境变量复制一个文件或另一个文件。我已经为此脚本尝试了 ENTRYPOINT 和 RUN 命令。这不起作用,因为尚未设置环境变量。如果“if”语句不能,为什么“sed”命令要获取值?我认为这里的问题是我运行命令时尚未设置环境变量,所以我担心这不起作用
    • @Gabber,我说的是使用 run time 环境变量 (docker run -e "MYVAR=myvalue") 和启动脚本(应该使用 ENTRYPOINT 或 @ 设置) 987654332@)。启动脚本将执行类似sed -i 's/foo/$MYVAR/g' domain.xml.
    猜你喜欢
    • 2022-08-16
    • 2018-10-16
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    相关资源
    最近更新 更多