Перейти к основному содержимому

Запуск Spring Boot с PostgreSQL в Docker Compose

· 6 мин. чтения

1. Введение

В этом руководстве мы хотим запустить приложение Spring Boot с популярной базой данных с открытым исходным кодом PostgreSQL. В предыдущей статье мы рассматривали Docker Compose для одновременной обработки нескольких контейнеров . Поэтому вместо того, чтобы устанавливать PostgreSQL как отдельное приложение, мы будем использовать Docker Compose для запуска Spring Boot и PostgreSQL .

2. Создание проекта Spring Boot

Перейдем к Spring Initializer и создадим наш проект Spring Boot . Мы добавим модули PostgreSQL Driver и Spring Data JPA . После того, как мы загрузим полученный ZIP-файл и распакуем его в папку, мы можем запустить наше новое приложение:

./mvnw spring-boot:run

Приложение не работает, потому что не может подключиться к базе данных:

***************************
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. Докерфайл

Прежде чем мы сможем запустить PostgreSQL с Docker Compose, нам нужно превратить наше приложение Spring Boot в образ Docker . Первый шаг — упаковать приложение в виде файла JAR:

./mvnw clean package -DskipTests

Здесь мы сначала очищаем наши предыдущие сборки перед упаковкой приложения. Кроме того, мы пропускаем тесты, потому что они не работают без PostgreSQL.

Теперь у нас есть JAR-файл приложения в целевом каталоге. Этот файл имеет имя проекта и номер версии в своем имени и заканчивается на -SNAPSHOT.jar . Таким образом, его имя может быть docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar .

Давайте создадим новый каталог src/main/docker . После этого копируем туда JAR-файл приложения:

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

Наконец, мы создаем этот Dockerfile в том же каталоге:

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

Этот файл описывает, как Docker должен запускать наше приложение Spring Boot . Он использует Java 11 от AdoptOpenJDK и копирует JAR-файл приложения в application.jar . Затем он запускает этот JAR-файл, чтобы запустить наше приложение Spring Boot.

4. Файл компоновки Docker

Теперь давайте напишем наш файл Docker Compose, docker-compose.yml , и сохраним его в 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

Наше приложение называется app. Это первая из двух служб (строки 4-15):

  • Образ Spring Boot Docker имеет имя docker-spring-boot-postgres:latest (строка 5). Docker создает этот образ из файла Dockerfile в текущем каталоге (строки 6–7) .
  • Имя контейнера — app (строка 8). Это зависит от службы БД (строка 10). Вот почему он начинается после контейнера db
  • Наше приложение использует контейнер db PostgreSQL в качестве источника данных (строка 12). Имя базы данных, имя пользователя и пароль — все compose-postgres (строки 12-14) .
  • Hibernate автоматически создаст или обновит все необходимые таблицы базы данных (строка 15).

База данных PostgreSQL имеет имя db и является вторым сервисом (строки 17-22):

  • Мы используем PostgreSQL 13.1 (строка 18)
  • Имя контейнера — db (строка 19) .
  • Имя пользователя и пароль — compose-postgres (строки 21-22) .

5. Работа с Docker Compose

Давайте запустим наше приложение Spring Boot и PostgreSQL с помощью Docker Compose :

docker-compose up

Во-первых, это создаст образ Docker для нашего приложения Spring Boot. Затем он запустит контейнер PostgreSQL. Наконец, он запустит образ Docker нашего приложения. На этот раз наше приложение работает нормально:

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)

Как мы видим, Spring Data не нашел интерфейса репозитория. Это верно – мы еще не создали его!

Если мы хотим остановить все контейнеры, нам нужно сначала нажать [Ctrl-C]. Затем мы можем остановить Docker Compose:

docker-compose down

6. Создание объекта клиента и репозитория

Чтобы использовать базу данных PostgreSQL в нашем приложении, мы создадим простую сущность клиента :

@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;

У клиента есть сгенерированный атрибут id и два обязательных атрибута: firstName и lastName .

Теперь мы можем написать интерфейс репозитория для этой сущности :

public interface CustomerRepository extends JpaRepository<Customer, Long> { }

Просто расширяя JpaRepository , мы наследуем методы для создания и запроса нашей сущности Customer .

Наконец, мы будем использовать эти методы в нашем приложении:

@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());
}
}
  • Мы получаем доступ к нашему репозиторию клиентов через внедрение зависимостей
  • Запрашиваем количество существующих клиентов с репозиторием — это будет ноль
  • Затем мы создаем и сохраняем клиента
  • Когда мы снова запрашиваем существующих клиентов, мы ожидаем найти только что созданного.

7. Запуск с Docker Compose снова

Чтобы запустить обновленное приложение Spring Boot, нам нужно сначала его пересобрать. Поэтому мы еще раз выполняем эти команды в корневом каталоге проекта:

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

Как нам восстановить наш образ Docker с помощью этого обновленного JAR-файла приложения? Лучший способ — удалить существующий образ Docker, имя которого мы указали в файле docker-compose.yml . Это заставляет Docker снова собрать образ при следующем запуске нашего файла Docker Compose:

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

Итак, после остановки наших контейнеров мы удаляем Docker-образ приложения. Затем мы снова запускаем наш файл Docker Compose, который перестраивает образ приложения.

Вот вывод приложения:

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 находит наш пустой репозиторий клиентов. Поэтому мы начинаем без клиента, но затем успешно создаем его.

8. Заключение

В этом кратком руководстве мы начали с создания приложения Spring Boot для PostgreSQL. Затем мы написали файл Docker Compose для запуска контейнера нашего приложения с контейнером PostgreSQL.

Наконец, мы создали объект клиента и репозиторий, что позволило нам сохранить клиента в PostgreSQL.

Как обычно, исходный код этого руководства можно найти на GitHub .