当涉及到多阶段的Dockerfile时,有几个过程我很难用脑子去思考。
以这个为例,下面有几个问题:
# 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"]我的问题是:
docker build ...整个图像,然后只是docker run ... --target=<stage>运行一个特定的阶段(development,test,lint,production等)还是仅仅构建和运行所需的特定阶段(例如docker build ... -t test --target=test && docker run test ...)?
我想说的不是前者,因为你最终会有一个臃肿的图像和构建工具包什么的.对,是这样?minikube、skaffold、devspace等)在运行单元测试时,您是指Dockerfile中的这些阶段(devspace钩子之类的)还是在容器中使用本机测试工具(例如npm test、./manage.py test等)?谢谢你澄清这些问题。
发布于 2021-08-10 21:52:45
从一个较少的DevSpace-y穿透力和一个更一般的码头-y(没有不尊重Lukas!)的回答:
问题1
细目
❌你是码头修理工..。整个图像,然后码头运行.-目标=运行一个特定的阶段
您的理解非常接近,并设法在查询的第二部分中概述了该方法:
或者您只是构建和运行所需的特定阶段(例如,坞构建. -t测试-✅= test & docker .)?
--target选项不存在于docker run命令中,在调用docker run --help时可以看到该命令。
我想说的不是前者,因为你最终会有一个臃肿的图像和构建工具包什么的.对,是这样?
是的,这是不可能的第一种方式,因为当没有指定--target,然后只有最后阶段被纳入您的形象。这是一个很大的好处,因为它减少了容器的最终大小,同时允许您使用多个指令。
详细情况和实例
它是一个标志,您可以在构建时传递给它,这样您就可以选择具体构建哪些层。这是一个非常有用的指令,可以用几种不同的方式使用。有一篇不错的博客文章这里谈到了多阶段构建的新特性(--target就是其中之一)。
例如,我在CI中成功地构建了大量项目,使用了不同的阶段和目标,下面是伪代码,但希望上下文能够应用
# 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。
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帮助规范外部因素,并提供统一的方法来确保测试和部署都是可审计的。
希望对任何形式或形式都有帮助
发布于 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直接通过手动对接命令来运行任何工作负载。
https://stackoverflow.com/questions/68730337
复制相似问题