不理解docker build——secret应该如何使用



我可以得到Docker提供的工作示例,并且几乎每个博客都只是它的一个变体:只需在构建输出中打印出秘密值。

酷…但我需要得到它进入我的应用程序,正在寻找它,未能建立,因为它不存在。我不太清楚,我自己也搞不清楚。

项目结构:

project-root/
api/
docker/
Dockerfile
mysecret.txt
src/
...
manage.py

这是Dockerfile(最后三行可能最相关):

# 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

命令如下:

$ docker build -f docker/Dockerfile --no-cache --secret id=mysecret,src=docker/mysecret.txt --target=test --progress=plain .

应用程序本身正在寻找:

SECRET_KEY = os.environ['MYSECRET']
SECRET_KEY = os.environ['mysecret']

但是它总是在Dockerfile的最后一步失败,说它找不到必要的环境变量,MYSECRETmysecret,来运行应用程序。

我已经尝试了很多事情来解决这个问题,并找出如何适当地将秘密进入应用程序:

  • 添加export MYSECRET步骤,希望将其添加为env var:printenvdocker run -it <image> bash中没有显示。
  • 查找docker run -it <image> bash中不存在的/run/secrets/mysecret的值(因为它不应该存在)

似乎当它到达RUN coverage ...时,该值不再可用。

那么我需要做什么才能让docker build --secret与我的Dockerfile正常工作呢?

简短回答

你能试着把2RUN coverageRUN --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

细节此--secret标志仅在一个docker层中存在。

最终构建的映像将没有秘密文件

文档:

https://docs.docker.com/develop/develop-images/build_enhancements/new-docker-build-secret-information

博客介绍:

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

RUN是由/bin/sh而不是/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

下面是我的工作示例:

  • test.py

    print MYSECRET value

    import os
    print(os.environ["MYSECRET"])
    
  • mysecret.txt

    包含MYSECRET值

    Hello
    
  • Dockerfile

    基于python:3.9 image

    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
    
  • 构建输出
    ...
    #7 [3/3] RUN --mount=type=secret,id=mysecret     MYSECRET=$(cat /run/secrets/mysecret)     && export MYSECRET     && python /tmp/test.py
    #7 sha256:f0134fcb389100e7094a47f437f8630e67da83447daaf617756c1d8432163bae
    #7 0.374 Hello
    #7 DONE 0.4s
    ...
    

最新更新