Cree imágenes de Docker delgadas para aplicaciones Dart

Si ha utilizado Docker para ejecutar su aplicación Dart en un entorno en contenedores (como Google Kubernetes Engine o Cloud Run ), es posible que se haya sorprendido del peso de la imagen de google / dart .

Basado en una imagen de Debian 10 “Buster” , google / dart está orientado al desarrollo, no optimizado para el tamaño, y actualmente pesa 682 MB.

tamaño de imagen de google / dart

Como Flutter , el conjunto de herramientas de la interfaz de usuario de Google para crear aplicaciones compiladas de forma nativa para dispositivos móviles , web y de escritorio a partir de una única base de código basada en Dart continúa creciendo en popularidad, el interés en usar Dart para implementar la funcionalidad de backend también ha aumentado.

Sin embargo, debido al enfoque en el desarrollo del lado del cliente, ha habido poca orientación sobre cómo optimizar el tamaño de la imagen para la implementación del lado del servidor.

En este artículo, le presentaré el dart-scratch , una imagen liviana basada en scratch que puede usar para crear la imagen más delgada posible para los contenedores de su aplicación Dart.

Entonces, ¿por qué es importante optimizar el tamaño de la imagen?

Cuando crea un contenedor en alguna máquina (física o virtual) por primera vez, la imagen utilizada para crear el contenedor debe viajar a través de la red desde un repositorio de imágenes en algún lugar (generalmente un registro como Docker Hub o Google Artifact Registry , por ejemplo) .

Existe un retraso en la transferencia de imágenes grandes que puede no ser un problema para los servidores de larga duración, pero el impuesto al rendimiento en la transferencia de imágenes grandes en un entorno de escalado dinámico que crea nuevas instancias de máquinas bajo demanda puede ser perjudicial.

Luego, cuando se está construyendo el contenedor, las capas de imágenes se leen desde la memoria caché de imágenes de la máquina. Los archivos más grandes obviamente toman más tiempo para leer, lo que significa un retraso más largo hasta que el contenedor está listo para hacer su trabajo.

Nuevamente, para los servidores de larga duración, esto puede no ser un problema importante, pero para las aplicaciones que necesitan responder rápidamente, los retrasos en la capacidad de respuesta se acumulan y pueden ser perceptibles para los usuarios. La eliminación de estos retrasos es especialmente crítica para las cargas de trabajo de escalado a cero que no consumen recursos (reduciendo así los costos), pero deben iniciar y ejecutar sus tareas rápidamente.

Rendimiento JIT vs AOT

Finalmente, una cosa más que afecta negativamente el tiempo de inicio es que el código de Dart se compila justo a tiempo (JIT) cuando se ejecuta en la máquina virtual de Dart. Iniciar un servidor puede tardar varios segundos antes de que esté listo para comenzar a escuchar en un socket.

Como se mencionó anteriormente, esto puede no ser un problema para algunas aplicaciones, pero esto puede ser muy indeseable en un entorno dinámico de escalado automático donde la capacidad de respuesta es importante.

Para solucionar este problema, se puede compilar una aplicación Dart con anticipación (AOT) en código de máquina usando dart2native . Esto proporciona un tiempo de inicio drásticamente mejorado.

Desafortunadamente, hay una trampa. Actualmente, dart2native no admite la reflexión (que se basa en dart: mirrors ). Las anotaciones de metadatos tienden a ser populares en varios servidores web, modelado de datos, serialización y marcos y bibliotecas de inyección de dependencia, por ejemplo.

Para los tipos de aplicaciones más breves y con un enfoque más estrecho que representan las cargas de trabajo típicas de Función como servicio, esto puede no ser un problema en absoluto. Para tipos de aplicaciones web más grandes y complejas que necesitan aprovechar marcos sofisticados, el soporte de anotaciones puede ser indispensable para usted.

Consulte esta página de preguntas frecuentes y documentos si desea obtener más detalles sobre el rendimiento y las limitaciones de JIT frente a AOT.

Utilice dardo-scratch para imágenes delgadas basadas en AOT o JIT

Si desea el lanzamiento de la aplicación más rápido posible y no necesita la reflexión de Dart (para soporte de anotaciones, por ejemplo), utilice Dart-scratch como se muestra a continuación. Esto construirá su aplicación usando dart2native .

Una imagen de aplicación de servidor mínima será de alrededor de 25 MB y cuando se crea un contenedor, la aplicación se iniciará en menos de un segundo. Esto es muy adecuado para funciones como servicio y otros tipos de trabajos que deben ejecutarse y escalar rápidamente.

Dockerfile de varias etapas para crear una imagen delgada con la aplicación compilada AOT:

 DE google / dart
# elimine el comentario de la siguiente línea para garantizar el último paquete de CA raíz y Dart
#RUN apt -y update && apt -y upgrade
WORKDIR / aplicación
COPIA pubspec. *.
RUN pub obtener
COPIAR . .
RUN pub get - sin conexión
EJECUTAR dart2native /app/bin/server.dart -o / app / bin / server
 DESDE subfuzion / dart-scratch
COPIA --desde = 0 / aplicación / bin / servidor / aplicación / bin / servidor
# COPIAR cualquier otro directorio o archivo que pueda necesitar en tiempo de ejecución, por ejemplo:
#COPY --desde = 0 / app / static / / app / static /
EXPONER 8080
ENTRYPOINT ["/ app / bin / server"]

Como se explicó anteriormente, si su aplicación depende de dart: mirrors, entonces no puede usar dart2native, por lo que deberá crear una imagen que use Dart VM.

Una imagen de aplicación de servidor mínima será de alrededor de 50 MB y cuando se crea un contenedor, la aplicación puede tardar varios segundos antes de que esté lista para escuchar en un socket. Debido al aumento del tiempo de inicio, esto es más adecuado para aplicaciones de mayor duración, aplicaciones que son menos sensibles al tiempo de inicio del trabajo o aplicaciones que requieren soporte de reflexión (para anotaciones, por ejemplo).

Dockerfile de varias etapas para crear una imagen delgada con la aplicación compilada JIT:

 DE google / dart
# elimine el comentario de la siguiente línea para garantizar el último paquete de CA raíz y Dart
#RUN apt -y update && apt -y upgrade
WORKDIR / aplicación
COPIA pubspec. *.
RUN pub obtener
COPIAR . .
RUN pub get - sin conexión
 DESDE subfuzion / dart-scratch
COPIA --desde = 0 / usr / lib / dart / bin / dart / usr / lib / dart / bin / dart
COPIA --desde = 0 /root/.pub-cache /root/.pub-cache
# Copiar toda la aplicación ...
COPIA --desde = 0 / aplicación / aplicación
# ... o copie archivos y directorios específicos que necesite en tiempo de ejecución, por ejemplo:
#COPY --desde = 0 /app/bin/server.dart /app/bin/server.dart
#COPY --desde = 0 / app / lib / / app / lib /
#COPY --desde = 0 / app / static / / app / static /
EXPONER 8080
ENTRYPOINT ["/ usr / lib / dart / bin / dart", "/app/bin/server.dart"]

En conclusión, quiero mencionar que esto es actualmente experimental y no es compatible con Google mientras repito esto. Planeo centrarme a continuación en implementar un paquete de compilación que se pueda usar para transformar el código de Dart en imágenes que se puedan ejecutar en entornos sin servidor en la nube.

Si este dart-scratch no funciona para usted, o si tiene casos de uso que le gustaría compartir, abra un problema aquí en el repositorio .


La creación de imágenes de Docker delgadas para las aplicaciones de Dart se publicó originalmente en Google Cloud - Community on Medium, donde las personas continúan la conversación destacando y respondiendo a esta historia.