DEV Community

Cover image for Guía Practica de Contenedores: Contenerizando nuestra API con Docker y Docker Compose (2/3)
crisemcon
crisemcon

Posted on • Updated on

Guía Practica de Contenedores: Contenerizando nuestra API con Docker y Docker Compose (2/3)

(Esta es la segunda parte de una guía practica sobre contenedores que abarca el desarrollo de un API CRUD, el uso de Docker para la contenerizacion de la aplicación, la incorporación de Docker Compose para la sincronización de múltiples contenedores, y finalmente Kubernetes para la orquestación de los contenedores que conforman la aplicación que desarrollaremos.) Codigo Fuente

En esta oportunidad utilizaremos Docker para construir una imagen de Node.js que incluya nuestra API CRUD desarrollada en la guía anterior. Luego ejecutaremos el contenedor y descubriremos la necesidad de incorporar mas contenedores. Debido a esto, utilizaremos Docker Compose para ejecutar en simultaneo 3 contenedores: Uno ejecutando nuestro servidor Node.js, otro ejecutando MySQL y el ultimo ejecutando PhpMyAdmin. Esto se puede visualizar en el siguiente diagrama:

docker compose diagram


1) Requisitos

Primero instalaremos las tecnologías necesarias para el desarrollo de esta guía: Docker y Docker-Compose.
Si ya posees las tecnologías mencionadas anteriormente y las de la primera parte de la guía, puedes saltarte a la sección 2

1.1) Instalando Docker

Existen varios métodos para instalar Docker, pero en esta guía instalaremos Docker usando el repositorio.
Primero, configuramos el repositorio con los siguientes comandos de terminal:

sudo apt-get update
sudo apt-get install \
   apt-transport-https \
   ca-certificates \
   curl \
   gnupg \
   lsb-release
Enter fullscreen mode Exit fullscreen mode

Luego agregamos la clave GPG oficial de Docker con:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Enter fullscreen mode Exit fullscreen mode

El siguiente paso es configurar el repositorio estable:

echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Enter fullscreen mode Exit fullscreen mode

Finalmente instalamos la última versión de Docker Engine y Containerd:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
Enter fullscreen mode Exit fullscreen mode

Podemos verificar que Docker Engine está instalado correctamente ejecutando la imagen hello-world:

sudo docker run hello-world
Enter fullscreen mode Exit fullscreen mode

Mas detalles acerca este paso en: https://docs.docker.com/engine/install/ubuntu/


1.2) Instalando Docker Compose

Primero, descargamos la versión estable actual de Docker Compose:

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Enter fullscreen mode Exit fullscreen mode

Luego aplicamos permisos ejecutables al binario:

sudo chmod +x /usr/local/bin/docker-compose
Enter fullscreen mode Exit fullscreen mode

Finalmente verificamos la versión de Docker Compose para comprobar que la instalacion fue exitosa:

docker-compose --version
Enter fullscreen mode Exit fullscreen mode

Mas detalles acerca este paso en: https://docs.docker.com/compose/install/


2) Contenerizando nuestra aplicación Node.js

Primero necesitamos crear un Dockerfile (documento de texto que contiene todos los comandos que un usuario puede llamar en la línea de comandos para ensamblar una imagen) en nuestro directorio de proyecto:

touch Dockerfile
Enter fullscreen mode Exit fullscreen mode
FROM node:14

WORKDIR /app

COPY package*.json ./

RUN npm install
RUN npm install -g nodemon

COPY script.js ./

CMD ["nodemon","script.js"]
Enter fullscreen mode Exit fullscreen mode

La primera sentencia indica que vamos a utilizar Node.js v14 como nuestra imagen base.
Luego configuramos nuestro directorio de trabajo, que en nuestro caso será una carpeta llamada “app” y contendrá nuestros archivos.
A continuación copiamos tanto package.json como package-lock.json en nuestro directorio de trabajo. Este archivo contiene los nombres de los paquetes necesarios para ejecutar nuestra aplicación.
Luego queremos que el contenedor instale las dependencias con el comando RUN. Además, copiamos nuestro archivo principal “script.js”.
Finalmente le decimos al contenedor que ejecute el comando “nodemon script.js” para iniciar el servidor cuando el contenedor comience a ejecutarse.

Ahora construimos nuestra imagen con el siguiente comando:

sudo docker build -t node-restapi .
Enter fullscreen mode Exit fullscreen mode

Deberíamos obtener una respuesta como la siguiente:
docker build

Como recordamos, configuramos nuestro servidor para que se ejecute en el puerto 8080. Sin embargo, ahora ese será el puerto dentro del contenedor.
Entonces, cuando queremos ejecutar nuestro contenedor, tenemos que adjuntar un puerto de nuestra máquina local al puerto del contenedor.
Eso se logra con el parámetro “-p 7000: 8080”. En ese caso, el puerto 7000 se conectará al puerto 8080 del contenedor.
Además, queremos ejecutar el contenedor con una terminal interactiva para imprimir el estado del servidor. Para eso, agregamos el parámetro “-it”. El comando completo es el siguiente:

sudo docker run -it -p 7000:8080 node-restapi
Enter fullscreen mode Exit fullscreen mode

docker run -it -p

En el log mostrado en la terminal podemos apreciar que nuestro contenedor no se pudo conectar correctamente a la base de datos. Esto sucede porque el contenedor no tiene nuestra base de datos, pues está en nuestra máquina local. Esto sera resuelto en la siguiente sección mediante Docker Compose.

Ahora nuestro contenedor se está ejecutando. Abrimos otra terminal para ver todos los contenedores en ejecución:

sudo docker ps
Enter fullscreen mode Exit fullscreen mode

docker ps

Si intentamos realizar una petición GET a la ruta http://localhost:7000/students, vemos el siguiente error en la terminal del contenedor:
get error docker

Esa es una buena señal. Nuestro servidor intenta manejar la petición, pero registra un error porque no puede conectarse a la base de datos para consultar la solicitud. Esto es lo que vamos a resolver en el siguiente apartado.


3) Contenerizando nuestra base de datos y sincronizando nuestra aplicación basada en contenedores con Docker Compose

En esta sección vamos a ejecutar 3 contenedores simultáneamente:

  • Servidor Node.js
  • Base de datos MySql
  • Administrador de base de datos PhpMyAdmin.

Primero, necesitamos hacer un par de cambios en algunos archivos. Editemos nuestro archivo script.js, específicamente el objeto mysqlConnection:

Antes:

//MySQL details
var mysqlConnection = mysql.createConnection({
 host: "localhost",
 user: "root",
 password: "password",
 database: "studentmanagement",
 multipleStatements: true,
});
Enter fullscreen mode Exit fullscreen mode

Despues:

var mysqlHost = process.env.MYSQL_HOST || 'localhost';
var mysqlPort = process.env.MYSQL_PORT || '3306';
var mysqlUser = process.env.MYSQL_USER || 'root';
var mysqlPass = process.env.MYSQL_PASS || 'password';
var mysqlDB = process.env.MYSQL_DB || 'studentmanagement';

//MySQL details
var mysqlConnection = mysql.createConnection({
 host: mysqlHost,
 port: mysqlPort,
 user: mysqlUser,
 password: mysqlPass,
 database: mysqlDB,
 multipleStatements: true,
});
Enter fullscreen mode Exit fullscreen mode

Este cambio es para usar la variable de entorno del contenedor para configurar el usuario, la contraseña, el puerto, el host y la base de datos de MySQL.

Anteriormente, expusimos el puerto 8080 del contenedor manualmente en la terminal, pero puede ser configurado en el Dockerfile:

Antes:

FROM node:14

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY script.js ./

CMD ["node","script.js"]
Enter fullscreen mode Exit fullscreen mode

Despues:

FROM node:14

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY script.js ./

EXPOSE 8080

CMD ["node","script.js"]
Enter fullscreen mode Exit fullscreen mode

Ahora construimos nuestra nueva imagen con el siguiente comando:

sudo docker build . -t nodejs-studentmanagement
Enter fullscreen mode Exit fullscreen mode

Luego vamos a crear el archivo docker-compose.yml, que describe los servicios, redes, variables de entorno y comunicación entre los contenedores:

touch docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

Como mencionamos, necesitamos tres servicios: nodejs, mysql y phpmyadmin. Además, vamos a tener dos redes: frontend y backend. La red de backend contendrá los tres servicios y la red de frontend solo el servicio Node.js.

Además, conectaremos el puerto 30001 al 8080 de nuestro contenedor Node.js y el puerto 30002 al puerto 80 del servicio PhpMyAdmin. El archivo docker-compose.yml debe contener lo siguiente:

La imagen de MySQL 5.7 habilita por defecto el puerto 3306 para conexiones entrantes, mientras que PhpMyAdmin habilita por defecto el puerto 80 para conexiones entrantes.

version: "3.2"
services:
        nodejs:
           build:
               context: .
           image: nodejs-studentmanagement
           depends_on:
               - mysql
           networks:
               - frontend
               - backend
           environment:
               - MYSQL_HOST=mysql-studentmanagement
               - MYSQL_USER=smuser
               - MYSQL_PASS=smpass
               - MYSQL_DB=studentmanagementdb
           volumes:
               - ./www/:/var/www/html
           ports:
               - "30001:8080"
           container_name: nodejs-studentmanagement
        mysql:
           image: mysql:5.7
           networks:
               - backend
           environment:
               - MYSQL_ROOT_PASSWORD=root
               - MYSQL_USER=smuser
               - MYSQL_PASSWORD=smpass
               - MYSQL_DATABASE=studentmanagementdb
           container_name: mysql-studentmanagement
        phpmyadmin:
           image: phpmyadmin/phpmyadmin:4.7
           depends_on:
               - mysql
           networks:
               - backend
           ports:
               - "30002:80"
           environment:
               - PMA_HOST=mysql-studentmanagement
               - PMA_PORT= 3306
           volumes:
               - /sessions
           container_name: phpmyadmin-studentmanagement
networks:
        frontend:
        backend:
Enter fullscreen mode Exit fullscreen mode

Finalmente usamos docker-compose para construir y ejecutar los tres contenedores, manteniendo las dependencias entre ellos:

sudo docker-compose up
Enter fullscreen mode Exit fullscreen mode

Ahora los tres contenedores están funcionando.
A continuacion necesitamos configurar la base de datos. Para ello, utilizaremos PhpMyAdmin, que está adjunto al puerto 30002.
Abrimos nuestro navegador y navegamos a http: //localhost:30002 e iniciamos sesión con las credenciales descritas en el docker-compose.yml:

  • User: smuser
  • Password: smpass

Ahora usamos nuestra base de datos "studentmanagementdb" y hacemos una consulta SQL para crear nuestra tabla de estudiantes:
use studentmanagementdb

CREATE DATABASE studentmanagement;
USE studentmanagement;
CREATE TABLE student (student_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,student_name VARCHAR(50),student_email VARCHAR(100), student_phone VARCHAR(15));
Enter fullscreen mode Exit fullscreen mode

Además, necesitamos nuestro procedimiento almacenado para identificar las solicitudes de agregar/editar:
mysql stored procedure

DELIMITER //

CREATE PROCEDURE `studentAddOrEdit`(
IN _student_id INT,
IN _student_name VARCHAR(50),
IN _student_email VARCHAR(100),
IN _student_phone VARCHAR(15)
)
BEGIN
IF _student_id = 0 THEN
INSERT INTO student(student_name,student_email,student_phone)
VALUES (_student_name,_student_email,_student_phone);
ELSE
UPDATE student
SET
student_name = _student_name,
student_email = _student_email,
student_phone = _student_phone
WHERE student_id = _student_id;
END IF;
SELECT _student_id AS 'student_id';
END //
Enter fullscreen mode Exit fullscreen mode

Nos aseguramos de que se haya creado correctamente navegando a la pestaña Rutinas:
Routines


4) Probando nuestra API con Postman

Podemos hacer una petición POST para registrar un estudiante con Postman:

post student

Podemos hacer una petición POST para registrar otro estudiante:
post student postman

Podemos realizar una petición GET para obtener los estudiantes con el navegador, que realiza peticiones HTTP GET por defecto al navegar a una dirección:
get students browser

Podemos editar un alumno con una petición PUT:
put student postman

Podemos obtener un alumno específico con una petición GET:
get student postman
get student result

Podemos eliminar a un estudiante con una petición DELETE:
delete student postman

Finalmente podemos visualizar los estudiantes desde el navegador para verificar el resultado final:
final phpmyadmin


Conclusion

En esta segunda parte de la guia utilizamos Docker para construir una imagen de Node.js con nuestro programa y ejecutamos nuestro propio contenedor. Tras esto surgio la necesidad de conectar el contenedor a una base de datos, por lo que utilizamos Docker Compose para ejecutar en simultaneo 3 contenedores: el servidor Node.js, la base de datos MySql y el administrador de base de datos PhpMyAdmin.
En la siguiente guia migraremos nuestra aplicacion multicontenedor de Docker Compose a una arquitectura de Kubernetes.

Espero que te haya sido de utilidad esta guia y nos vemos en la siguiente!

Top comments (0)