Versión actualizada en la cual se pueden encontrar algunas optimizaciones en los archivos de configuraciones y en las imágenes de Docker utilizadas.
En la actualidad es raro hablar de desplegar un proyecto y no hablar al mismo tiempo de Docker. Con Docker tenemos la posibilidad de que las aplicaciones estén aisladas en contenedores seguros que además de contener la aplicación, permita un mejor y más facil modo de controlarlas. La idea de este artículo, es mostrar como podemos de una manera sencilla y rápida, construir un proyecto de Angular y desplegarlo en una imagen de Docker.
Para dockerizar un proyecto de Angular, mostraremos 2 maneras a lo largo del artículo:
Para construir el proyecto Angular dentro de un contenedor de Docker es sencillo, solo tenemos que crear el archivo Dockerfile en el directorio de nuestro proyecto y copiar el siguiente código:
Dockerfile
FROM node:10.16.3
WORKDIR /app
COPY . ./
RUN npm install
RUN npm run build
Analizando el código línea a línea:
FROM node:10.16.3
: primeramente seleccionamos la imagen de Docker base a utilizarse, en el ejemplo se utiliza la imagen de node:10.16.3, pero esto depende de la versión de node que se desee para construir el proyectoWORKDIR /app
: luego definimos el directorio de trabajo, este paso es solo para organización y básicamente define en que directorio dentro del contenedor se van a ejecutar los comandos más adelanteCOPY . ./
: seguidamente se copia el proyecto dentro del contenedorRUN npm install
: instalamos las dependenciaRUN npm run build
: por último se construye el proyectoUna vez que el proyecto ha sido construido, lo que faltaría sería crear la imagen de Nginx y copiar el proyecto dentro. Para esto, primeramente se necesita crear un archivo de configuración de Nginx en el directorio del proyecto para posteriormente ser copiado dentro del contenedor. El archivo de configuración es el siguiente:
nginx.conf
server {
listen 80;
# send headers in one peace
tcp_nopush on;
# allow the server to close connection on non responding client, this will free up memory
reset_timedout_connection on;
# request timed out -- default 60
client_body_timeout 20;
# if client stop responding, free up memory -- default 60
send_timeout 20;
# server will close connection after this time -- default 75
keepalive_timeout 40;
# reduce the data that needs to be sent over network
gzip on;
gzip_min_length 200;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/x-javascript
application/json
application/x-web-app-manifest+json
application/xml
application/xhtml+xml
application/x-font-ttf
application/octet-stream
font/opentype
image/x-icon
image/svg+xml;
gzip_proxied expired no-cache no-store private auth;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_vary on;
gzip_disable msie6;
location / {
alias /usr/share/nginx/html/;
try_files $uri $uri/ /index.html;
}
}
Una vez creado el archivo de configuración de Nginx en el proyecto y asumiendo que se viene del primer paso, falta modificar el archivo Dockerfile de la siguiente manera:
Dockerfile
# Fijarse, que se le agregó (AS build-env) a esta línea
FROM node:10.16.3 AS build-env
WORKDIR /app
COPY . ./
RUN npm install
RUN npm run build
FROM nginx:1.13.9-alpine
COPY --from=build-env /app/dist/proyect-name/ /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
Con el soporte de múltiples imágenes de Docker es posible hacer lo que se ve en el ejemplo anterior, donde se hace uso de una segunda imagen, que será la base del contenedor. A continuación se explicarán los pasos añadidos:
FROM nginx:1.13.9-alpine
: se define la imagen final del contenedor a crearseCOPY --from=build-env /app/dist/dcs-frontend/ /usr/share/nginx/html
: se copian los archivos contruidos con la primera imagen de Node, haciendo referencia a esta por medio del parametro --from=build-env
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
: se copia el archivo de configuración de Nginx remplazando el existente en el contenedorCMD ["nginx", "-g", "daemon off;"]
: define el comando a ejecutarse al iniciar el contenedor de DockerEn caso de no utilizarse Docker para construir el proyecto, se hace necesario construirlo previamente y crear el Dockerfile con la configuración agregada en el paso 2. Por tanto lo primero que debe hacerse antes de construir la imagen de Docker es ejecutar los siguientes dos comando en un terminal en el directorio del proyecto:
npm install
npm run build
Básicamente instalamos las dependencias del proyecto y luego hacemos el build del mismo. A continuación pasaremos al paso dos directamente copiando los ficheros generados junto al archivo de configuración de Nginx descrito en el paso 2 y creamos el archivo de Docker con el siguiente código:
Dockerfile
FROM nginx:1.13.9-alpine
COPY ./dist/proyect-name/ /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
Una vez hecho esto la imagen del proyecto estará lista para construir nuestro contenedor de Docker con el proyecto y ponerlo en producción. Para ello podemos hacerlo de dos maneras: con docker-compose o directamente con Docker, a continuación se mostrarán ambas variantes:
Primeramente es necesario crear el archivo de configuración de docker-compose:
docker-compose.yml
version: '3'
services:
deploy:
build:
context: .
dockerfile: ./Dockerfile
restart: always
ports:
- '127.0.0.1:4000:80'
luego de crear este archivo en el directorio del proyecto solo falta ejecutar el siguiente comando y el proyecto estará listo en el puerto 4000 definido en las cofiguraciones.
docker-compose up --build
Sin el uso de docker-compose la imagen puede construirse de la siguiente manera:
docker build -t my-project .
Una vez construida la imagen levantamos el contenedor con ella:
docker run my-project -p 127.0.0.1:4000:80 --restart=always
Y de esta manera y con no más que 3 archivos de configuración se despliega el proyecto con Docker. No olviden dejarnos sus sugerencias si lo compartido en el artículo ha sido de ayuda.
Happy coding!