Skip to content

Creando imágenes a partir de múltiples imágenes con Dockerfiles

Multistage

Introducción

En entornos de desarrollo y producción modernos, la creación de imágenes de contenedor optimizadas y reutilizables es una práctica clave para lograr eficiencia, portabilidad y mantenibilidad. Una estrategia avanzada dentro de esta práctica consiste en la construcción de imágenes a partir de múltiples etapas o fuentes, utilizando Dockerfiles bien estructurados. Este enfoque permite construir imágenes más livianas, seguras y enfocadas en la funcionalidad específica de la aplicación.

Utilizar múltiples imágenes como base en diferentes etapas del Dockerfile es especialmente útil cuando se desea separar el entorno de compilación del entorno de ejecución, o cuando se requiere combinar dependencias específicas que provienen de distintas distribuciones o tecnologías. Esto no solo reduce el tamaño final de la imagen, sino que también minimiza la superficie de ataque y mejora la trazabilidad de los componentes.

Adoptar estas prácticas no solo ayuda a cumplir con estándares de calidad y seguridad, sino que también facilita el mantenimiento y la evolución del ciclo de vida de las aplicaciones contenidas. En este módulo aprenderás cómo estructurar correctamente tus Dockerfiles para aprovechar el poder de múltiples imágenes base y etapas, logrando resultados más eficientes y profesionales.

Objetivo General

Comprender y aplicar prácticas para la creación de imágenes de contenedor utilizando múltiples imágenes base y etapas en Dockerfiles, con el fin de construir imágenes optimizadas, seguras y eficientes que faciliten la portabilidad, el mantenimiento y la escalabilidad de aplicaciones en entornos modernos de desarrollo y producción.

Laboratorio: Creando imágenes a partir de múltiples imágenes con Dockerfiles

  1. Ingresar al servidor qué contiene al ambiente de laboratorio con credenciales de administración y cree un directorio llamada multi-stage.

    mkdir multi-stage
    
    cd multi-stage
    

  2. Cree un archivo llamado Dockerfile.nginx con el siguiente contenido

    1
    2
    3
    4
    5
    6
    FROM registry.suse.com/bci/bci-base:15.4
    LABEL description="Servicio de nginx en imagen opensuse"
    LABEL maintainer="John Doe <jdoe@xyz.com>"
    RUN zypper -n install nginx && zypper clean --all
    EXPOSE 80
    CMD ["nginx", "-g", "daemon off;"]
    

  3. Cree una imagen nueva con el tag opensuse-nginx:15.4

    docker build -t opensuse-nginx:15.4 -f Dockerfile.nginx .
    

  4. Clone el siguiente repositorio (Angular App) en la máquina local y acceda a la carpeta que contenga el repositorio. Bash/Sh shell:

    sudo dnf install git -y
    
    git clone https://gitlab.com/ITMGT/sample-angular-app.git
    
    cd sample-angular-app
    

  5. Cree una carpeta llamada docker

    mkdir docker
    

  6. Cree un archivo llamado Dockerfile.multistage dentro de la carpeta docker con el siguiente contenido

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    FROM registry.suse.com/bci/nodejs:14 AS build
    
    # Set the working directory
    WORKDIR /usr/local/app
    
    # Add the source code to app
    COPY ./ /usr/local/app/
    
    # Install all the dependencies
    RUN npm install
    
    # Generate the build of the application
    RUN npm run build
    

  7. Cree una imagen de prueba con el tag angular-app:0.0.1-build-only. Durante el proceso de construcción del app, se mostrarán algunas advertencias "WARN", en un caso real se deben validar y actualizar las versiones de las dependecias

    docker build -t angular-app:0.0.1-build-only -f docker/Dockerfile.multistage .
    

  8. Verifique los archivos que contiene la imagen iniciando un contenedor temporal

    docker run -it --rm angular-app:0.0.1-build-only ls -l dist/sample-angular-app
    

  9. Valide el espacio ocupado en disco por el ambiente de contrucción del app

    docker run -it --rm angular-app:0.0.1-build-only du -sh /usr/local/app/
    

  10. Valide el espacio ocupado en disco por el app construido

    docker run -it --rm angular-app:0.0.1-build-only du -sh /usr/local/app/dist/
    
    # Note que la diferencia es considerable
    

  11. Modifique el archivo docker/Dockerfile.multistage agregando el siguiente contenido, al final del archivo existente.

    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    FROM opensuse-nginx:15.4
    
    # Copy the build output to replace the default nginx contents.
    COPY --from=build /usr/local/app/dist/sample-angular-app /srv/www/htdocs/
    
    # Give permissions to write pid file to nginx user
    RUN touch /run/nginx.pid && chown -R nginx:nginx /run/nginx.pid
    
    # Use an user without root permissions
    USER nginx
    
    
    # Expose port 80
    EXPOSE 80
    

  12. Verificar que el Dockerfile se vea de la siguiente manera:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    FROM registry.suse.com/bci/nodejs:14 as build
    
    # Set the working directory
    WORKDIR /usr/local/app
    
    # Add the source code to app
    COPY ./ /usr/local/app/
    
    # Install all the dependencies
    RUN npm install
    
    # Generate the build of the application
    RUN npm run build
    
    FROM opensuse-nginx:15.4
    
    # Copy the build output to replace the default nginx contents.
    COPY --from=build /usr/local/app/dist/sample-angular-app /srv/www/htdocs/
    
    # Give permissions to write pid file to nginx user
    RUN touch /run/nginx.pid && chown -R nginx:nginx /run/nginx.pid
    
    # Use an user without root permissions
    USER nginx
    
    
    # Expose port 80
    EXPOSE 80
    

  13. Crear una nueva imagen con el tag angular-app:0.0.1

    docker build -t angular-app:0.0.1 -f docker/Dockerfile.multistage .
    

  14. Inspeccione las imágenes creadas

    docker image inspect \
    angular-app:0.0.1-build-only angular-app:0.0.1 \
    --format='{{println .RepoTags}}{{range .RootFS.Layers}}{{println . }}{{end}}'
    
    docker images | grep angular
    

  15. Inicia un contenedor con la imagen que se creó.

    docker run --name=angular-app -p 30080:80 -d angular-app:0.0.1
    

  16. Verificar funcionamiento. Desde su navegador de Internet acceda a su HOST de Prueba. Ejecute el siguiente comando, para obtener su dirección ip.

    HOST_EXTERNAL_IP=$(curl -s http://showip.net)
    echo http://${HOST_EXTERNAL_IP}:30080
    

Limpieza de ambiente

Limpiar el ambiente deteniendo y eliminando los recursos

docker stop angular-app
docker rm angular-app
docker image rm opensuse-nginx:15.4
docker image rm angular-app:0.0.1-build-only
docker image rm angular-app:0.0.1
cd ~/ ; rm -fr sample-angular-app