Cómo acelerar las compilaciones de Docker y optimizar el almacenamiento en caché con "COPY –link"

COPY --link es una nueva característica de BuildKit que podría acelerar sustancialmente las compilaciones de imágenes de Docker. Funciona copiando archivos en capas de imágenes independientes que no dependen de la presencia de sus predecesores. Puede agregar contenido nuevo a las imágenes sin que la imagen base exista en su sistema.

Esta capacidad se agregó como parte de Buildx v0.8 en marzo de 2022. Se incluye en la versión 20.10.14 de la CLI de Docker, por lo que ya debería tener acceso si está ejecutando la última versión.

En este artículo, mostraremos qué --link hace y explica cómo funciona. También veremos algunas de las situaciones en las que no debería ser usado.

→ Índice de contenidos

--link es un nuevo argumento opcional para el Dockerfile existente COPY instrucción. Cambia la forma en que funcionan las copias al crear una nueva capa de instantánea cada vez que la usa.

Regular COPY Las declaraciones agregan archivos a la capa que los precede en el Dockerfile. El contenido de esa capa debe existir en su disco para que el nuevo contenido pueda fusionarse en:

FROM alpine
COPY my-file /my-file
COPY another-file /another-file

El Dockerfile anterior copia my-file en la capa producida por el comando anterior. Después de la FROM instrucción, la imagen consta del contenido de Alpine:

bin/
dev/
etc/
...

El primero COPY instrucción produce una imagen que incluye todo, desde Alpine, así como el my-file expediente:

my-file
bin/
dev/
etc/
...

Y el segundo COPY la instrucción agrega another-file encima de esta imagen:

another-file
my-file
bin/
dev/
etc/
...

La capa producida por cada instrucción incluye todo lo que vino antes, así como todo lo que se agregó recientemente. Al final de la compilación, Docker usa un proceso de diferenciación para calcular los cambios dentro de cada capa. El blob de imagen final contiene solo los archivos que se agregaron en cada etapa de la instantánea, pero esto no se refleja en el proceso de ensamblaje durante la compilación.

“–Enlace” modifica COPY para crear un nuevo sistema de archivos independiente cada vez que se utiliza. En lugar de copiar los archivos nuevos encima de la capa anterior, se envían a una ubicación completamente diferente para convertirse en una capa independiente. Posteriormente, las capas se unen para producir la imagen final.

Cambiemos el Dockerfile de ejemplo para usar --link:

FROM alpine
COPY --link my-file /my-file
COPY --link another-file /another-file

el resultado de la FROM la instrucción no ha cambiado: produce la capa Alpine, con todo el contenido de esa imagen:

bin/
dev/
etc/
...

El primero COPY instrucción tiene un efecto notablemente diferente. Esta vez se crea otra capa independiente. Es un nuevo sistema de archivos que contiene solo my-file:

my-file

Entonces el segundo COPY instrucción crea otra instantánea nueva con solo another-file:

another-file

Cuando se completa la compilación, Docker almacena estas instantáneas independientes como nuevos archivos de capa (tarballs). Los tarballs se vinculan nuevamente a la cadena de capas anteriores, construyendo la imagen final. Esto consiste en las tres instantáneas fusionadas, lo que da como resultado un sistema de archivos que coincide con el original cuando se crean los contenedores:

my-file
another-file
bin/
dev/
etc/
...

Esta imagen del proyecto BuildKit ilustra las diferencias entre los dos enfoques.

Imagen del blog de Docker que muestra las diferencias entre "COPY" y "COPY --link"

COPY --link solo está disponible cuando usa BuildKit para crear sus imágenes. Ejecute su compilación con docker buildx --create o usar docker build con el DOCKER_BUILDKIT=1 conjunto de variables de entorno.

También debe aceptar la sintaxis de Dockerfile v1.4 usando un comentario en la parte superior de su archivo:

# syntax=docker/dockerfile:1.4
FROM alpine:latest
COPY --link my-file /my-file
COPY --link another-file /another-file

Ahora puede construir su imagen con soporte para copias vinculadas:

DOCKER_BUILDKIT=1 docker build -t my-image:latest .

Imágenes construidas a partir de Dockerfiles usando COPY --link se puede usar como cualquier otro. Puede iniciar un contenedor con docker run y enviarlos directamente a los registros. los --link flag solo afecta la forma en que se agrega el contenido a las capas de la imagen durante la compilación.

Por qué importan las copias vinculadas

Utilizando el --link permitir que las cachés de compilación se reutilicen incluso cuando el contenido COPY en cambios. Además, las compilaciones pueden completarse sin que su imagen base exista en su máquina.

Volviendo al ejemplo anterior, estándar COPY El comportamiento requiere la alpine que exista una imagen en su host Docker antes de que se pueda agregar el nuevo contenido. La imagen se descargará automáticamente durante la compilación si no la extrajo previamente.

Con copias vinculadas, Docker no necesita la alpine contenido de la imagen. tira de la alpine manifiesto, crea nuevas capas independientes para los archivos copiados, luego crea un manifiesto revisado que vincula las capas con las proporcionadas por alpine. el contenido de la alpine La imagen, sus blobs de capa, solo se descargará si inicia un contenedor desde su nueva imagen o si lo exporta a un archivo tar. Cuando envía la imagen a un registro, ese registro almacenará sus nuevas capas y adquirirá de forma remota la alpine unos.

Esta funcionalidad también facilita rebases de imágenes eficientes. Tal vez actualmente esté distribuyendo una imagen de Docker utilizando la última versión de Ubuntu 20.04 LTS:

FROM golang AS build
...
RUN go build -o /app .

FROM ubuntu:20.04
COPY --link --from=build /app /bin/app
ENTRYPOINT ["/bin/app"]

Puede construir la imagen con el almacenamiento en caché habilitado usando BuildKit's --cache-to bandera. los inline cache almacena datos de caché de compilación dentro de la imagen de salida, donde se pueden reutilizar en compilaciones posteriores:

docker buildx build --cache-to type=inline -t example-image:20.04 .

Ahora supongamos que desea proporcionar una imagen basada en el próximo LTS después de su lanzamiento, Ubuntu 22.04:

FROM golang AS build
...
RUN go build -o /app .

FROM ubuntu:22.04
COPY --link --from=build /app /bin/app
ENTRYPOINT ["/bin/app"]

Reconstruya la imagen utilizando los datos de caché incrustados en la versión original:

docker buildx build --cache-from example-image:20.04 -t example-image:22.04 .

La compilación se completará casi al instante. Utilizando los datos almacenados en caché de la imagen existente, Docker puede verificar los archivos necesarios para construir /app no he cambiado Esto significa que el caché para la capa independiente creada por el COPY instrucción sigue siendo válida. Como esta capa no depende de ninguna otra, la ubuntu:22.04 la imagen tampoco se extraerá. Docker simplemente vincula la capa de instantáneas que contiene /bin/app en un nuevo manifiesto dentro del ubuntu:22.04 cadena de capas La capa de instantáneas se "reubica" de manera efectiva en una nueva imagen principal, sin que se produzca ninguna operación en el sistema de archivos.

El modelo también optimiza las compilaciones de varias etapas en las que se pueden producir cambios entre cualquiera de las etapas:

FROM golang AS build
RUN go build -o /app .

FROM config-builder AS config
RUN generate-config --out /config.yaml

FROM ubuntu:latest
COPY --link --from=config /config.yaml build.conf
COPY --link --from=build /app /bin/app

Sin que --linkcualquier cambio en el generado config.yaml causas ubuntu:latest que se extraerá y el archivo que se copiará. Luego, el binario debe volver a compilarse, ya que los cambios en el sistema de archivos invalidan su caché. Con copias vinculadas, un cambio en config.yaml permite que la construcción continúe sin tirar ubuntu:latest o recompilar el binario. La capa de instantáneas con build.conf el interior simplemente se reemplaza por una nueva versión que es independiente de todas las demás capas.

Cuándo no usarlo

Hay algunas situaciones en las que el --link bandera no funcionará correctamente. Debido a que copia archivos en una nueva capa, en lugar de agregarlos encima de la capa anterior, no puede usar referencias ambiguas como su ruta de destino:

COPY --link my-file /data

con un regular COPY instrucción, my-file será copiado a /data/my-file si /data ya existe como directorio en la imagen. Con --linkel sistema de archivos de la capa de destino siempre estará vacío, por lo que my-file se escribe a /data.

La misma consideración se aplica a la resolución de enlaces simbólicos. Estándar COPY resuelve automáticamente las rutas de destino que son enlaces simbólicos en la imagen. cuando estas usando --linkeste comportamiento no se admite porque el enlace simbólico no existirá en la capa independiente de la copia.

Se recomienda comenzar a usar --link donde no se apliquen estas limitaciones. La adopción de esta característica acelerará sus compilaciones y hará que el almacenamiento en caché sea más poderoso. Si no puede eliminar de inmediato las rutas de destino ambiguas o con enlaces simbólicos, puede seguir usando las existentes COPY instrucción. Es debido a estos cambios incompatibles hacia atrás que --link es un indicador opcional, en lugar del nuevo valor predeterminado.

Resumen

BuildKit COPY --link es una nueva característica de Dockerfile que puede hacer que las compilaciones sean más rápidas y eficientes. Las imágenes que usan copias vinculadas no necesitan extraer capas anteriores solo para que los archivos se puedan copiar en ellas. Docker crea una nueva capa independiente para cada COPY en su lugar, luego vincula esas capas nuevamente en la cadena.

Puede comenzar a usar copias vinculadas ahora si está creando imágenes con BuildKit y la última versión de Buildx o Docker CLI. La adopción de “–link” es un nuevo paso de compilación de mejores prácticas de Docker, siempre que no se vea afectado por los cambios en la resolución de la ruta de destino que requiere.

Subir Change privacy settings