我有一个包含多个子项目的项目,并且我想为每个子项目运送一个单独的docker映像。为了提高效率,我想使用multistage builds,并且正在寻找一种最佳实践模式,以最有效,最直观的方式实现这一目标。到目前为止,我发现了两种可能,都有缺点:
我可以为构建器映像创建一个Dockerfile
FROM maven as builder
COPY . /build
WORKDIR /build
RUN mvn -e clean install
以及每个子项目的单独Dockerfiles
FROM my_builder as builder
FROM openjdk:jre-slim as proj1
COPY --from=builder /build/proj1.jar /somewhere/
CMD ["java", "-jar","/somewhere/proj1.jar"]
这行得通,但是缺点是,我必须分多个步骤构建映像,并且子项目的Dockerfile不能自己构建:
docker build -t my_builder .
docker build proj1/
docker build proj2/
我可以使用docker-compose文件消除此问题:
version: "3.4"
services:
builder:
build:
context: ./
proj1:
build:
target: proj1
context: ./proj1
depends_on:
- builder
proj2:
build:
target: proj2
context: ./proj2
depends_on:
- builder
这具有可以通过单个命令运行构建的优点
docker-compose build
但是具有为项目创建不需要的docker-compose不必要和人为的依赖的缺点。
我还可以将buildstage添加到所有Dockerfiles
FROM maven as builder
COPY . /build
WORKDIR /build
RUN mvn -e clean install
FROM openjdk:jre-slim as proj1
COPY --from=builder /build/proj1.jar /somewhere/
CMD ["java", "-jar","/somewhere/proj1.jar"]
这样做的好处是我可以自己构建每个项目的容器
docker build proj1/
另一方面,它效率较低,并且违反了DRY原则(每个Dockerile的第一部分反复进行重复)。
有更好的方法吗?最好甚至可以使用一个Dockerfile吗?
答案 0 :(得分:2)
我遇到了同样的问题:几个项目共享一些共同的Dockerfile行,但有一些区别。单个Dockerfile可以通过多种方式解决此问题。
首先,您可以执行扇出方法:
FROM ubuntu:18.04 as base
RUN echo "base" >> /history.txt
CMD cat /history.txt
FROM base as variant0
RUN echo "variant0" >> /history.txt
FROM base as variant1
RUN echo "variant1" >> /history.txt
然后在构建期间,您只需使用--target
选择要使用的那个:
docker build --file=fan-out.dockerfile --target=variant0 --tag=fan-out/variant0 ./
或者,有时您的项目在最后而不是在开始时具有共享步骤。您可以执行以下操作,即所谓的扇入方法:
ARG variant
FROM ubuntu:18.04 as variant0
RUN echo "variant0" >> /history.txt
FROM ubuntu:18.04 as variant1
RUN echo "variant1" >> /history.txt
FROM ubuntu:18.04 as variant2
RUN echo "variant2" >> /history.txt
FROM $variant as join
# pass, do nothing
FROM ubuntu:18.04 as final
COPY --from=join /history.txt /
RUN echo "final" >> /history.txt
CMD cat /history.txt
并使用--build-arg
进行构建:
docker build --file=fan-in.dockerfile --target=final --build-arg="variant=variant1" --tag=fan-in/variant1 ./
在这两种方法中,您可能都希望有一个makefile或shell脚本来跟踪每个变体的命令。
我写了blog post并提供了更多详细信息。