La compilación en varias etapas es una característica nueva y requiere un demonio y un cliente Docker 17.05 o superior. Para aquellos que luchan por optimizar Dockerfiles y hacerlos fáciles de leer y mantener, las compilaciones de múltiples etapas son muy útiles.
Antes de la construcción de múltiples etapas
Una de las cosas más desafiantes al crear una imagen es reducir el tamaño de la imagen. Cada instrucción en el Dockerfile agregará una capa a la imagen. Antes de pasar a la siguiente capa, debe recordar eliminar todos los artefactos innecesarios. Para escribir un Dockerfile verdaderamente eficiente, tradicionalmente necesita usar técnicas de shell y otra lógica para mantener las capas lo más pequeñas posible y asegurarse de que cada capa tenga los artefactos que necesita de la capa anterior, y nada más.
De hecho, es muy común tener un Dockerfile para el entorno de desarrollo (contiene todo lo necesario para construir la aplicación) y un Dockerfile optimizado para el entorno de producción (contiene solo la aplicación y el contenido necesario para ejecutar la aplicación). A esto se le llama "modo de constructor". Mantener dos Dockerfiles no es ideal.
Aquí hay un Dockerfile.build
archivo de ejemplo y los constructores cumplen con los modos anteriores Dockerfile
:
Dockerfile.build
:
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
COPY app.go .
RUN go get -d -v golang.org/x/net/html \
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
Tenga en cuenta que este ejemplo también utiliza el operador Bash &&
dos RUN
comprimidos artificiales juntos para evitar crear capas adicionales en el espejo. Esto es propenso a fallar y difícil de mantener. Por ejemplo, es fácil insertar otro comando y olvidarse de usar el \
carácter para continuar la línea.
Dockerfile
:
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY app .
CMD ["./app"]
build.sh
:
#!/bin/sh
echo Building alexellis2/href-counter:build
docker build --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy \
-t alexellis2/href-counter:build . -f Dockerfile.build
docker container create --name extract alexellis2/href-counter:build
docker container cp extract:/go/src/github.com/alexellis/href-counter/app ./app
docker container rm -f extract
echo Building alexellis2/href-counter:latest
docker build --no-cache -t alexellis2/href-counter:latest .
rm ./app
Cuando ejecuta el build.sh
script, necesita construir la primera imagen, crear un contenedor desde el cual copiar el trabajo y luego construir un segundo espejo. Los dos espejos ocupan espacio en su sistema y aún están allí en la app
pieza de trabajo del disco local .
¡La construcción de varias etapas simplifica enormemente esta situación!
Usar compilación de varias etapas
Para la compilación de varias etapas, puede usar varios Dockerfile en la FROM
declaración. Cada FROM
instrucción puede usar un grupo diferente de espejos y están comenzando a construir una nueva etapa. Puede copiar de forma selectiva artefactos de una etapa a otra, descartando todo lo que no desee en la imagen final. Para ilustrar cómo funciona esto, ajustemos el Dockerfile en la sección anterior usando una compilación de múltiples etapas.
Dockerfile
:
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
Solo necesitas un Dockerfile. Tampoco necesita un script de compilación por separado. Solo corre docker build
.
$ docker build -t alexellis2/href-counter:latest .
El resultado final es el mismo espejo de producción diminuto que antes y una complejidad significativamente reducida. No es necesario crear espejos intermedios y no es necesario extraer ningún artefacto en el sistema local.
¿Como funciona? La segunda FROM
instrucción se utiliza alpine:latest
el espejo como base para comenzar una nueva fase de construcción. COPY --from=0
Solo los artefactos de construcción de la etapa anterior se copian en esta nueva etapa. El SDK de Go y los artefactos intermedios se dejarán atrás y no se guardarán en la imagen final.
Nombra la fase de construcción
Por defecto, las fases no tienen nombre y pueden ser referenciadas por sus números enteros. FROM
El primer número entero de la instrucción comienza desde 0. Sin embargo, puede agregar uno AS <NAME>
a la FROM
directiva denominada etapa. Los siguientes ejemplos y nombrando etapa COPY
utilizando un ejemplo mejorado del nombre de la instrucción anterior. Esto significa que incluso si las instrucciones del Dockerfile se reordenan más tarde, COPY
no se romperán.
FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]
Deténgase en una etapa de construcción específica
Al compilar la imagen, no es necesario compilar el Dockerfile completo, incluida cada etapa. Puede especificar la fase de construcción de destino. El siguiente comando asume que está usando antes Dockerfile
, pero se llama builder
fase de parada:
$ docker build --target builder -t alexellis2/href-counter:latest .
Algunos escenarios en los que esto puede ser muy poderoso son:
- Depurar una fase de compilación específica
- Todos usan una herramienta o una
调试(debug)
fase habilitada de depuración de símbolos y una生产(production)
fase ajustada - Utilice una
测试(testing)
etapa en la que su aplicación se llene con datos de prueba, pero cuando cree un producto, use una etapa diferente que utilice datos reales.
Utilice espejos externos como "escenarios"
Al usar una compilación de múltiples etapas, no está restringido a copiar de etapas creadas previamente en el Dockerfile. Puede utilizar las COPY --from
instrucciones de una copia separada de la imagen que se pueden utilizar están disponibles en el nombre de la imagen local, el registro local o la etiqueta o ID de Docker. El cliente de Docker extrae la imagen y copia los artefactos de ella cuando es necesario. La sintaxis es:
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
Trate la etapa anterior como la nueva etapa
En las FROM
instrucciones de uso , puede consultar el contenido de la etapa anterior. P.ej:
FROM alpine:latest as builder
RUN apk --no-cache add build-base
FROM builder as build1
COPY source1.cpp source.cpp
RUN g++ -o /binary source.cpp
FROM builder as build2
COPY source2.cpp source.cpp
RUN g++ -o /binary source.cpp
Autor:
Traductor oficial del sitio web de Docker : Technical Zemin
Editor: Technical Verses
enlaces: texto en inglés