Introducción
Docker es una herramienta que permite crear imágenes de sistemas operativos (instanciadas en contenedores) y las cuales funcionan de una manera similar a las máquinas virtuales convencionales, pero mucho más ligeras.
Instalación de Docker
Hay que seguir estos pasos:
1. Ir a https://docs.docker.com/toolbox/overview/ y bajarnos “Toolbox for Windows”.
2. Ejecutar el instalador y aceptar las opciones por defecto.
3. Lanzar “Docker Quickstart Terminal” (tardará unos minutos en arrancar la primera vez) e introducir “docker –version” para comprobar que está instalado correctamente.
En este punto ya tenemos Docker listo para generar imágenes.
Creación de aplicación Java
Programaremos una aplicación Java en Eclipse para usarla en un imagen de Docker.
1. Vamos a Eclipse y creamos un nuevo proyecto de tipo Maven con el siguiente pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.luisgomezcaballero</groupId> <artifactId>dockerdemo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>dockerdemo</name> <description>Demo project for Docker</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2. La clase principal va a ser la habitual en proyectos de Spring Boot:
DockerdemoApplication.java
package com.luisgomezcaballero.dockerdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DockerdemoApplication { public static void main(String[] args) { SpringApplication.run(DockerdemoApplication.class, args); } }
3. Necesitaremos una entidad simple:
MyEntity.java
package com.luisgomezcaballero.dockerdemo.model; public class MyEntity { private long myLong; private String myString; public MyEntity() { super(); } public MyEntity(long myLong, String myString) { super(); this.myLong = myLong; this.myString = myString; } public long getMyLong() { return myLong; } public void setMyLong(long myLong) { this.myLong = myLong; } public String getMyString() { return myString; } public void setMyString(String myString) { this.myString = myString; } @Override public String toString() { return "MyEntity [myLong=" + myLong + ", myString=" + myString + "]"; } }
4. Creamos un servicio simple (por simplicidad, contendrá un listado simple de entidades):
MyService.java
package com.luisgomezcaballero.dockerdemo.service; import java.util.List; import com.luisgomezcaballero.dockerdemo.model.MyEntity; public interface MyService { public List<MyEntity> readAll(); public MyEntity readById(long id); public MyEntity create(MyEntity myEntity); public MyEntity update(long id, MyEntity myEntity); public void deleteById(long id); public void deleteAll(); }
MyServiceImpl.java
package com.luisgomezcaballero.dockerdemo.service; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.springframework.stereotype.Service; import com.luisgomezcaballero.dockerdemo.model.MyEntity; @Service public class MyServiceImpl implements MyService { private List<MyEntity> myEntityList; { myEntityList = new ArrayList<MyEntity>(); myEntityList.add(new MyEntity(1, "Entity1")); myEntityList.add(new MyEntity(2, "Entity2")); myEntityList.add(new MyEntity(3, "Entity3")); } @Override public List<MyEntity> readAll() { return myEntityList; } @Override public MyEntity readById(long id) { for (MyEntity myEntity : myEntityList) { if (myEntity.getMyLong() == id) { return myEntity; } } return null; } @Override public MyEntity create(MyEntity myEntity) { myEntityList.add(myEntity); return myEntity; } @Override public MyEntity update(long id, MyEntity myEntity) { for (MyEntity myEntityToModify : myEntityList) { if (myEntityToModify.getMyLong() == id) { int index = myEntityList.indexOf(myEntityToModify); myEntityList.set(index, myEntity); break; } } return myEntity; } @Override public void deleteById(long id) { for (Iterator<MyEntity> iterator = myEntityList.iterator(); iterator.hasNext();) { MyEntity myEntity = iterator.next(); if (myEntity.getMyLong() == id) { iterator.remove(); } } } @Override public void deleteAll() { myEntityList.clear(); } }
5. Y ahora un Controlador que use dicho servicio:
MainController.java
package com.luisgomezcaballero.dockerdemo.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.luisgomezcaballero.dockerdemo.model.MyEntity; import com.luisgomezcaballero.dockerdemo.service.MyService; @RestController @RequestMapping("/dockerdemo") public class MainController { @Autowired MyService myService; @RequestMapping(value = "/myentity/", method = RequestMethod.GET) public ResponseEntity<List<MyEntity>> readAllEntities() { return new ResponseEntity<List<MyEntity>>(myService.readAll(), HttpStatus.OK); } @RequestMapping(value = "/myentity/{id}", method = RequestMethod.GET) public ResponseEntity<MyEntity> readEntityById(@PathVariable("id") long id) { MyEntity myEntityResult = myService.readById(id); return new ResponseEntity<MyEntity>(myEntityResult, HttpStatus.OK); } @RequestMapping(value = "/myentity/", method = RequestMethod.POST) public ResponseEntity<MyEntity> createEntity(@RequestBody MyEntity myEntity) { myService.create(myEntity); return new ResponseEntity<MyEntity>(myEntity, HttpStatus.CREATED); } @RequestMapping(value = "/myentity/{id}", method = RequestMethod.PUT) public ResponseEntity<MyEntity> updateEntity(@PathVariable("id") long id, @RequestBody MyEntity myEntity) { myService.update(id, myEntity); return new ResponseEntity<MyEntity>(myEntity, HttpStatus.OK); } @RequestMapping(value = "/myentity/{id}", method = RequestMethod.DELETE) public ResponseEntity<MyEntity> deleteEntityById(@PathVariable("id") long id) { myService.deleteById(id); return new ResponseEntity<MyEntity>(HttpStatus.NO_CONTENT); } @RequestMapping(value = "/myentity/", method = RequestMethod.DELETE) public ResponseEntity<MyEntity> deleteAllEntities() { myService.deleteAll(); return new ResponseEntity<MyEntity>(HttpStatus.NO_CONTENT); } }
Compilación de la aplicación y generación del paquete WAR
Una vez que tenemos todo el código podemos usar Maven para compilarlo y generar un empaquetado de toda la aplicación con extensión .war.
Esto se consigue haciendo click con el botón derecho del ratón sobre el nombre del proyecto y seleccionando “Maven install”. Esta operación compilará el código, generará un fichero war en la carpeta target y lo copiará a nuestro repositorio local Maven para un uso futuro, aunque con que genere el war ya no es suficiente.
Navegando a la carpeta target veremos cómo se ha creado el fichero “dockerdemo-0.0.1-SNAPSHOT.jar”.
Dockerfile
El Dockerfile es el fichero con el que Docker creará la imagen conteniendo nuestra aplicación.
Creamos en la carpeta raíz del proyecto el siguiente fichero:
Dockerfile
FROM fabric8/java-alpine-openjdk8-jdk COPY target/dockerdemo-0.0.1-SNAPSHOT.jar . EXPOSE 8080 CMD ["java","-jar","dockerdemo-0.0.1-SNAPSHOT.jar"]
Generación de la imagen Docker
Lanzamos “Docker Quickstart Terminal” y navegamos hasta la carpeta raíz del proyecto. Podemos usar “pwd” para saber en que directorio estamos y “cd” para navegar entre carpetas.
Ejecutamos “docker build -t dockerdemo1 .” para generar la imagen. Tardará un poco ya que se bajará una versión pequeña de Linux con Java llamada Alpine.
Y con esto ya tendríamos en nuestro Docker la imagen (que no el contenedor).
Para ver las imágenes que tenemos, usamos el comando “docker images”.
Creación de un contenedor
Para instanciar la imagen en un contenedor, usamos el comando “docker run -d -p 8080:8080 dockerdemo1”.
Probar la aplicación dockerizada
Ahora la aplicación está corriendo dentro de un contenedor, y podemos probarla usando, por ejemplo, Postman.
Usamos “docker-machine ip” para saber en qué IP tenemos docker y después podremos lanzar peticiones contra esta máquina usando los paths que definimos en el controlador de la aplicación.
Abrimos Postman y usamos la siguiente URL para hacer una prueba:
192.168.99.100:8080/dockerdemo/myentity/
El resultado debería ser el siguiente:
[ { "myLong": 1, "myString": "Entity1" }, { "myLong": 2, "myString": "Entity2" }, { "myLong": 3, "myString": "Entity3" } ]
Repositorio
Esta aplicación Java puede encontrarse en el siguiente repositorio: https://github.com/luisgomezcaballero/dockerdemo.
So, what do you think ?