如何通过docker-compose将变量传递到Dockerfile

时间:2019-02-26 12:28:41

标签: docker docker-compose dockerfile

我想在主机和Docker的容器之间正确共享目录 在两个系统上都使用相同的UIDGID。 为此,我想将它们作为变量MY_UID=$(id -u)传递给docker。

我们正在考虑以下情况:.env引用了某些变量,例如MY_UID=$(id -u)不是行值,例如MY_UID=1000

正确声明变量,将其导出为环境变量 并且它可以在docker-compose.yml级别上运行,但是docker-compose不会将它们进一步传递给Dockerfile。

到目前为止,我已经在docker-compose.yml中尝试过:

  • env_file字段
  • 环境字段

与bash一起使用:

  • 导出变量,例如:
    • cat .env | envsubst | docker-compose -f-...
    • VAR = 123 docker-compose ...

或docker-compose -e的选项。

给定变量的整个路径为export> docker-compose> dockerfile。


出于测试目的,Dockerfile很简单,例如: (在此级别上,变量不起作用!)

FROM heroku/heroku:18 AS production
RUN useradd -ms /usr/bin/fish -p $(openssl passwd -1 django) --uid "$MY_UID" --gid "$MY_GID" -r 

和$ MY_UID在使用docker-compose时为空。


docker-compose.yml (在此级别上变量有效!)

version: '3.7'

networks: {}
services:
  django:
    build:
      context: ${MY_DIR}
      dockerfile: ${COMPOSE_DIR}/django/Dockerfile
    env_file:
      - .env
    environment:
      - MY_UID: ${MY_UID}
    volumes:
      - ${MY_DIR}:/app:rw

docker-compose config返回: MY_GID: $$(id -u) 对于.env:MY_GID=$(id -u)


我想避免这种解决方法:

source .env && cat template_Dockerfile | envsubst > Dockerfile

source .env && cat .env | envsubst > .env_for_dockercompose

2 个答案:

答案 0 :(得分:1)

关于将值从docker-compose(或仅从CLI)传递到Dockerfile的正确方法,我想您需要添加一些ARG指令,例如:

FROM heroku/heroku:18 AS production
ARG MY_UID="...default UID..."
ARG MY_GID="...default GID..."
RUN useradd -ms /usr/bin/fish -p $(openssl passwd -1 django) --uid "$MY_UID" --gid "$MY_GID" -r 

然后对其进行测试:

$ docker build --build-arg=MY_UID="1000" --build-arg=MY_GID="1000" -t test .

我使用类似的方法in the Dockerfile of coqorg/base(基于Debian)。

但是,如果您对传递变量以确保UID / GID匹配特别感兴趣,请注意,可以采用另一种方法,该方法具有额外的好处,即可以使映像与使用不同UID / GID的多个主机兼容。 this SO answer by @BMitch中对此进行了描述,该提案建议在启动时修复容器目录的权限,例如:

答案 1 :(得分:0)

用于UID / GID的解决方案(事实上,不同的主机=因此开发人员具有不同的uid)

您可以使用2张图片来处理UID/GID(第一张=主图片和公开图片,第二张=小图片和私人图片) 这样,大部分环境都会被缓存,并由称为base_image的预先配置的第一张映像提供给其他人。

然后,最终图像的说明很简单:

FROM base_image
RUN groupadd -r django -g ${UFG_GID} ...

base_image被赋予所有人, 但最终映像是一个延续,每个主机都打算构建每个主机上不同UID/GID部分的内容。但这没问题,因为这样的操作非常便宜。

这样,不需要额外的脚本,但是其他人无法使用最终图像来避免使用不同的UID/GID问题。

如果您希望每个人都可以使用一个图像,则需要用于修复用户权限的其他脚本-请参见ErikiMD answer


一种完全控制必须如何填充变量(从主机或容器)的解决方案。

说明:

  • 为docker准备模板,docker-compose
    • Dockerfile_template
    • docker-compose.yml_template
  • 将模板渲染到正确的docker文件中

这样,通过下面的模板,您可以完全控制将在每个级别(主机,容器)上替换哪个变量

...
ENV PATH="/pyenv/bin:${DOLLAR}PATH"
...
RUN ...  ${MY_VAR}...
...

注意

使用DOLLAR='$',并用${DOLLAR}PATH转义$ PATH,以避免用错误的主机中的值替换$ PATH。

含义:

  • 在主主机上渲染正确的docker文件时,将填充$ MY_VAR
  • $ PATH稍后将被填充(在将模板渲染到docker文件时被转义)

以这种方式呈现docker文件:

source .env && \
cat $COMPOSE_DIR/django/Dockerfile_template | DOLLAR='$' envsubst > $COMPOSE_DIR/django/Dockerfile \
docker-compose up -d --build

生成预配置的Dockerfile-在其中替换一些变量为值。

  • .env保留所有变量
  • envsubst用于以shell格式字符串替换环境变量

docker-compose.yml_template也是如此(如果需要)。