:::: MENU ::::

Docker

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 ?