Una vez introducidos en el mundo de los contenedores de software y las principales diferencias entre trabajar con contenedores y máquinas virtuales, hablaremos en este artículo sobre qué es Docker y cómo funciona en detalle. Además, levantaremos un container a partir de una pequeña API de SpringBoot.
Qué vas as ver en esta entrada
Qué es Docker
Docker es una plataforma creada con el fin de desarrollar, implementar y ejecutar aplicaciones dentro de contenedores. Lo cual permite a los desarrolladores realizar el empaquetado de nuestras aplicaciones junto a sus correspondientes dependencias dentro de una unidades estandarizadas conocidas bajo el término de contenedores de software.
Aunque existen distintos tipos de implementaciones de contenedores, el más famoso motor para crear contenedores de software es Docker.
Un contenedor, por tanto, realmente nos permite encapsular, es decir, empaquetar un software dentro de dicho contenedor utilizando la arquitectura de microservicios.
Proceso de creación de un contenedor en Docker
Además, hay que matizar que dentro del contenedor se definen una serie de instrucciones (dockerfile) que permiten crear una imagen (docker image) con la que poder arrancar a dicho contenedor (docker container).
Vamos a explicar los estos elementos con más detalle:
- Dockerfile: es el documento de texto sobre el que podemos agrupar una serie de comandos con el fin que se ejecuten todos a la vez evitando así tener que ejecutarlos uno a uno manualmente con el fin de que el proceso de crear una imagen de Docker sea mucho más rápido y más eficiente.
- Docker image: una imagen de Docker, contiene las librerías, junto al código de la aplicación que contiene todo lo necesario para ejecutar nuestra aplicación.
- Container: es una imagen de Docker cuando empieza a funcionar, es decir, cuando cobra vida.
Instalando Docker en Windows
Vamos al enlace: https://www.docker.com/get-started
Y una vez tengamos el instalador descargado realizamos la instalación con el tradicional siguiente, siguiente…
Aunque me gustaría destacar que vamos a marcar las siguientes opciones:
Una vez iniciado el proceso de instalación, solamente tenemos que esperar a que el instalador nos muestre un mensaje de que la instalación ha finalizado.
Instalando W2L
Si pulsamos sobre cerrar, el ordenador se reiniciará ya que Docker virtualiza a nivel de sistema operativo y requiere el reinicio del equipo.
Tras la instalación, podremos ver un icono como el siguiente en nuestro escritorio:
Si lo abrimos, vemos que nos aparece una ventana en la que se indica que no tenemos instalado el WSL 2.
WSL 2 = Windows Subsystem for Linux
WSL2 nos permite ejecutar el kernel nativo de Linux al completo ejecutándose desde un equipo Windows.
Finalmente, y una vez tenemos WSL 2 instalando, si iniciamos nuevamente Docker y vemos la siguiente ventana:
Y si ahora finalmente abrimos el CMD y ejecutamos docker –version, podemos ver que también tenemos configurada la variable de entorno de Windows. Vamos a verlo:
Y si queremos la versión más detallada podemos hacer un docker version la cual nos mostrará las diferentes versiones con las que estamos trabajando tanto en el cliente como en el servidor:
Creando nuestro primer contenedor
Si hacemos docker help podemos ver todos los comandos que tenemos disponibles en Docker. Vamos a verlos:
Docker info: muestra toda la información del sistema sobre el que se ejecuta docker. La versión del kernel, el número de contenedores y las imágenes.
Creando una API con Spring Boot
Una vez tenemos instalado Docker, vamos a crear una API sobre la que más tarde generamos un JAR (un empaquetado) de dicha API.
Para crear la API vamos a Eclipse:
E instalamos Spring Boot:
Una vez instalado, vamos a crear una API muy sencillita:
Para ello, marcamos la pestaña de Spring Web:
Finalmente, vamos a crear un controlador llamado IndexController:
Y dentro del IndexController añadimos lo siguiente:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class IndexController { @GetMapping("/") @ResponseBody public String welcomeWithParamName() { return "Bienvenido@s!"; } }
Si vamos a la consola podemos ver el puerto sobre el que arranca la API, por defecto este será el 8080. Y si vamo al navegador y hacemos localhost:8080, vemos que nuestra API funciona correctamente:
Y que nos está devolviendo lo que hemos escrito en el controlador, para la ruta raíz (/):
En el caso que escribamos otra ruta, nuestra API de Spring Boot nos dará respuesta un Whitelabel Error Page:
Finalmente, una vez ya tenemos desarrollada la API, vamos a finalizar su ejecución:
Si volvemos a hacer una petición a nuestra API, podemos ver que como ya hemos parado la conexión ya no nos retorna nada:
Creando el JAR de la API
Para crear el JAR, es decir, meter nuestra aplicación en lo que viene siendo un JAR en inglés, un tarro. Es decir, la vamos a empaquetar.
Y en la consola nos aparecerá la ruta sobre la que se ha realizado el JAR:
Si ejecutamos el JAR de la API (haciendo doble click), podemos volver a ver que tenemos operativa nuestra API.
Y nuevamente, vamos a detener la aplicación ahora, cómo se está ejecutando desde un JAR, y no desde Eclipse como anteriormente hemos realizado,no podemos pulsar el STOP para detenerla.
Por tanto, para finalizar su ejecución tenemos que abrir el archivo jps.exe que se encuentra ubicado dentro de directorio bin del jdk:
Con ello, podemos ver todos los JAR que tenemos en ejecución en nuestro equipo, entre los que se encuentra nuestra API.
Si queremos finalizar la ejecución de dicho JAR desde windows, podemos utilizar taskkill -f /PID. Vamos a verlo:
Tras volver a hacer un jps.exe podemos verificar que ya no tenemos el JAR de nuestra API en ejecución. Por tanto, lo hemos detenido correctamente.
Empezando con Docker
Como ya hemos visto anteriormente, el proceso de creación de un container en Docker consta de 3 pasos:
Si hacemos un docker images, podemos ver que no tenemos ninguna imagen. Lo podemos comprobar desde el CMD o bien desde la interfaz gráfica de Docker.
Además, también podemos listar los contenedores y comprobar que actualmente no tenemos ninguno:
Creando el Docker File
Un dockerfile como ya hemos dicho es la receta que creará la imagen que posteriormente será ejecutada en el contenedor.
Para ello, vamos a docker Hub y descargamos la imagen que queramos en mi caso usaré la imagen de JDK 13:
Vamos a mover el fichero JAR que hemos generado al directorio raíz C:/:
El dockerfile es un archivo sin extensión.
En mi caso lo he situado en el escritorio y contendrá lo siguiente:
FROM openjdk:13-jdk-alpine ARG JAR_FILE=*.jar COPY ${JAR_FILE} SpringBoot-API-0.0.1-SNAPSHOT.jar ENTRYPOINT ["java","-jar","/SpringBoot-API-0.0.1-SNAPSHOT.jar"]
Creando la imagen
Una vez creado, el dockerfile, vamos a abrir una terminal en mi caso, como tengo el fichero dockerfile abierto, vamos a ir a dicha ruta desde la terminal:
Y vamos a crear la imagen para posteriormente ejecutarla en el contenedor. Vamos a ello:
Si nos metemos en la interfaz gráfica de docker podemos ver que también podemos ver la imagen que hemos creado:
Creando el contenedor
Con el -p 8080:8080 estamos asociando el puerto 8080 de la máquina con el puerto 8080 del contenedor. Podríamos asociar puertos del contenedor diferentes a los de la máquina. Por ejemplo el puerto 3000 al puerto 8080 del contenedor de la siguiente manera: -p 3000:8080
Y aquí podemos ver tanto mediante la terminal y la interfaz gráfica que ya tenemos el contenedor montado.
Testeando nuestra API
Si paramos el contenedor, con docker stop:
Podemos ver que ahora la aplicación ya no nos responde a las peticiones:
Conclusión
Bueno aunque ha sido largo, ¡misión conseguida! Hemos levantado nuestro primer contenedor con una aplicación de Spring Boot. Y aunque quedan muchas cosas por ver, espero que os haya sido de ayuda. ¿Trabajas habitualmente con Docker y aprovechas los beneficios que tiene? ¡Cuéntanos en nuestras redes sociales!
Si quieres aprender más sobre contenedores visita nuestro canal de YouTube! ¡Suscríbete!