Implementar tu aplicación web en un contenedor usando tecnología OpenSource — Analogía Pokemón

Maureenbarahona
7 min readMay 8, 2021

--

Antesal

Estoy haciendo esta guía para que sea mas fácil implementar una aplicación web y lanzarla desde cero. Aunque se hablara de como preparar un proyecto y almacenarlo en un repositorio sera de manera bien básica ya que el objetivo es ver nuestra aplicación contenida y ejecutándose en un navegador . Pero tratare de ser lo mas especifica en cada paso. Esto lo realice para el Festival Latinoamericano de Software Libre (Flisol 2021)

Crear una React Application

Antes de crear la app , necesitamos instalar node.js (Omitir este paso si ya lo tienen) Desde el terminal ejecutar lo siguiente:

sudo apt-get update
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install nodejs
sudo apt-get install npm

Siguiendo , crearemos una aplicación en reactjs dentro de una carpeta donde almacenaras tus proyectos.

sudo npx create-react-app primera_app
cd primera_app
sudo npm start

Tips:

Si su carpeta esta con candado , desde el terminal tiene que dar permisos a la carpeta con : sudo chmod -R 777 <nombre de la carpeta>

Desde tu terminal se miraría algo parecido a esto y desde el navegador estaría tu aplicación ejecutándose -tips: Usa la tecla Ctrl+c para detener la ejecución

Analogía Pokemón.

He estado pensando cual seria la manera mas fácil de explicar que es docker y que es kubernetes que hasta un niño lo pudiera entender . Y me inspire en pokemón.

Imaginémonos que cada pokebola tiene que ser un ecosistema único para adaptarse a la comodidad de cada pokemón (Mi aplicación puede estar en una versión x o y fuera de la que tengo instalada en mi maquina). Lo fantástico de esto es que podemos tener cada pokebola junta sin afectar el ecosistema de cada pokemón. Cada pokebola seria una aplicación dockerizada con la estructura necesaria para que la aplicación funcione.

Configurando mi Docker container

Uno de los pasos es instalar Docker en nuestras maquinas , esto es con Ubuntu pero si necesitan otra distro pueden leer la documentacion https://docs.docker.com/engine/install/ubuntu/

Probando Una Imagen de Docker (postgress) Esto esta en el dockerhub https://hub.docker.com/_/postgres

docker run postgres

docker run -e POSTGRES_PASSWORD=password postgres

Vamos a crear un build de nuestras aplicación :

cd cloud-challenge
sudo npm run build

Puede crear su cuenta de Docker.

Creando mi Docker ID

Abrir mi proyecto en VSCodium

Me situó en la carpeta o esta edición la pueden hacer desde VIM

touch Dockerfile

Editamos nuestro Dockerfile

# pull official base image
FROM node:13.12.0-alpine

# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# install app dependencies
COPY package.json ./
COPY package-lock.json ./
RUN npm install
RUN npm install react-scripts@3.4.1 -g

# add app
COPY . ./

# start app
CMD ["npm", "start"]

Aquí hay una descripción general de los comandos:

  • FROM : Define la imagen que usaremos como base para nuestro contenedor. En este contexto, usamos Node Version 13.12.0, el (-alpine) es una distribucion construida especificamente para imagenes de Docker.
  • LABEL : define los metadatos de nuestro Dockerfile, incluida información sobre la versión, descripción y mantenedores. (No lo usamos en este ejemplo)
  • ENV : Para facilitar la ejecución de nuevos software, o manejar nuestras vairables de entorno de una manera mas dinámica.
  • WORKDIR : Establece el directorio de trabajo de la aplicación. Si el directorio de trabajo aún no existe, Docker lo crea.
  • COPY: Copie un archivo o archivos en el contenedor de Docker. En la línea 11, enumeramos varios archivos para copiar y luego especificamos dónde copiarlos. La ruta final especificada es la ubicación en la que se copian los archivos (en este caso, el directorio de trabajo).
  • RUN : especifica un comando que debe ejecutar Docker. Normalmente uso este comando para instalar dependencias, depurar y ejecutar comandos en el contenedor. En este contexto, ejecutamos npm install — production para instalar solo dependencias de producción.
  • EXPOSE : Le dice a Docker en qué puertos debe escuchar el contenedor durante el tiempo de ejecución. En este contexto, exponemos el puerto 3000 ya que ese es el puerto en el que se está ejecutando React.
  • CMD : especifica el comando que se debe ejecutar cuando se inicia el contenedor de la ventana acoplable. En este contexto, ejecutamos npm start ya que ese es el comando que inicia la interfaz.

Agregamos .dockerignore con el proposito de pasar nuestro proyecto lo mas liviano posible , eso permitira que por ejemplo nuestras dependencias locales dentro de “node_modules” no se envien al demonio de Docker.

node_modules
build
.dockerignore
Dockerfile
Dockerfile.prod

Cree y etiquete la imagen de Docker:

$ docker build -t primera_app:dev .

Vamos a ejecutar el contenedor una vez que la construcción este lista:

$ docker run \
-it \
--rm \
-v ${PWD}:/app \
-v /app/node_modules \
-p 3001:3000 \
-e CHOKIDAR_USEPOLLING=true \
primera_app:dev

¿Que esta pasando aquí?

  1. El comando docker run crea y ejecuta una nueva instancia de contenedor a partir de la imagen que acabamos de crear.
  2. -itinicia el contenedor en modo interactivo . ¿Por qué es esto necesario? A partir de la versión 3.4.1 , react-scripts sale después del inicio (a menos que se especifique el modo CI), lo que hará que el contenedor salga. De ahí la necesidad de un modo interactivo.
  3. --rm quita el contenedor y los volúmenes después de que el contenedor sale.
  4. -v ${PWD}:/app monta el código en el contenedor en "/ app".
  5. Dado que queremos utilizar la versión de contenedor de la carpeta “node_modules”, hemos configurado otro volumen: -v /app/node_modules. Ahora debería poder eliminar el sabor local "node_modules".
  6. -p 3001:3000 expone el puerto 3000 a otros contenedores Docker en la misma red (para la comunicación entre contenedores) y el puerto 3001 al host.
  7. Por último, -e CHOKIDAR_USEPOLLING=true permite un mecanismo de votación a través de chokidar (que envuelve fs.watch, fs.watchFiley fsevents) para que el trabajo voluntad-recarga caliente.

Abra su navegador en http: // localhost: 3001 / y debería ver la aplicación. Intente realizar un cambio en el Appcomponente dentro de su editor de código. Debería ver la aplicación de recarga en caliente. Mata al servidor una vez hecho.

Agregando Docker compose

Es una herramienta para definir y ejecutar aplicaciones Docker multicontenedor que permite simplificar el uso de Docker a partir de archivos YAML, de está forma es mas sencillo crear contendores que se relacionen entre sí, conectarlos, habilitar puertos, volumenes, etc. Nos permite lanzar un solo comando para crear e iniciar todos los servicios desde su configuración(YAML), esto significa que puedes crear diferentes contenedores y al mismo tiempo diferentes servicios en cada contenedor, integrarlos a un volumen común e iniciarlos y/o apagarlos, etc. Este es un componente fundamental para poder construir aplicaciones y microservicios.
Docker-Compose funciona en todos los entornos: production, staging, development, testing, así como flujos de trabajo basados en Continuous Integration(CI).
Si quieres conocer más acerca de Docker-Compose ve a la documentación oficial https://docs.docker.com/compose/#features

Agregamos docker-compose.yml en la raiz

version: '3.7'

services:

sample:
container_name: primera_app
build:
context: .
dockerfile: Dockerfile
volumes:
- '.:/app'
- '/app/node_modules'
ports:
- 3001:3000
environment:
- CHOKIDAR_USEPOLLING=true

Toma nota de los volúmenes. Sin el volumen anónimo ( '/app/node_modules'), el directorio node_modules sería sobrescrito por el montaje del directorio de host en tiempo de ejecución. En otras palabras, esto sucedería:

  • Construir : el node_modulesdirectorio se crea en la imagen.
  • Ejecutar : el directorio actual se monta en el contenedor, sobrescribiendo el node_modulesque se instaló durante la compilación.

Construye la imagen y enciende el contenedor:

$ docker-compose up -d --build

Asegúrese de que la aplicación se esté ejecutando en el navegador y vuelva a probar la recarga en caliente. Baje el contenedor antes de continuar:

$ docker-compose stop

Crear Dockerfile para Producción

Creemos un Dockerfile separado para usar en producción llamado Dockerfile.prod :

# build environment
FROM node:13.12.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm ci
RUN npm install react-scripts@3.4.1 -g
COPY . ./
RUN npm run build

# production environment
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Aquí, aprovechamos el patrón de compilación de varias etapas para crear una imagen temporal que se utiliza para construir el artefacto, los archivos estáticos de React listos para producción, que luego se copian en la imagen de producción. La imagen de compilación temporal se descarta junto con los archivos y carpetas originales asociados con la imagen. Esto produce una imagen ajustada y lista para la producción.

Con el Dockerfile de producción, cree y etiquete la imagen de Docker:

$ docker build -f Dockerfile.prod -t primera_app:prod .

Ejecutar el contenedor:

$ docker run -it --rm -p 1337:80 primera_app:prod

Vaya a http: // localhost: 1337 / en su navegador para ver la aplicación.

Pruebe con un nuevo archivo Docker Compose también llamado docker-compose.prod.yml :

version: '3.7'

services:

sample-prod:
container_name: primera_app-prod
build:
context: .
dockerfile: Dockerfile.prod
ports:
- '1337:80'

Ejecutar el contenedor , (Recuerde detenerlo cuando termine)

$ docker-compose -f docker-compose.prod.yml up -d --build

Lo que sigue…

Es que puedas subir cualquier proyecto y escalarlo a tus necesidades. Recuerda ser un buen entrenador pokemon.

--

--

Maureenbarahona
Maureenbarahona

Written by Maureenbarahona

Cloud GDE - DevOps/SRE Engineer /Co-Organizer in @DevTeam504 /Organizer in @cncfHonduras /ambassador at phi-economy, /Woman Techmakers Ambassador

No responses yet