Esecuzione di Spring Boot con PostgreSQL in Docker Compose

1. Introduzione

In questo tutorial, vogliamo eseguire un'applicazione Spring Boot con il popolare database open source PostgreSQL. In un articolo precedente, abbiamo esaminato Docker Compose per gestire più contenitori contemporaneamente . Quindi, invece di installare PostgreSQL come applicazione separata, useremo Docker Compose per eseguire Spring Boot e PostgreSQL .

2. Creazione del progetto Spring Boot

Andiamo a Spring Initializer e creiamo il nostro progetto Spring Boot . Aggiungeremo i moduli PostgreSQL Driver e Spring Data JPA . Dopo aver scaricato il file ZIP risultante e averlo estratto in una cartella, possiamo eseguire la nostra nuova applicazione:

./mvnw spring-boot:run

L'applicazione non riesce perché non riesce a connettersi al database:

*************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class 

3. Dockerfile

Prima di poter avviare PostgreSQL con Docker Compose, dobbiamo trasformare la nostra applicazione Spring Boot in un'immagine Docker . Il primo passo è creare il pacchetto dell'applicazione come file JAR:

./mvnw clean package -DskipTests

Qui, prima puliamo le nostre build precedenti prima di creare il pacchetto dell'applicazione. Inoltre, saltiamo i test perché falliscono senza PostgreSQL.

Ora abbiamo un file JAR dell'applicazione nella directory di destinazione . Quel file ha il nome del progetto e il numero di versione nel suo nome e termina con -SNAPSHOT.jar . Quindi il suo nome potrebbe essere docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar .

Creiamo la nuova directory src / main / docker . Successivamente, copiamo il file JAR dell'applicazione lì:

cp target/docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar src/main/docker

Infine, creiamo questo Dockerfile nella stessa directory:

FROM adoptopenjdk:11-jre-hotspot ARG JAR_FILE=*.jar COPY ${JAR_FILE} application.jar ENTRYPOINT ["java", "-jar", "application.jar"]

Questo file descrive come Docker dovrebbe eseguire la nostra applicazione Spring Boot . Utilizza Java 11 da AdoptOpenJDK e copia il file JAR dell'applicazione in application.jar . Quindi esegue quel file JAR per avviare la nostra applicazione Spring Boot.

4. Docker Compose File

Ora scriviamo il nostro file Docker Compose, docker-compose.yml , e salviamolo in src / main / docker :

version: '2' services: app: image: 'docker-spring-boot-postgres:latest' build: context: . container_name: app depends_on: - db environment: - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/compose-postgres - SPRING_DATASOURCE_USERNAME=compose-postgres - SPRING_DATASOURCE_PASSWORD=compose-postgres - SPRING_JPA_HIBERNATE_DDL_AUTO=update db: image: 'postgres:13.1-alpine' container_name: db environment: - POSTGRES_USER=compose-postgres - POSTGRES_PASSWORD=compose-postgres

Il nome della nostra applicazione è app. È il primo di due servizi (linee 4-15):

  • L'immagine Docker di Spring Boot ha il nome docker-spring-boot-postgres: latest (riga 5). Docker crea quell'immagine dal Dockerfile nella directory corrente (righe 6-7)
  • Il nome del contenitore è app (riga 8). Dipende dal servizio db (riga 10). Ecco perché inizia dopo il contenitore db
  • La nostra applicazione utilizza il contenitore db PostgreSQL come sorgente dati (riga 12). Il nome del database, il nome utente e la password sono tutti compose-postgres (righe 12-14)
  • Hibernate creerà o aggiornerà automaticamente tutte le tabelle di database necessarie (riga 15)

Il database PostgreSQL ha il nome db ed è il secondo servizio (righe 17-22):

  • Usiamo PostgreSQL 13.1 (riga 18)
  • Il nome del contenitore è db (riga 19)
  • Il nome utente e la password sono entrambi compose-postgres (righe 21-22)

5. Esecuzione con Docker Compose

Eseguiamo la nostra applicazione Spring Boot e PostgreSQL con Docker Compose :

docker-compose up

In primo luogo, questo creerà l'immagine Docker per la nostra applicazione Spring Boot. Successivamente, avvierà un contenitore PostgreSQL. Infine, lancerà la nostra applicazione Docker image. Questa volta, la nostra applicazione funziona bene:

Starting DemoApplication v0.0.1-SNAPSHOT using Java 11.0.9 on f94e79a2c9fc with PID 1 (/application.jar started by root in /) [...] Finished Spring Data repository scanning in 28 ms. Found 0 JPA repository interfaces. [...] Started DemoApplication in 4.751 seconds (JVM running for 6.512)

Come possiamo vedere, Spring Data non ha trovato l'interfaccia del repository. È corretto: non ne abbiamo ancora creato uno!

Se vogliamo fermare tutti i contenitori, dobbiamo prima premere [Ctrl-C]. Quindi possiamo fermare Docker Compose:

docker-compose down

6. Creazione di un'entità cliente e di un repository

Per utilizzare il database PostgreSQL nella nostra applicazione, creeremo una semplice entità cliente :

@Entity @Table(name = "customer") public class Customer { @Id @GeneratedValue private long id; @Column(name = "first_name", nullable = false) private String firstName; @Column(name = "last_name", nullable = false) private String lastName;

Il cliente ha un attributo id generato e due attributi obbligatori: firstName e lastName .

Ora possiamo scrivere l'interfaccia del repository per questa entità :

public interface CustomerRepository extends JpaRepository { }

Estendendo semplicemente JpaRepository , ereditiamo i metodi per creare e interrogare la nostra entità Customer .

Infine, useremo questi metodi nella nostra applicazione:

@SpringBootApplication public class DemoApplication { @Autowired private CustomerRepository repository; @EventListener(ApplicationReadyEvent.class) public void runAfterStartup() { List allCustomers = this.repository.findAll(); logger.info("Number of customers: " + allCustomers.size()); Customer newCustomer = new Customer(); newCustomer.setFirstName("John"); newCustomer.setLastName("Doe"); logger.info("Saving new customer..."); this.repository.save(newCustomer); allCustomers = this.repository.findAll(); logger.info("Number of customers: " + allCustomers.size()); } }
  • Accediamo al nostro repository dei clienti tramite l'iniezione di dipendenze
  • Chiediamo il numero di clienti esistenti con il repository: questo sarà zero
  • Quindi creiamo e salviamo un cliente
  • When we then query the existing customers again, we expect to find the one we just created

7. Running with Docker Compose Again

To run the updated Spring Boot application, we need to rebuild it first. Therefore, we execute these commands once more in the project root directory:

./mvnw clean package -DskipTests cp target/docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar src/main/docker

How do we rebuild our Docker image with this updated application JAR file? The best way is to remove the existing Docker image whose name we specified in the docker-compose.yml. This forces Docker to build the image again the next time we start our Docker Compose file:

cd src/main/docker docker-compose down docker rmi docker-spring-boot-postgres:latest docker-compose up

So after stopping our containers, we delete the application Docker image. We then start our Docker Compose file again, which rebuilds the application image.

Here's the application output:

Finished Spring Data repository scanning in 180 ms. Found 1 JPA repository interfaces. [...] Number of customers: 0 Saving new customer... Number of customers: 1

Spring Boot trova il nostro repository cliente vuoto. Pertanto, iniziamo con nessun cliente ma poi ne creiamo uno con successo.

8. Conclusione

In questo breve tutorial, abbiamo iniziato creando un'applicazione Spring Boot per PostgreSQL. Successivamente, abbiamo scritto un file Docker Compose per eseguire il nostro contenitore dell'applicazione con un contenitore PostgreSQL.

Infine, abbiamo creato un'entità cliente e un repository, che ci ha permesso di salvare un cliente in PostgreSQL.

Come al solito, il codice sorgente di questo tutorial può essere trovato su GitHub.