NashTech Blog

How to containerize postgresql and a spring webflux application in docker

Table of Contents

Modern applications require scalability, portability, and efficiency. Containerization with Docker allows us to package applications and their dependencies into isolated environments. In this blog, we’ll containerize a Spring WebFlux application (spring-flux-docker-demo) along with PostgreSQL using Docker and Docker Compose.

Additionally, we’ll explore Serverless Architecture, Reactive Programming, and why PostgreSQL is a great fit for Spring WebFlux.

Serverless Architecture

Serverless architecture is a cloud computing model where developers don’t manage servers. Instead, cloud provider handle infrastructure, scaling and execution dynamically. Serverless architecture allows developers to build and run application without managing the underlying infrastructure.

Key Characteristics:
  • Function As A Service (FAAS): Developers deploy discrete functions that execute in response to specific events, such as HTTP requests and database changes.
  • Automatic Scaling: The infrastructure scales function up or down based on demand, ensuring optimal performance with manual intervention.
  • Cost Efficiency: Billing is based on the actual execution time and resource consumed by functions, eliminating costs associated with idle servers.

Reactive Programming

Reactive programming is a paradigm focused on building asynchronous, non-blocking, and event-driven applications. It enables systems to react to data changes and user events in real-time, ensuring high responsiveness and scalability.

Core Principles:
  • Asynchronous Data Streams: Handling data as continuous streams allows applications to process events as they occur without blocking operations.
  • Non-Blocking Operations: Tasks can execute without waiting for others to complete, leading to improved performance and resource utilization.
  • Event-Driven Architecture: Systems respond to events or changes in state, promoting a more dynamic and responsive behaviour.

Spring WebFlux

Spring WebFlux is a module within the Spring Framework that supports the development of reactive and non-blocking web applications. It leverages reactive programming principles to handle concurrency with a small number of threads, making it suitable for applications requiring high scalability and performance.

Features:
  • Reactive Stream Support: Integrates with the Reactive Stream API to handle asynchronous data stream effectively.
  • Non-Blocking I/O: Utilizes non-blocking input/output operations to enhance application responsiveness and resource efficiency.
  • Declarative Programming Model: Offers a functional programming approach, simplifying the development of complex reactive efficiency.

Now you’ve been thinking, why are we learning about serverless architecture, reactive programming, and Spring WebFlux? Well, it all fits into the picture in the next paragraph.

Spring WebFlux and PostgreSQL (with R2DBC) integrate seamlessly to build efficient, reactive, and serverless applications. On one hand, WebFlux is designed for non-blocking, event-driven execution, ensuring that applications handle concurrent requests efficiently without being tied to traditional thread-based architectures. As a result, it is particularly well-suited for serverless environments, where performance and cost optimization depend on handling workloads dynamically. Furthermore, since serverless platforms scale resources automatically, WebFlux ensures smooth performance under varying loads, making applications highly responsive and scalable.

On the other hand, PostgreSQL with R2DBC (Reactive Relational Database Connectivity) extends these benefits to the database layer by replacing traditional blocking JDBC connections with fully asynchronous interactions. Consequently, rather than waiting for queries to complete and consuming unnecessary resources, R2DBC allows data to flow continuously, significantly reducing latency and improving throughput. More importantly, this integration ensures that the entire system remains fully reactive, preventing performance bottlenecks and maximizing efficiency. Therefore, by combining WebFlux and PostgreSQL, serverless applications can achieve higher scalability, lower operational costs, and enhanced real-time responsiveness, making them an ideal choice for modern cloud-native development.

What’s Next?

Now that we have cleared our basics of reactive programming, serverless architecture, Spring WebFlux, and PostgreSQL, let’s move on to the demonstration of an application that brings these concepts to life.

In the upcoming section, we will build a Spring WebFlux application that integrates with PostgreSQL using R2DBC and containerize it using Docker. This demo will showcase how a fully reactive, non-blocking stack efficiently handles concurrent requests while ensuring scalability and performance in a serverless environment. So, let’s dive into the implementation and see these principles in action! 

Let’s create a Spring WebFlux application that integrates with PostgreSQL using R2DBC and containerize it using Docker. This application will demonstrate how reactive programming works with serverless architecture principles.

1. Setting Up the Spring WebFlux Project

A. Go to Spring Initializr
B. Select Gradle Project and Java Version
C. Add the following dependencies:
-> Spring Reactive Web (for WebFlux)
-> Spring Boot DevTools (optional for development)
-> R2DBC PostgreSQL (for non-blocking database access)
-> Flyway (for database migrations)
D. Click Generate and extract the ZIP file

2. Configuring PostgreSQL & R2DBC

The application.yml file configures the PostgreSQL connection and enables Flyway migrations for database setup.

spring:
r2dbc:
url: r2dbc:postgresql://localhost:5432/reactive_db
username: postgres
password: postgres
flyway:
url: jdbc:postgresql://localhost:5432/reactive_db
user: postgres
password: postgres
sql:
init:
mode: always

  • r3dbc.url -> Configures PostgreSQL with Reactive Database Connectivity (R2DBC) instead of traditional JDBC.
  • flyway.url -> Defines database migration settings using Flyway, ensuring that tables are created automatically.
  • sql.init.mode: always -> Ensures that the database initializes whenever the app starts.

3. Implementing Reactive Data Handling

Creating the User Model

The User class represents the structure of our database entity.

@Data /* Lombok’s @Data annotation generates getters, setters, and constructors automatically. */
@Table("users") /* Maps this class to the users table. */
public class User {
    @Id /* Marks id as the primary key. */
    private Long id;
    private String name;
    private String email;
}
Creating the Reactive Repository
@Repository
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
}
  • ReactiveCrudRepository → Provides reactive CRUD operations for User.
  • Unlike traditional repositories, this one is fully asynchronous and supports Flux (multiple records) and Mono (single record).
Creating the Service Layer

The service layer contains business logic for handling users.

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }

    public Mono<User> getUserById(Long id) {
        return userRepository.findById(id);
    }

    public Mono<User> createUser(User user) {
        return userRepository.save(user);
    }

    public Mono<Void> deleteUser(Long id) {
        return userRepository.deleteById(id);
    }
}
  • Flux<User> –> Returns multiple users asynchronously.
  • Mono<User> -> Returns a single user asynchronously.
  • findAll(), findById(), save(), and deleteById() are provided by ReactiveCrudRepository.

4. Creating a Reactive API Controller

The controller exposes REST endpoints for handling users.

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping /* Retrieves all users (Flux). */
    public Flux<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/{id}") /* Retrieves a single user (Mono). */
    public Mono<User> getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping /* Create a new User. */
    public Mono<User> createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @DeleteMapping("/{id}") /* Delete a user. */
    public Mono<Void> deleteUser(@PathVariable Long id) {
        return userService.deleteUser(id);
    }
}

5. Dockerizing the Application

Dockerfile:
FROM openjdk:23
WORKDIR /app
COPY build/libs/demo-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Docker Compose File (docker-compose.yml)
version: "3.8"
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: reactive_db
    ports:
      - "5432:5432"

  app:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - db

6. Running the Application

  • Start the Spring Boot WebFlux application after PostgreSQL is ready.
  • Follow the below commands:
./gradlew builld /* use gradle wrapper in case 'gradlew: command not found' error message occurs. */ 
docker-compose up --build
./gradlew bootRun
  • Now, test the endpoints on http://localhost:8080

Sample:

curl -x POST http://localhost:8080/users -H “Content-Type: application/json” -d ‘ {“name”: “Mayank”, “email”: “mayank@nash.com”} ‘

Conclusion

In this journey, we explored how serverless architecture, reactive programming, and Spring WebFlux come together to build high-performance, scalable applications. We saw how traditional architectures struggle with blocking operations, making reactive programming a necessity for modern cloud-native applications.

By leveraging Spring WebFlux and PostgreSQL (with R2DBC), we created a non-blocking, event-driven API that efficiently handles concurrency while remaining lightweight. Running this in Docker ensures seamless deployment and scalability, making it a great fit for cloud environments.

Picture of Mayank Devrani

Mayank Devrani

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top