OpenShift Persistent Volume Claims (PVC) for Java Applications

Learn how Java and Spring Boot applications use Persistent Volume Claims (PVC) in OpenShift for file uploads, reports, logs, and persistent storage. Understand PVC architecture, implementation, and enterprise best practices.


Introduction

Enterprise Java applications frequently need to store data that must survive application restarts.

Examples include:

  • User uploaded documents
  • PDF reports
  • Images
  • Invoice files
  • Log archives
  • Batch processing files
  • CSV imports
  • Exported Excel reports

If these files are stored inside a container, they disappear whenever the Pod restarts.

This is why Java applications running on OpenShift should use Persistent Volume Claims (PVCs).

A PVC allows your Spring Boot application to read and write files to persistent storage that remains available even after deployments, scaling events, or Pod failures.


Learning Objectives

By the end of this article, you will understand:

  • Why Java applications need PVCs
  • PVC architecture
  • File upload implementation
  • Spring Boot integration
  • Mounting storage
  • Enterprise storage patterns
  • Shared storage
  • Backup strategies
  • Best practices

Problem Without PVC

Suppose a customer uploads an important document.

flowchart LR
    User[Customer]
    --> Pod[Spring Boot Pod]

    Pod --> LocalStorage[Container Storage]

    LocalStorage --> Upload[Uploaded File]

    Pod -. Restart .-> Lost[❌ File Lost]

After the Pod restarts, the uploaded file is permanently lost.


Solution Using PVC

flowchart LR
    User[Customer]

    --> SpringBoot[Spring Boot Pod]

    --> PVC[Persistent Volume Claim]

    --> PV[Persistent Volume]

    --> Storage[(Cloud Storage)]

Files remain available regardless of Pod lifecycle.


Real-World Java Use Cases

Spring Boot applications commonly use PVCs for:

Application Persistent Data
Banking Customer Documents
Insurance Claim Attachments
Healthcare Medical Images
E-Commerce Product Images
HRMS Employee Documents
CRM PDF Reports
Batch Processing CSV Files
Analytics Generated Reports

PVC Architecture

flowchart TD

SpringBoot[Spring Boot Application]

PVC[Persistent Volume Claim]

PV[Persistent Volume]

Storage[(AWS EBS / Azure Disk)]

SpringBoot --> PVC

PVC --> PV

PV --> Storage

File Upload Workflow

sequenceDiagram

participant Customer

participant SpringBoot

participant PVC

participant Storage

Customer->>SpringBoot: Upload File

SpringBoot->>PVC: Save File

PVC->>Storage: Persist File

Storage-->>Customer: Upload Successful

Create PVC

apiVersion: v1
kind: PersistentVolumeClaim

metadata:
  name: upload-pvc

spec:

  accessModes:
  - ReadWriteOnce

  resources:

    requests:

      storage: 10Gi

Deploy:

oc apply -f pvc.yaml

Verify PVC

oc get pvc

Example:

NAME         STATUS

upload-pvc   Bound

Mount PVC

Deployment YAML

spec:

  containers:

  - name: payment-api

    volumeMounts:

    - name: upload-storage

      mountPath: /app/uploads

  volumes:

  - name: upload-storage

    persistentVolumeClaim:

      claimName: upload-pvc

Storage Architecture

flowchart LR

PVC

--> Volume

Volume

--> SpringBoot

SpringBoot

--> UploadFolder["/app/uploads"]

Spring Boot File Upload

@RestController
@RequestMapping("/files")
public class FileUploadController {

    @PostMapping("/upload")
    public String upload(
            @RequestParam MultipartFile file)
            throws Exception {

        Path path = Paths.get(
                "/app/uploads/" +
                file.getOriginalFilename());

        Files.copy(
                file.getInputStream(),
                path,
                StandardCopyOption.REPLACE_EXISTING);

        return "Upload Successful";
    }

}

Files are now stored on persistent storage.


Download File

@GetMapping("/{name}")
public ResponseEntity<Resource> download(
        @PathVariable String name)
        throws Exception {

    Path path = Paths.get(
            "/app/uploads/" + name);

    Resource resource =
            new UrlResource(path.toUri());

    return ResponseEntity.ok(resource);
}

Upload Flow

flowchart LR

Customer

--> RESTAPI

RESTAPI

--> SpringBoot

SpringBoot

--> PVC

PVC

--> PersistentStorage

Report Generation

Many enterprise applications generate reports.

flowchart LR

BatchJob

--> PDFReport

PDFReport

--> PVC

PVC

--> Download

Reports remain available even after application restart.


Spring Batch Example

flowchart LR
    INPUT["CSV Input"]
    JOB["Spring Batch Job"]
    WRITER["Item Writer"]
    FILE["Generated Output File"]
    STORAGE["PersistentVolumeClaim (PVC)"]

    INPUT --> JOB
    JOB --> WRITER
    WRITER --> FILE
    FILE --> STORAGE

Banking Example

Customer uploads KYC documents.

flowchart TD
    CUSTOMER["Customer"]
    API["Upload API"]
    APP["Spring Boot"]
    PVC["PersistentVolumeClaim"]
    EBS["AWS EBS"]

    CUSTOMER --> API
    API --> APP
    APP --> PVC
    PVC --> EBS

Documents remain safe after deployment.


Insurance Example

Claim documents.

flowchart LR
    CUSTOMER["Customer"]
    CLAIM["Claim Service"]
    PVC["PersistentVolumeClaim"]
    DISK["Azure Disk"]

    CUSTOMER --> CLAIM
    CLAIM --> PVC
    PVC --> DISK

Healthcare Example

Medical images.

flowchart TD
    PORTAL["Doctor Portal"]
    APP["Spring Boot Application"]
    PVC["PersistentVolumeClaim"]
    STORAGE["Cloud Storage"]

    PORTAL --> APP
    APP --> PVC
    PVC --> STORAGE

Shared Storage

Some applications require multiple Pods to access the same storage.

flowchart LR

Pod1

--> SharedPVC

Pod2

--> SharedPVC

Pod3

--> SharedPVC

SharedPVC

--> Storage

Requires ReadWriteMany (RWX) support.


Access Modes

Mode Description
ReadWriteOnce One Node
ReadOnlyMany Read Only
ReadWriteMany Shared Read/Write

Most Java applications use:

  • ReadWriteOnce

Shared document systems may require:

  • ReadWriteMany

Verify Mount

Enter Pod.

oc rsh payment-api-xxxxx

Check directory.

ls /app/uploads

Pod Restart Test

flowchart LR
    POD1["Pod 1"]
    PVC["PersistentVolumeClaim"]
    RESTART["Pod Restart"]
    POD2["New Pod"]

    POD1 --> PVC
    RESTART --> POD2
    POD2 --> PVC

Files remain available.


Scale Application

flowchart LR

SpringBoot

--> Pod1

SpringBoot

--> Pod2

SpringBoot

--> Pod3

Pod1 --> PVC

Pod2 --> PVC

Pod3 --> PVC

All Pods share persistent storage when supported.


Enterprise Architecture

flowchart TD
    USERS["Users"]
    ROUTE["Route"]
    SERVICE["Service"]
    PODS["Spring Boot Pods"]

    PVC["PVC"]
    STORAGE_CLASS["Storage Class"]
    CLOUD_STORAGE["Cloud Storage"]

    POSTGRES["PostgreSQL"]
    DB_PVC["Database PVC"]

    USERS --> ROUTE
    ROUTE --> SERVICE
    SERVICE --> PODS

    PODS --> PVC
    PVC --> STORAGE_CLASS
    STORAGE_CLASS --> CLOUD_STORAGE

    PODS --> POSTGRES
    POSTGRES --> DB_PVC

Logging Example

Store application logs.

logging.file.name=/app/uploads/logs/payment.log

Logs remain available after restart.


Backup Strategy

flowchart LR
    PVC["PersistentVolumeClaim"]
    BACKUP["Backup Job"]
    STORAGE["Object Storage"]
    DR["Disaster Recovery"]

    PVC --> BACKUP
    BACKUP --> STORAGE
    STORAGE --> DR

Always back up persistent storage.


Monitoring Storage

Useful commands.

oc get pvc
oc describe pvc upload-pvc
df -h

Common Problems

PVC Pending

Possible causes:

  • StorageClass missing
  • No storage available

Verify:

oc get storageclass

Permission Denied

Check:

  • Security Context
  • File ownership
  • Mount path

Disk Full

Verify:

df -h

Increase PVC size if supported.


Missing Files

Verify:

ls /app/uploads

Ensure the PVC is mounted correctly.


Best Practices

  • Never store uploaded files inside containers.
  • Use PVC for reports and documents.
  • Separate database storage from file storage.
  • Enable automated backups.
  • Monitor disk usage.
  • Use RWX only when required.
  • Use StorageClasses for dynamic provisioning.
  • Test recovery after Pod restart.

Common Mistakes

❌ Saving files inside /tmp.

❌ Running databases without PVC.

❌ Deleting PVC accidentally.

❌ Ignoring storage monitoring.

❌ Sharing one PVC across unrelated applications.


Advantages

  • Persistent storage
  • Survives Pod restart
  • Cloud-native architecture
  • Enterprise ready
  • Better scalability
  • Reliable file management
  • Easy backups
  • Simplified storage operations

Summary

Persistent Volume Claims are essential for Java applications that need durable storage.

Key takeaways:

  • Containers are temporary, but PVC-backed storage is persistent.
  • Spring Boot applications can store uploads, reports, and generated files on PVCs.
  • PVCs abstract the underlying storage implementation, making applications portable across cloud providers.
  • StorageClasses simplify dynamic provisioning.
  • Enterprise applications should always use PVCs for critical business data.

Interview Questions

  1. What is a Persistent Volume Claim (PVC)?
  2. Why do Java applications need persistent storage?
  3. What happens to container data after a Pod restart?
  4. How do you mount a PVC into a Spring Boot application?
  5. What are the different PVC access modes?
  6. When should you use ReadWriteMany?
  7. How do you verify that a PVC is mounted?
  8. Why should uploaded files never be stored inside a container?
  9. What is the role of a StorageClass?
  10. What are the best practices for persistent storage in enterprise Java applications?