某些应用场景下,需要对Dokcer镜像加入环境变量,这时需要ENV指令。本文本来具体对ENV指令进行解析。

  ENV 语法

ENV <key>=<value> ...

  ENV 语义

  · ENV指令将环境变量的值设置为。

  · ENV指定的环境变量,可以在后续所有构建阶段使用,并且可用于行内替换使用。

  · 环境变量的值可以被其他环境变量引用,此时,如果引号字符没有转义,将被删除。

  · 与命令行解析类似,引号(")和反斜杠(\)用于包含空格的值,例如:

# 引号内的值可包含空格.
ENV MY_NAME="John Doe"
# 可以使用\来转义空格,还原其含义.
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy

  · 允许在一个指令中同时设置多个环境变量,例如:

ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
    MY_CAT=fluffy

  · 使用构建后的镜像运行容器时,ENV设置的环境变量保持不变,其已被保存到镜像中。

  · 环境变量持久性可能会导致意料之外的副作用。例如,设置ENV DEBIAN_FRONTEND=noninteractive会更改apt-get的行为,并可能会混淆镜像的用户。

  · 如果环境变量只在构建期间需要,而不希望保存到最终镜像中,则使用RUN指令设置值或使用ARG定义变量:

   RUN指令设置变量值:

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...

   ARG指令设置变量值:

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...

  · 兼容语法

   ENV允许使用ENV <key> <value>,省略=。但是这种语法不允许在一个ENV指令中同时设置多个环境变量。兼容语法主要用于兼容老版本,并不推荐使用。

ENV MY_VAR my-value

  · 通过docker inspect可以查看镜像包含的环境变量。

  · 运行容器时,通过docker run --env<key>=<value>可以覆盖镜像带有的环境变量。

  ENV 示例

  · 设置环境变量,容器启动时引用环境变量。

  1) 进入/securitit/dockerfile/目录(根据个人选择,这是本文使用的目录),创建dockerfile文件。

FROM nginx
MAINTAINER Securitit
ENV SECURITIT_NAME="Securitit"
ENV SECURITIT_EMAIL="Securitit@163.com"
ENV SECURITIT_DESC="${SECURITIT_NAME}'s is ${SECURITIT_EMAIL}"
CMD echo "${SECURITIT_DESC}"

  配置文件中定义了SECURITIT_NAMESECURITIT_EMAILSECURITIT_DESC、,其中SECURITIT_DESC引用了SECURITIT_NAMESECURITIT_EMAIL,通过CMD指定容器启动时输出SECURITIT_DESC

  2) 执行如下的构建命令,基于dockerfile构建镜像。

docker build -f /securitit/dockerfile/dockerfile -t securitit-nginx-env:1.0.0.1 .

dockerfile cmd多个命令 dockerfile 多个env_Docker

  3) 查看镜像信息。

docker images

dockerfile cmd多个命令 dockerfile 多个env_Docker_02

  4) 查看镜像元数据。

  可以看到构建的镜像声明开放80和8080两个端口。

docker inspect -f {{".Config.Env"}} df091d578e94

dockerfile cmd多个命令 dockerfile 多个env_Docker_03

  5) 指定通过dockerfile生成的镜像启动容器。

docker run --name securitit-nginx-env -it -p 80:80 securitit-nginx-env:1.0.0.1

dockerfile cmd多个命令 dockerfile 多个env_ENV_04

  · 通过兼容语法设置环境变量,容器启动时通过docker run --env<key>=<value>覆盖镜像的环境变量。

  1) 进入/securitit/dockerfile/目录(根据个人选择,这是本文使用的目录),创建dockerfile文件。

FROM nginx
MAINTAINER Securitit
ENV SECURITIT_NAME="Securitit"
ENV SECURITIT_EMAIL="Securitit@163.com"
ENV SECURITIT_DESC="${SECURITIT_NAME}'s is ${SECURITIT_EMAIL}"
ENV SECURITIT_LABEL="BOOK BALL MUSIC"
CMD echo "${SECURITIT_DESC}, ${SECURITIT_NAME}'s label is ${SECURITIT_LABEL}"

  配置文件中定义了SECURITIT_NAMESECURITIT_EMAILSECURITIT_DESCSECURITIT_LABEL,其中SECURITIT_DESC引用了SECURITIT_NAMESECURITIT_EMAILSECURITIT_LABEL,通过CMD指定容器启动时输出SECURITIT_DESC

  2) 执行如下的构建命令,基于dockerfile构建镜像。

docker build -f /securitit/dockerfile/dockerfile -t securitit-nginx-env:1.0.0.2 .

dockerfile cmd多个命令 dockerfile 多个env_Docker_05

  3) 查看镜像信息。

docker images

dockerfile cmd多个命令 dockerfile 多个env_ENV_06

  4) 查看镜像元数据。

docker inspect -f {{".Config.Env"}} 9a836d4afa55

dockerfile cmd多个命令 dockerfile 多个env_环境变量_07

  5) 指定通过dockerfile生成的镜像启动容器。

docker run --name securitit-nginx-env-v2 -it -p 80:80 --env SECURITIT_NAME="CSDN" securitit-nginx-env:1.0.0.2

dockerfile cmd多个命令 dockerfile 多个env_环境变量_08

  容器启动命令中增加了--env SECURITIT_NAME="CSDN" ,目的是为了替换环境变量SECURITIT_NAME的值,dockerfile中内容为${SECURITIT_DESC}, ${SECURITIT_NAME}'s label is ${SECURITIT_LABEL}docker run时输出内容为Securitit's is Securitit@163.com, CSDN's label is BOOK BALL MUSIC,发现开头的Securitit未替换为CSDN,原因是镜像构建时,SECURITIT_DESC已做过替换,通过docker inspect查看镜像元数据时,SECURITIT_DESC值已变为Securitit's is Securitit@163.com

  总结

  环境变量对于系统和软件来说,还是十分关键的,环境变量可以描述其部分状态,并随便其整个生命周期。

  若文中存在错误和不足,欢迎指正!