如何在 docker 构建过程中使用环境变量获取脚本? [英] How to source a script with environment variables in a docker build process?

查看:68
本文介绍了如何在 docker 构建过程中使用环境变量获取脚本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个与以下 docker 项目有类似问题的图像:

I'm creating an image that has a similar problem like the following docker project:

FROM alpine:3.9.3

COPY ./env.sh /env.sh
RUN source /env.sh
CMD env

env.sh

TEST=test123

我用

docker build -t sandbox .

并运行它

docker run --rm sandbox

输出是

HOSTNAME=72405c43801b
SHLVL=1
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/

我的环境变量丢失了.

在实际项目中,我必须为 IBM DB2 客户端的安装提供更长的复杂脚本,该脚本还设置了环境变量.如何在不阅读整个安装过程并在 dockerfile 中使用 ENV 设置所有变量的情况下实现它?

In the real project I have to source a longer complex script for the installation for IBM DB2 client that also sets environment variables. How can I achieve it without reading the whole installation process and setting all variables with ENV in the dockerfile?

在实际项目中,文件 env.sh 是作为安装过程的一部分创建的,它不能从容器外部使用.环境变量的设置取决于它在其上执行的系统.如果我在主机上运行它,它会在来宾中设置错误的变量.

In the real project the file env.sh is created as part of the installation process and it is not available from outside of the container. The environment variables are set depending on the system it is executed on. If I run it on the host it will set wrong variables in the guest.

真实脚本的一部分是

if [ -f ${INST_DIR?}/tools/clpplus.jar ]; then
    AddRemoveString CLASSPATH ${INST_DIR?}/tools/clpplus.jar a
fi

if [ -f ${INST_DIR?}/tools/antlr-3.2.jar ]; then
    AddRemoveString CLASSPATH ${INST_DIR?}/tools/antlr-3.2.jar a
fi

if [ -f ${INST_DIR?}/tools/jline-0.9.93.jar ]; then
    AddRemoveString CLASSPATH ${INST_DIR?}/tools/jline-0.9.93.jar a
fi

if [ -f ${INST_DIR?}/java/db2jcc.jar ]; then
    AddRemoveString CLASSPATH ${INST_DIR?}/java/db2jcc.jar a
fi

if [ -f ${INST_DIR?}/java/db2jcc_license_cisuz.jar ]; then
    AddRemoveString CLASSPATH ${INST_DIR?}/java/db2jcc_license_cisuz.jar a
fi

它检查安装并根据此设置变量.由于主机上没有安装 DB2,因此不会设置变量.

It checks the installation and sets the variables depending on this. Since on the host is no DB2 installation the variables wouldn't be set.

推荐答案

每个 Dockerfile RUN 步骤运行一个新容器和一个新 shell.如果您尝试在一个 shell 中设置环境变量,稍后它将不可见.例如,您可以试验这个 Dockerfile:

Each Dockerfile RUN step runs a new container and a new shell. If you try to set an environment variable in one shell, it will not be visible later on. For example, you might experiment with this Dockerfile:

FROM busybox
ENV FOO=foo1
RUN export FOO=foo2
RUN export BAR=bar
CMD echo FOO is $FOO, BAR is $BAR
# Prints "FOO is foo1, BAR is "

对此有三个很好的解决方案.按照从最简单/最好到最难/最复杂的顺序:

There are three good solutions to this. In order from easiest/best to hardest/most complex:

  1. 完全避免需要环境变量.将软件安装到系统"位置,例如/usr;无论如何,它将被隔离在 Docker 映像中.(不要使用额外的隔离工具,比如 Python 虚拟环境,或者像 nvmrvm 这样的版本管理器;只需安装你需要的特定东西.)

  1. Avoid needing the environment variables at all. Install software into "system" locations like /usr; it will be isolated inside the Docker image anyways. (Don’t use an additional isolation tool like Python virtual environments, or a version manager like nvm or rvm; just install the specific thing you need.)

使用ENV.工作:

FROM busybox
ENV FOO=foo2
ENV BAR=bar
CMD echo FOO is $FOO, BAR is $BAR
# Prints "FOO is foo2, BAR is bar"

  • 使用入口点脚本.这通常看起来像:

    #!/bin/sh
    # Read in the file of environment settings
    . /opt/wherever/env
    # Then run the CMD
    exec "$@"
    

    COPY 将此脚本复制到您的 Dockerfile 中.使它成为 ENTRYPOINT;让 CMD 成为你实际运行的东西.

    COPY this script into your Dockerfile. Make it be the ENTRYPOINT; make the CMD be the thing you’re actually running.

    FROM busybox
    WORKDIR /app
    COPY entrypoint.sh .
    COPY more_stuff .
    ENTRYPOINT ["/app/entrypoint.sh"]
    CMD ["/app/more_stuff/my_app"]
    

    如果你关心这些事情,你通过这种方法设置的环境变量在 docker inspectdocker exec 调试 shell 中是不可见的;但是如果你 docker run -it ... sh 他们将是可见的.这是一个有用且重要的模式,我几乎总是在我的 Dockerfiles 中使用 CMD,除非我专门尝试像这样进行首次设置.

    If you care about such things, environment variables you set via this approach won’t be visible in docker inspect or a docker exec debug shell; but if you docker run -it ... sh they will be visible. This is a useful and important enough pattern that I almost always use CMD in my Dockerfiles unless I’m specifically trying to do first-time setup like this.

    这篇关于如何在 docker 构建过程中使用环境变量获取脚本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆