Tengo un proyecto con varios subproyectos y quiero enviar una imagen acoplable separada para cada uno de ellos. Para aumentar la eficiencia, quiero usar compilaciones de varias etapas y estoy buscando un patrón de mejores prácticas sobre cómo hacerlo de la manera más eficiente e intuitiva. Hasta ahora he encontrado dos posibilidades, ambas con inconvenientes:
Puedo hacer un Dockerfile para la imagen del constructor.
FROM maven as builder COPY . /build WORKDIR /build RUN mvn -e clean instally Dockerfiles separados para cada subproyecto
FROM my_builder as builder FROM openjdk:jre-slim as proj1 COPY --from=builder /build/proj1.jar /somewhere/ CMD ["java", "-jar","/somewhere/proj1.jar"]Esto funciona, pero el inconveniente es que tengo que compilar mis imágenes en varios pasos y los Dockerfiles de los subproyectos no se pueden compilar solos:
docker build -t my_builder . docker build proj1/ docker build proj2/Puedo eliminar este problema usando un archivo 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: - builderEsto tiene la ventaja de poder ejecutar la compilación con un solo comando
docker-compose buildpero tiene el inconveniente de crear una dependencia artificial e innecesaria para docker-compose que no es necesaria en el proyecto.
También podría agregar el escenario de compilación a todos los 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"]Esto tendría la ventaja de que puedo construir el contenedor de cada proyecto por sí mismo.
docker build proj1/Por otro lado, es menos eficiente y viola el principio DRY (la primera parte de cada Dockerfile se repite una y otra vez).
¿Hay una mejor manera de hacer esto? ¿Preferiblemente incluso uno que funcione con un solo Dockerfile?
Tuve el mismo problema: varios proyectos que compartían algunas líneas comunes de Dockerfile, pero tenían algunas diferencias. Hay un par de formas en que puede resolver esto con un solo Dockerfile.
Primero, puedes hacer un método de abanico:
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 Luego, durante su compilación, simplemente seleccione cuál desea usar --target :
docker build --file=fan-out.dockerfile --target=variant0 --tag=fan-out/variant0 ./Alternativamente, a veces su proyecto tiene los pasos compartidos al final en lugar de al principio. Podrías hacer algo como esto, lo que yo llamo el método de fan-in:
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 Y constrúyelo con --build-arg :
docker build --file=fan-in.dockerfile --target=final --build-arg="variant=variant1" --tag=fan-in/variant1 ./En cualquiera de estos métodos, probablemente querrá tener un archivo MAKE o una secuencia de comandos de shell para realizar un seguimiento de los comandos para cada variación.
Escribí una publicación de blog con algunos detalles más.