Not understanding how docker build --secret is supposed to be used

soc*_*pet 9 docker dockerfile

I can get the example working that Docker provides and just about every blog is just a variation of it: just printing out the secret value in the build output.

Cool... but I need to get it into my app that is looking for it and failing to build because it doesn't exist. That much isn't clear to me and I've been unable to figure it out myself.

This is the project structure:

project-root/
  api/
    docker/
      Dockerfile
      mysecret.txt
    src/
      ...
    manage.py
Run Code Online (Sandbox Code Playgroud)

This is the Dockerfile (the last three lines are probably the most relevant):

# syntax=docker/dockerfile:1
FROM python:3.8-slim as python-base
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100 \
    POETRY_HOME="/opt/poetry" \
    POETRY_VIRTUALENVS_IN_PROJECT=true \
    POETRY_NO_INTERACTION=1 \
    PYSETUP_PATH="/opt/pysetup" \
    VENV_PATH="/opt/pysetup/.venv"

ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"


FROM python-base as builder-base
RUN apt-get update \
    && apt-get install --no-install-recommends -y \
        curl \
        build-essential

ENV POETRY_VERSION=1.1.8
RUN curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

WORKDIR $PYSETUP_PATH
COPY ./poetry.lock ./pyproject.toml ./
RUN poetry install --no-dev


FROM python-base as development
ENV FASTAPI_ENV=development

COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH

COPY ./docker/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

WORKDIR $PYSETUP_PATH
RUN poetry install

WORKDIR /app
COPY . .

EXPOSE 5000
ENTRYPOINT /docker-entrypoint.sh $0 $@
CMD ["python", "src/manage.py", "runserver", "0.0.0.0:5000"]


FROM development AS test
RUN --mount=type=secret,id=mysecret export MYSECRET=$(cat /run/secrets/mysecret)
RUN coverage run --omit='src/manage.py,src/config/*,*/.venv/*,*/*__init__.py,*/tests.py,*/admin.py' src/manage.py test src && coverage report
Run Code Online (Sandbox Code Playgroud)

This is the command:

$ docker build -f docker/Dockerfile --no-cache --secret id=mysecret,src=docker/mysecret.txt --target=test --progress=plain .
Run Code Online (Sandbox Code Playgroud)

The app itself is looking for:

SECRET_KEY = os.environ['MYSECRET']
SECRET_KEY = os.environ['mysecret']
Run Code Online (Sandbox Code Playgroud)

But it always fails at the last step of the Dockerfile saying it can't find the necessary env var, MYSECRET or mysecret, to run the app.

I've tried numerous things to resolve the issue and figure out how to appropriately get the secret into the app:

  • Adding a export MYSECRET step to hopefully add it as env var: printenv shows nothing in the docker run -it <image> bash.
  • Finding the value in /run/secrets/mysecret in the docker run -it <image> bash which doesn't exist (as it shouldn't).

It just seems like by the time it gets to the RUN coverage ... the value is no longer available.

So what do I need to do here to get docker build --secret working properly with my Dockerfile?

Eti*_*jon 11

简短回答

你能尝试将 2RUN coverage与结合起来吗RUN --mount ...

我想事情会是这样的:

RUN --mount=type=secret,id=mysecret \
  export MYSECRET=$(cat /run/secrets/mysecret) \
  && coverage run --omit='src/manage.py,src/config/*,*/.venv/*,*/*__init__.py,*/tests.py,*/admin.py' src/manage.py test src \
  && coverage report
Run Code Online (Sandbox Code Playgroud)

细节

--secret标志仅存在于一个 docker 层中。

最终构建的镜像不会有秘密文件

文档:

https://docs.docker.com/engine/reference/builder/#run---mounttypesecret

关于它的博客:

https://pythonspeed.com/articles/docker-buildkit/

每个RUN都会创建一个中间层。

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

所以,根据我的理解,

RUN --mount=type=secret,id=mysecret export MYSECRET=$(cat /run/secrets/mysecret)

不会在您的最终图像和最后的图像中持续存在RUN

编辑1

/bin/shRUN 由not执行/bin/bash,因此您必须MYSECRET分两步实例化并导出它:

/bin/sh -c [您的 RUN 指令]

RUN --mount=type=secret,id=mysecret \
    MYSECRET=$(cat /run/secrets/mysecret) \
    && export MYSECRET \
    && coverage run --omit='src/manage.py,src/config/*,*/.venv/*,*/*__init__.py,*/tests.py,*/admin.py' src/manage.py test src \
    && coverage report
Run Code Online (Sandbox Code Playgroud)

这是我的工作示例:

  • 测试.py

    打印我的秘密值

    RUN --mount=type=secret,id=mysecret \
      export MYSECRET=$(cat /run/secrets/mysecret) \
      && coverage run --omit='src/manage.py,src/config/*,*/.venv/*,*/*__init__.py,*/tests.py,*/admin.py' src/manage.py test src \
      && coverage report
    
    Run Code Online (Sandbox Code Playgroud)
  • 我的秘密.txt

    包含 MYSECRET 值

    Hello
    
    Run Code Online (Sandbox Code Playgroud)
  • Dockerfile

    基于python:3.9镜像

    FROM python:3.9
    
    COPY test.py /tmp/test.py
    
    RUN --mount=type=secret,id=mysecret \
      MYSECRET=$(cat /run/secrets/mysecret) \
      && export MYSECRET \
      && python /tmp/test.py
    
    Run Code Online (Sandbox Code Playgroud)
  • 构建输出
    RUN --mount=type=secret,id=mysecret \
        MYSECRET=$(cat /run/secrets/mysecret) \
        && export MYSECRET \
        && coverage run --omit='src/manage.py,src/config/*,*/.venv/*,*/*__init__.py,*/tests.py,*/admin.py' src/manage.py test src \
        && coverage report
    
    Run Code Online (Sandbox Code Playgroud)

  • @cjones,对于您的构建`--secret id=mysecret,src=mysecret.txt --secret id=another,src=another.txt`。关于 dockerfile `RUN --mount=type=secret,id=mysecret \ --mount=type=secret,id=another \ MYSECRET=$(cat /run/secrets/mysecret) \ &amp;&amp; export MYSECRET \ &amp;&amp; ANOTHER=$( cat /run/secrets/another) \ &amp;&amp; 导出 ANOTHER \ &amp;&amp; python /tmp/test.py` (6认同)