【发布时间】:2021-05-28 20:09:43
【问题描述】:
我正在开发一个使用多阶段 Dockerfile 的项目。这适用于 CircleCI,但我对 Docker 不是很有经验,所以我在本地运行时遇到了麻烦。来自文档:
第二个 FROM 指令开始一个新的构建阶段 alpine:latest 图像作为其基础。 COPY --from=0 行仅复制 上一阶段的建好的神器进入了这个新阶段。围棋 SDK 和任何中间工件都被留下,而不是保存在 最终图像。
如果我理解正确,这意味着如果我在第 1 阶段安装了一组依赖项,在第 2 阶段安装了另一组,那么在我运行 docker-compose up 之后,我只会看到安装了一些依赖项。这就是当地正在发生的事情。但是,为了附加到容器并运行开发服务器,我需要安装 all 项目依赖项。我在这里读到可以在构建命令中使用--rm=false 参数(我不确定这是否指的是docker build、docker-compose build,或者是否有任何区别)。我尝试将 rm 设置添加到我的 docker-compose 但显然它不存在。
version: "3.8"
services:
app:
container_name: my.container
build:
context: .
dockerfile: Dockerfile.dev
rm: false
entrypoint: sh -c
command: tail -f /dev/null
stdin_open: true
tty: true
app2:
...
我的 Dockerfile 大致如下:
ARG PYTHON_VERSION=3.8-alpine3.12
FROM python:$PYTHON_VERSION AS base
ARG USER=myuser
# Install application run-time dependencies.
RUN addgroup -S ${USER} && \
adduser -S -g ${USER} ${USER} && \
apk add --no-cache \
--upgrade \
bash && \
rm -rf /var/cache/apk/*
FROM base AS builder
RUN mkdir /install
RUN mkdir /e2e_install
WORKDIR /install
# Install application build-time dependencies.
RUN apk update && \
apk add --no-cache --upgrade \
bash \
build-base \
libffi-dev \
pcre-dev \
linux-headers \
zlib-dev \
python3-dev \
openssh \
openssh-keygen \
git \
gcc \
musl-dev && \
rm -rf /var/cache/apk/*
# Install project and test dependencies.
RUN pip install --no-cache-dir --disable-pip-version-check pip==20.0.2
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir \
--no-warn-script-location \
--prefix=/install \
--disable-pip-version-check -r /tmp/requirements.txt
COPY test_requirements.txt /tmp/test_requirements.txt
RUN pip install --no-cache-dir \
--ignore-installed \
--no-warn-script-location \
--prefix=/install \
--disable-pip-version-check -r /tmp/test_requirements.txt
# install e2e-test dependencies
COPY e2e/requirements.txt /tmp/e2e_test_requirements.txt
RUN cat /tmp/e2e_test_requirements.txt
RUN pip install --no-cache-dir \
--ignore-installed \
--disable-pip-version-check \
--no-warn-script-location \
--prefix=/e2e_install \
-r /tmp/e2e_test_requirements.txt
# Tag version number into source code.
ARG VERSION_NUMBER=unversioned
WORKDIR /source
COPY . .
RUN sed -i -e "s/__version__ = \"unversioned\"/__version__ = \"${VERSION_NUMBER}\"/" external_api/__init__.py
# -------------------- e2e Image --------------------
FROM base as e2e-test
ARG USER=myuser
COPY --from=builder /e2e_install /usr/local
WORKDIR /opt/company/myapp
COPY --from=builder /source/e2e ./e2e
COPY --from=builder /source/scripts/entry_point.sh .
# Set file owner group,
RUN chown -R ${USER}:${USER} /opt/company
ENTRYPOINT ["./entry_point.sh"]
# -------------------- Production Image --------------------
FROM base
ARG USER=myuser
# Copy necessary files from builder.
WORKDIR /opt/company
COPY --from=builder /install /usr/local
COPY --from=builder /source .
# Set file owner group,
RUN chown -R ${USER}:${USER} /opt/company
# Run unit tests.
RUN PYTHONPATH=. pytest tests/unit_test --cov=. --cov-report=xml
COPY ./scripts/entry_point.sh .
ENTRYPOINT ["./entry_point.sh"]
当我运行docker-compose build 时,我得到了一堆这些:
Step 20/26 : ARG VERSION_NUMBER=unversioned
---> Running in 1ce3e682b483
Removing intermediate container 1ce3e682b483
---> dcc4d4b6b4b5
Step 21/26 : WORKDIR /source
---> Running in c8d9c1349305
Removing intermediate container c8d9c1349305
当我附加到容器并尝试运行 Django 开发服务器时,它不起作用,因为未安装依赖项(即使 docker-compose build 输出显示它们已安装)。我想这是因为“中间容器”正在被删除。我试图将多阶段 Dockerfile 转换为单阶段文件,但我仍然不断收到“正在删除中间容器”消息,并且依赖项并未全部安装。我是否必须在单个 RUN 指令中安装所有依赖项?这是我进入容器时安装所有依赖项的唯一方法吗?我有没有办法保持这个 Dockerfile 完整,并以某种方式告诉 docker-compose 在构建时停止“留下中间工件”?我是否正确使用了“神器”这个词?我找不到明确的解释,也不确定我完全理解什么是“docker artifact”。
【问题讨论】:
-
日常开发可以使用普通的Python虚拟环境吗?
-
我正在做的项目使用微服务架构。涉及到 4 个独立的 Python 项目,它们都必须相互通信,其中 2 个有自己的数据库,其他依赖项如 redis、rabbitmq。在本地安装所有这些东西是不可能的。
-
您应该能够将
--no-rm应用于docker-compose build命令本身。您是正确的,在 Compose 文件中似乎无法执行此操作。 -
我认为你有 2 个选择。我不确定哪个更可取,我也没有尝试过。首先,确定哪个中间容器包含您需要的依赖项,并且您的 Python 脚本不会被
COPY ---from命令移动。编辑 Compose 文件以按 ID 引用 intermediate 容器图像。其次,将多阶段的 Dockerfile 合并为一个阶段。正如您所写,多阶段的目的通常是清除运行时不需要的构建|开发依赖项,因此这种方法可以为您提供一切。 -
第二个可能是更好的选择。它还为您提供了两种我认为有用的图像。包含所有内容的开发人员|开发映像和不包含所有内容的运行时|最终用户映像。
标签: docker docker-compose dockerfile