Spring Boot con PostgreSQL y Docker Compose

En este post vas a aprender como crear una aplicacion Spring Boot con una base de datos PostgreSQL para que se ejecute dentro de un contenedor Docker.

Verás a continuación estos puntos para construir tu aplicación Spring Boot con una base de datos PostgreSQL en un contenedor Docker.

Spring Boot PostgreSql Docker Compose

Ya hemos estado trabajando en otros post con Spring Boot, Java y Docker. Te dejo aquí algunos links que pueden ayudarte con este tema.

Dependencias para Spring Boot con Postgresql

Para este tutorial vas a utilizar Gradle para administrar las dependencias y el build del proyecto. La estructura de tu proyecto quedará al finalizar de este modo:

Spring Boot Docker PostgreSQL

Necesitas definir las siguientes dependencias para utilizar Spring Boot con Postgresql:

1
2
3
'org.springframework.boot:spring-boot-starter-web'
'org.springframework.boot:spring-boot-starter-data-jpa'
'org.postgresql:postgresql'

El archivo build.gradle completo queda así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
plugins {
	id 'org.springframework.boot' version '2.2.1.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	runtimeOnly 'org.postgresql:postgresql'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

El main de Spring Boot para el proyecto

Debes definir el main de tu aplicación con la anotación @SpringBootApplication

1
2
3
4
5
6
7
8
@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

El resto de componentes para el proyecto: modelo, repositorio, controller y propiedades

Modelo

Vas a crear una entidad User que será un modelo muy simple para almacenar en la base de datos PostgreSQL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class UserModel {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

// set and get… 
}

Repositorio

Creas un repositorio para nuestro modelo User. Extenderá la clase JpaRepository de Spring.

1
2
3
@Repository
public interface UserRespository extends JpaRepository<UserModel, Long> {
}

Controller

Creas un controller con rest points básicos para este ejemplo. Vas a definir tres restpoint: - /user/all para devolver todos los user - /user/{id} para devolver un solo User por el ID - /user/save para guardar un User

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import com.experto.springbootpostgresqldocker.model.UserModel;
import com.experto.springbootpostgresqldocker.repository.UserRespository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

@RestController
public class UserController {

    private UserRespository userRespository;

    @Autowired
    public UserController(UserRespository userRespository) {
        this.userRespository = userRespository;
    }

    @GetMapping("/user/all")
    Iterable<UserModel> all() {
        return userRespository.findAll();
    }

    @GetMapping("/user/{id}")
    UserModel userById(@PathVariable Long id) {
        return userRespository.findById(id).orElseThrow(() -> new ResponseStatusException(
                HttpStatus.NOT_FOUND));
    }

    @PostMapping("/user/save")
    UserModel save(@RequestBody UserModel user) {
        return userRespository.save(user);
    }

}

Archivo application.properties

Defines en el archivo la configuración que tendrá la base de datos con la url de la conexión, el username y el password. Veremos más adelante que estos valores por default salen de la imagen PostgeSql que usaremos en el archivo de configuración del docker compose.

La propiedad spring.jpa.hibernate.ddl-auto tiene estas opciones create, create-drop, validate, update De la documentación de spring tenemos: - create: crea el schema de la base de datos destruyendo los datos.
- create-drop: borra el schema al finalizar la sesión. - validate: solo valida el schema sin realizar cambios en las tablas de base de datos. - update: actualiza el schema con los cambios que hagas en tus entidades.

Archivo _resources/application.properties _ .

1
2
3
4
spring.datasource.url=jdbc:postgresql://dbpostgresql:5432/mydb
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=create

Configuración de Docker para Spring Boot con PostgreSQL

El archivo Dockerfile

En el archivo de Dockerfile le daremos las siguientes instrucciones a Docker.

1
2
3
4
5
6
FROM openjdk:8-jdk-alpine
MAINTAINER experto.com
VOLUME /tmp
EXPOSE 8080
ADD build/libs/springbootpostgresqldocker-0.0.1-SNAPSHOT.jar springbootpostgresqldocker.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/springbootpostgresqldocker.jar"]

Spring Boot Docker PostgreSQL

FROM: usas aqui una (imagen de Docker)[https://hub.docker.com/_/openjdk] con un jdk8 y un server linux alpine. MAINTAINER: datos de contacto VOLUME: la carpeta donde se trabajara EXPOSE: el puerto que se expondrá **ADD : copia el jar file de nuestra aplicación springbootpostgresqldocker-0.0.1-SNAPSHOT.ja en el contenedor docker con el nombre springbootpostgresqldocker.jar
**ENTRYPOINT : ejecuta la sentencia al arrancar el contenedor docker

El archivo docker-compose.yml

Debes crear un archivo docker-compose.yml en el cual vas a establecer dos servicios.

El primer servicio que llamarás app hace referencia al servicio de SpringBoot que configuraste en el Dockerfile. Dentro de ese servicio la instrucción build indica que ese servicio viene del Dockerfile que previamente definiste.

El segundo servicio que llamarás dbpostgresql utiliza una imagen postgresql del hub de docker que docker descargará de allí. Dejamos el password, user, y nombre de la db que viene por defecto.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
version: '3.1'
services:
  app:
    container_name: app-springboot-postgresql
    image: app-springboot-postgresql
    build: ./
    ports:
      - "8080:8080"
    depends_on:
      - dbpostgresql
  dbpostgresql:
    image: postgres
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_USER=postgres
      - POSTGRES_DB=mydb

Spring Boot Docker PostgreSQL

Ejecutar SpringBoot con PostgreSQL en el contenedor Docker

Build de tu proyecto para crear el archivo jar

En este ejemplo estamos usando gradlew. Por lo que lo que debes hacer es un build de este modo:

1
./gradlew build

Spring Boot Docker PostgreSQL

Esto dejará el archivo jar de tu proyecto en la carpeta /build/libs de tu proyecto.

Spring Boot Docker PostgreSQL

Build de docker compose para crear la imagen y ejecutar la aplicación dentro de docker

Luego de haber hecho un build de tu proyecto y tener disponible el archivo jar, puedes lanzar el contenedor.

1
docker-compose up --build

Spring Boot Docker PostgreSQL

Probar tu aplicación Spring Boot + PostgreSQL + Docker

Recuerda que habíamos creado previamente un UserController con un post para guardar el User y un get para obtener los usuarios Ahora ejecutas este post. Observa que guardas un Usuario y el response te devuelve el mismo User con el id ya asignado.

Post /user/save

1
2
3
4
curl -s -X POST \
  http://localhost:8080/user/save \
  -H 'Content-Type: application/json' \
  -d '{"name":"Moana"}'

Spring Boot Docker PostgreSQL

Luego haces un get con el ID que del nuevo usuario que guardaste previamente.

Get /user/save

1
2
curl -s -X GET \
  http://localhost:8080/user/1 

Spring Boot Docker PostgreSQL

Conclusión:

En este post creaste una app simple con Spring Boot utilizando dos imágenes de Docker. La primera para el servicio de SpringBoot y la segunda para PostgreSQL. Ejecutaste el contenedor de Docker con las imágenes y luego guardaste un nuevo User en la base de datos PostgreSQL utilizando los rest point que definiste para el User.

El código :

Como siempre puedes ver este código en github y gitlab.
https://github.com/gustavopeiretti/springboot-postgresql-docker-example
https://gitlab.com/gustavopeiretti/springboot-postgresql-docker-example