DEV Community

Cover image for Angular + Docker... really?
Falcon
Falcon

Posted on • Updated on

Angular + Docker... really?

Este es un tutorial básico de docker para Front end developers, de igual forma los conceptos explicados acá, se pueden usar como base para dockerizar cualquier otra app creada en otro lenguaje ó framework.

Cuando el Big Bang de microservicios sucedió, se dice que surgió de las profundidas un concepto que en su tiempo fue innovador y de gran utilidad, los dioses le llamaron "Máquinas virtuales (VM)". Las máquinas virtuales tienen un sistema operativo completo con su propia administración de memoria instalada con la sobrecarga asociada de los controladores de dispositivos virtuales. En una máquina virtual, se emulan recursos valiosos para el SO huésped y el hipervisor, lo que hace posible ejecutar muchas instancias de uno o más sistemas operativos en paralelo en una sola máquina (o host). Cada sistema operativo invitado se ejecuta como una entidad individual del sistema host.

Todo iba funcionando de maravilla, pero como siempre, nada es perfecto. Costos de mantenimiento del hardware, dinero, esos demonios que rodean nuestros desarrollos, comenzaron a salir de la oscuridad y abrumar el paraíso de las máquinas virtuales. Las VMs son hardware dependientes, lo cual las hacen más $$ de usar e implementar, además al tener un sistema operativo invitado, estaban consumiendo más memoria de lo esperado. Cuando todos empezaban a desesperarse, desde el mismo océano, surgió la esperanza, una pequeña ballena trajo la respuesta: contenedores.

Alt Text

Tomado de https://www.testautomationguru.com

Contenedores, docker.

Los contenedores son más pequeños que las máquinas virtuales y permiten un arranque más rápido con un mejor rendimiento, menos aislamiento y una mayor compatibilidad posible debido al uso compartido del núcleo del host. La mejor opción para ejecutar una arquitectura de aplicación de microservicios son los contenedores de aplicaciones. En términos simples, Docker es una plataforma de software que simplifica el proceso de creación, ejecución, administración y distribución de aplicaciones. Lo hace virtualizando el sistema operativo de la computadora en la que está instalado y ejecutándose.

Conceptos básicos

  • Dockerfile: Un Dockerfile es un documento de texto que contiene todos los comandos que un usuario podría llamar en la línea de comandos para ensamblar una imagen.

  • Docker image: Es un archivo ejecutable que contiene todas las bibliotecas y configuraciones necesarias para ejecutar la aplicación. Tiene varias capas apiladas una encima de la otra y representadas como un solo objeto. Una imagen es creada, usando un Dockerfile.

  • Docker container: Es una instancia en ejecución de un docker image. Puede haber muchos contenedores ejecutándose en base a la misma imagen.

"Contenerizar" un Angular app

Para motivos de este post, yo estoy suponiendo que usted ya tiene instalado NPM y Angular CLI, siendo así, vamos a crear un Angular app.

ng new angular-docker

Ok, vamos a crear un dockerfile y se tiene que guardar dentro de nuestra carpeta angular-docker. Este archivo no tiene extensión y se llama Dockerfile. A continuación agregar el siguiente código a dockerfile:

FROM node:latest as node

ARG ENV=prod
ARG APP=angular-docker

ENV ENV ${ENV}
ENV APP ${APP}

WORKDIR /app
COPY ./ /app/

# Instala y construye el Angular App
RUN npm ci
RUN npm run build --prod
RUN mv /app/dist/${APP}/* /app/dist/

# Angular app construida, la vamos a hostear un server production, este es Nginx

FROM nginx:1.13.8-alpine

COPY --from=node /app/dist/ /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/default.conf

Ok, hasta aquí muy lindo y todo ¿ Pero que rayos significa lo que está en el Dockerfile?

FROM node:latest as node : Las aplicaciones de Angular necesitan node and npm para instalar sus dependencias, de igual forma podrías usar yarm pero esto sería otra historia. Entonces, acá lo que estamos haciendo es usar la última version de node, la cual guardaremos en una capa llamada node (puedes escoger cualquier nombre).

WORKDIR /app: Este establece el directorio de trabajo para nuestro código en la imagen, es utilizado por todos los comandos posteriores como COPY, RUN y CMD.

COPY ./ /app/: Este comando copia todos los archivos existentes en el proyecto a la carpeta /app de nuestra imagen de docker.

RUN npm ci: El comando npm ci tiene la misma funcionalidad de instalar dependencias como npm install pero a diferencia, que npm ci primero borra la carpeta node_modules, luego instala las versiones exactas de las dependencias del proyecto usando elpackaje.json.lock. Este comando es recomendando cuando estás trabajando con herramientas de CI/CD como Travis, Jenkins, Concourse.

RUN npm run build --prod: El comando build crea una nueva carpeta llamada dist para su distribución. Estos son los archivos que podemos alojar en un servidor y que nuestra aplicación Angular cargará. El flag --prod crear una versión más optimizada y pequeña de nuestra app.

RUN mv /app/dist/${APP}/* /app/dist/ : Movemos todo lo creado por el comando anterior en la carpeta app/dist.

Hasta acá, nuestra imagen ya contiene la versión mas optimizada de nuestro proyecto, pero no basta con eso, recordemos que Angular es solo HTML, CSS y JS, necesita un server/proxy para poder hostearse y ser accesible para los usuarios. Mi server favorito para aplicaciones web, es NGINX.

FROM nginx:1.13.8-alpine: En este comando vamos a crear una segunda capa, la cual contiene la versión 1.13.8-alpine de nginx.

COPY --from=node /app/dist/ /usr/share/nginx/html: En este comando sucede mucha magia, como decimos en Costa Rica, pele el ojo. Vamos a tomar los contenidos de la carpeta app/dist/ generados en la primer capa llamada node y los vamos a mover al folder /usr/share/nginx/html de nuestro server NGINX. Acá estamos viendo la magia de los multi-stages de docker.

Alt Text

COPY ./nginx.conf /etc/nginx/conf.d/default.conf: Por último, solamente copiamos un archivo de configuración de nginx en el folder del contenedor. Les dejo el link de mi configuración https://github.com/gelopfalcon/kubernetes-fundamentals/blob/master/contact-list-master/nginx.conf

Construir la imagen

docker build -t my-angular-docker .

El comando anterior nos permite crear una imagen en nuestro entorno local. Podemos asegurarnos de que exista, usando docker images la cual desplega las imagenes que hemos creado o descargado de algún registry.

Construir contenedor

docker container run -p 8080:80 --name myapp my-angular-docker.

Estamos creando un container llamado myapp en base a la imagen my-angular-docker.

-p 8080:80: Nuestro container necesita ser accesible fuera de docker. Entonces las solicitudes hechas por el puerto 8080 de nuestro server host, serán escuchadas por el puerto 80 de nuestro container. Recordemos que nuestro container myapp tiene un server NGINX con un Angular app hosted, la cual es accesible por el 80.

Asegúrese que su container está funcionando correctamente, docker ps mostrará los containers corriendo y sus status. Bueno, si no hay ningún problema, abrir tu browser favorito y acceder a tu container http://localhost:8080.

Si quieres detener el container solo debes docker stop <NAME> para nuestro caso sería docker stop myapp, una vez detenido el container, no deberías ser capaz de acceder tu app desde el browser, hasta que vuelvas a activarlo. Para hacer eso, basta con docker start myapp.

Alt Text

Gracias por su atención, estamos haciendo un gran esfuerzo para que la comunidad hispano-parlante también pueda colaborar con contenidos. Los invito a seguirme en twitter y también en comunidades como GDG Pura vida donde regularmente se hacen eventos gratuitos para la comunidad.

Top comments (1)

Collapse
 
raulsesaj profile image
RICARDO RAUL JACINTO MONTES

Hola, hope you can help me out

Segui todo el proceso como se describe en el blog, pero no puedo avanzar porque siempre llego a este punto

mv: cannot stat '/app/dist/angular-docker/': No such file or directory
The command '/bin/sh -c mv /app/dist/${APP}/
/app/dist' returned a non-zero code: 1

el dockerfile se encuentra en la raiz de la app y es idéntico a lo que se reporta en el blog. He tratado diferentes cosas, des de /app/${APP}/* pero no puedo avanzar. Segun entiendo esa trayectoria se construye en la imagen, pero si no alcanzo a construirla no puedo saber si existe o no.

Algun consejo?
Thanks in advance