首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解多级Dockerfile工作流程

理解多级Dockerfile工作流程
EN

Stack Overflow用户
提问于 2021-08-10 16:20:54
回答 2查看 598关注 0票数 2

当涉及到多阶段的Dockerfile时,有几个过程我很难用脑子去思考。

以这个为例,下面有几个问题:

代码语言:javascript
复制
# Dockerfile
# Uses multi-stage builds requiring Docker 17.05 or higher
# See https://docs.docker.com/develop/develop-images/multistage-build/

# Creating a python base with shared environment variables
FROM python:3.8.1-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"


# builder-base is used to build dependencies
FROM python-base as builder-base
RUN apt-get update \
    && apt-get install --no-install-recommends -y \
        curl \
        build-essential

# Install Poetry - respects $POETRY_VERSION & $POETRY_HOME
ENV POETRY_VERSION=1.0.5
RUN curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

# We copy our Python requirements here to cache them
# and install only runtime deps using poetry
WORKDIR $PYSETUP_PATH
COPY ./poetry.lock ./pyproject.toml ./
RUN poetry install --no-dev  # respects 


# 'development' stage installs all dev deps and can be used to develop code.
# For example using docker-compose to mount local volume under /app
FROM python-base as development
ENV FASTAPI_ENV=development

# Copying poetry and venv into image
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH

# Copying in our entrypoint
COPY ./docker/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

# venv already has runtime deps installed we get a quicker install
WORKDIR $PYSETUP_PATH
RUN poetry install

WORKDIR /app
COPY . .

EXPOSE 8000
ENTRYPOINT /docker-entrypoint.sh $0 $@
CMD ["uvicorn", "--reload", "--host=0.0.0.0", "--port=8000", "main:app"]


# 'lint' stage runs black and isort
# running in check mode means build will fail if any linting errors occur
FROM development AS lint
RUN black --config ./pyproject.toml --check app tests
RUN isort --settings-path ./pyproject.toml --recursive --check-only
CMD ["tail", "-f", "/dev/null"]


# 'test' stage runs our unit tests with pytest and
# coverage.  Build will fail if test coverage is under 95%
FROM development AS test
RUN coverage run --rcfile ./pyproject.toml -m pytest ./tests
RUN coverage report --fail-under 95


# 'production' stage uses the clean 'python-base' stage and copyies
# in only our runtime deps that were installed in the 'builder-base'
FROM python-base as production
ENV FASTAPI_ENV=production

COPY --from=builder-base $VENV_PATH $VENV_PATH
COPY ./docker/gunicorn_conf.py /gunicorn_conf.py

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

COPY ./app /app
WORKDIR /app

ENTRYPOINT /docker-entrypoint.sh $0 $@
CMD [ "gunicorn", "--worker-class uvicorn.workers.UvicornWorker", "--config /gunicorn_conf.py", "main:app"]

我的问题是:

  1. 你是docker build ...整个图像,然后只是docker run ... --target=<stage>运行一个特定的阶段(developmenttestlintproduction等)还是仅仅构建和运行所需的特定阶段(例如docker build ... -t test --target=test && docker run test ...)? 我想说的不是前者,因为你最终会有一个臃肿的图像和构建工具包什么的.对,是这样?
  2. 当涉及到本地Kubernetes开发时(minikubeskaffolddevspace等)在运行单元测试时,您是指Dockerfile中的这些阶段(devspace钩子之类的)还是在容器中使用本机测试工具(例如npm test./manage.py test等)?

谢谢你澄清这些问题。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-08-10 21:52:45

从一个较少的DevSpace-y穿透力和一个更一般的码头-y(没有不尊重Lukas!)的回答:

问题1

细目

❌你是码头修理工..。整个图像,然后码头运行.-目标=运行一个特定的阶段

您的理解非常接近,并设法在查询的第二部分中概述了该方法:

或者您只是构建和运行所需的特定阶段(例如,坞构建. -t测试-✅= test & docker .)?

--target选项不存在于docker run命令中,在调用docker run --help时可以看到该命令。

我想说的不是前者,因为你最终会有一个臃肿的图像和构建工具包什么的.对,是这样?

是的,这是不可能的第一种方式,因为当没有指定--target,然后只有最后阶段被纳入您的形象。这是一个很大的好处,因为它减少了容器的最终大小,同时允许您使用多个指令。

详细情况和实例

它是一个标志,您可以在构建时传递给它,这样您就可以选择具体构建哪些层。这是一个非常有用的指令,可以用几种不同的方式使用。有一篇不错的博客文章这里谈到了多阶段构建的新特性(--target就是其中之一)。

例如,我在CI中成功地构建了大量项目,使用了不同的阶段和目标,下面是伪代码,但希望上下文能够应用

代码语言:javascript
复制
# Dockerfile
FROM python as base

FROM base as dependencies

COPY requirements.txt .
RUN pip install -r requirements.txt

FROM dependencies as test

COPY src/ src/
COPY test/ test/

FROM dependencies as publish

COPY src/ src/

CMD ...

这样的Dockerfile将使您能够在CI工作流中执行类似的操作,再一次,伪代码-esque。

代码语言:javascript
复制
docker build . -t my-app:unit-test --target test
docker run my-app:unit-test pyunit ...
docker build . -t my-app:latest
docker push ...

在某些情况下,对何时构建的内容拥有这种细粒度的控制是非常有利的,并且能够运行那些只包含几个阶段的映像,而无需构建整个应用程序,这是非常有益的。

这里的关键是,没有人期望您需要使用--target,但它可以用于解决特定问题。

问题2

当涉及到当地的Kubernetes开发(迷你库贝,骷髅,开发空间等)在运行单元测试时,您是指Dockerfile中的这些阶段(devspace钩子之类的)还是在容器中使用本机测试工具(例如npm测试、./manage.py e.py测试等等)?

Lukas很好地介绍了一种特定于devspace的方法,但最终您可以任意测试。使用devspace使运行(并记住运行)测试更容易,这听起来确实是个好主意。无论您使用什么工具来启用一个更简单的工作流,很可能仍然会在幕后使用npm test等。

如果您希望在容器之外调用npm test (这很好),如果您希望在容器中调用它,那也可以。你的问题的解决方案会根据你的情况而改变。CICD帮助规范外部因素,并提供统一的方法来确保测试和部署都是可审计的。

希望对任何形式或形式都有帮助

票数 4
EN

Stack Overflow用户

发布于 2021-08-10 17:01:56

复制Reddit对此的响应,以帮助可能在StackOverflow上查找此信息的其他人:

这里是DevSpace的维护者。对于我的工作流(以及使用devspace init设置的默认devspace init行为),在开发过程中跳过了图像构建,因为它往往是工作流中最烦人和最耗时的部分。相反,大多数使用DevSpace的团队都会将一个dev映像推送到注册中心并由CI/CD构建,然后在devspace.yaml中使用replacePods.replaceImage,如下所示:https://devspace.sh/cli/docs/configuration/development/replace-pods

这意味着您的清单或舵机图表正在被部署,引用prod映像(应该是的),然后devspace (部署后)将用经过开发优化的映像替换您的吊舱的映像,这些映像将提供您所有的工具。在这些吊舱中,您可以使用终端构建应用程序,运行测试以及集群中运行的其他依赖项等。

不过,通常情况下,团队在CI/CD中也会在一段时间后开始使用DevSpace,然后将profiles (例如prod配置文件或integration-testing配置文件等)添加到他们的devspace.yaml中,在这里他们再次添加图像构建,因为他们希望使用kaniko或docker在管道中构建映像。为此,您还可以在devspace.yaml中指定构建目标:https://devspace.sh/cli/docs/configuration/images/docker#target

FWIW关于1:我从来不使用docker run --target,但我也总是使用Kubernetes直接通过手动对接命令来运行任何工作负载。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68730337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档