Managing Volume Mounts in Spring Boot Pods
About
Spring Boot applications running inside containers often require access to:
Persistent storage (e.g., for file uploads, logs, or databases)
Externalized configurations (e.g.,
application.properties, YAML files)Secrets (e.g., database passwords, tokens)
Kubernetes and OpenShift provide a declarative way to mount these as volumes into pods so that applications can access them like regular files.
Types of Volume Mounts for Spring Boot Apps
PersistentVolumeClaim (PVC)
Store and retain application data persistently
ConfigMap
Inject application configuration files
Secret
Inject sensitive data like passwords
1. Mounting a PersistentVolumeClaim (PVC)
A Spring Boot application may need to:
Store or access files beyond its container lifecycle.
Persist logs, uploads, reports, caches, or temporary working data.
Retain state across pod restarts or re-deployments.
Since containers are ephemeral, persistent storage must be mounted into the pod using a PVC.
A PersistentVolumeClaim (PVC) is a user request for storage. It:
Specifies size and access requirements (e.g., 10Gi, ReadWriteOnce).
Is bound to an available PersistentVolume (PV) that satisfies the request.
Abstracts the storage backend from the application (block storage, file system, cloud disk, etc.).
Is referenced inside the pod to mount the storage.
Internal Flow of PVC Mounting
Step-by-step Kubernetes (OpenShift) mechanics:
User defines a PVC in a YAML manifest.
The OpenShift controller checks for an available PV that satisfies the request (capacity, access mode, storage class).
If found, the PVC is bound to that PV.
During pod scheduling, the container runtime (like CRI-O) mounts the volume from the node (or network) into the pod at the specified path.
Inside the container, the mount path behaves like a native directory.
If using dynamic provisioning:
A StorageClass is used.
A new PV is created on-the-fly using the storage plugin (e.g., AWS EBS, Ceph, NFS).
The PVC binds to that PV automatically.
Access Mode Considerations
The PVC must have an access mode compatible with how the Spring Boot app is deployed:
ReadWriteOnce (RWO): One pod on one node can mount as read-write.
ReadWriteMany (RWX): Multiple pods (across nodes) can mount concurrently.
Use RWX for clustered Spring Boot apps needing shared state (e.g., shared cache or uploads).
Use Case: File Upload Handling in Spring Boot Using PVC
We are building a Spring Boot app deployed on OpenShift that:
Lets users upload files via a REST API.
Saves these files to
/data/uploadsdirectory.Ensures uploaded files persist across pod restarts.
YAML Definitions
StorageClass (if using dynamic provisioning)
PersistentVolumeClaim
Deployment (Spring Boot App Pod + PVC Mount)
Spring Boot Application Code
application.properties
This ensures:
If
FILE_UPLOAD_PATHis passed (via env), it’s used.Else, defaults to
/tmp/uploads.
File Upload Controller
Expected Behavior
User uploads a file via REST.
File is stored under
/data/uploadsinside the container.This directory is mapped to the PVC → meaning file is stored on the persistent volume.
If the pod crashes, the file remains available when the pod restarts.
Testing the Workflow
Upload a file using curl
Check if the file persists after a pod restart
Common Use Cases in Spring Boot
File uploads
/data/uploads
Must persist even after app restarts
Exported reports
/data/reports
Can be backed up externally
Runtime temp storage
/tmp/data
Can use emptyDir or PVC if needed later
Log file persistence
/var/log/app
Useful for sidecar log shippers
Caches or binary blobs
/cache/store
Use with ReadWriteMany if clustered
2. Mounting ConfigMaps as Volumes
A ConfigMap in OpenShift is a key-value store used to manage non-sensitive configuration data independently from container images.
By mounting a ConfigMap as a volume into a Spring Boot pod, we can:
Externalize application configuration
Avoid rebuilding images for configuration changes
Support environment-specific setups (e.g., dev, test, prod)
Override default configurations such as
application.properties, YAML files, logging configurations, or arbitrary static files
Internal Flow of Mounting a ConfigMap as a Volume
A ConfigMap is defined containing configuration content (e.g.,
application.properties).The ConfigMap is mounted into a directory inside the container’s file system using a volume and volumeMount.
Spring Boot is configured to load its config files from that directory.
On container startup, Spring Boot reads the file(s) as if they were on the local file system.
This approach allows runtime reconfiguration without rebuilding the image, and even supports rolling updates on config changes.
Spring Boot Configuration Mechanism
Spring Boot supports external configuration through various sources in a specific order:
Command-line arguments
Environment variables
application.propertiesorapplication.ymlfiles on the classpathFiles in directories specified using
spring.config.location
Mounting a ConfigMap into a path like /config and then pointing Spring Boot to load from there lets we override default values inside the JAR.
Use Case: Inject externalized application.properties into a Spring Boot application
Create application.properties
Create a file named application.properties with the following content:
This file will be injected into the container through a ConfigMap.
Create the ConfigMap
Create a ConfigMap from the file:
This creates a ConfigMap named spring-config where the key is application.properties and the value is the content of the file.
We can verify:
Or use a YAML definition instead:
Apply it with:
Modify Spring Boot Application
Ensure the Spring Boot app:
Reads configuration from an external directory
Has a controller that uses the
app.titlevalue
Controller Example:
Important: This value must be picked up from the ConfigMap file mounted in the pod.
Step 4: Create Deployment with Volume Mount
Create a deployment that:
Mounts the ConfigMap into
/configTells Spring Boot to load config from
/config/application.properties
springboot-deployment.yaml
Apply it:
Expose the Application
Or in OpenShift:
Get the URL:
Test the Endpoint
Access:
Expected output:
This confirms that:
The application read config from the mounted
/config/application.propertiesThe ConfigMap is functioning correctly
3. Mounting Secrets as Volumes
A Secret in OpenShift is a Kubernetes object used to store sensitive data such as:
Database credentials
API keys
OAuth tokens
TLS certificates
Mounting Secrets as volumes into a Spring Boot pod enables the application to securely access sensitive configuration at runtime without hardcoding or baking credentials into container images.
Secrets are base64-encoded and are mounted into the container’s file system as plain files. These files can then be read by the Spring Boot application as needed.
Internal Behavior of Secret Volumes
A Secret object is created, containing key-value pairs.
The pod declares a
volumefrom the secret and a correspondingvolumeMountto define the mount path.Kubernetes injects the contents of each secret key as a separate file in the specified directory.
Spring Boot (or other application logic) reads the secrets from disk, either during startup or on demand.
Each key becomes a file with the key as filename and the value as its contents.
When to Use Secrets as Volumes
When we do not want to expose sensitive data through environment variables.
When external libraries or tools (e.g., database clients, messaging clients, TLS consumers) expect config as files.
When we want to rotate secrets dynamically (e.g., mount a new TLS cert).
Use Case: Injecting Database Credentials into a Spring Boot App
Create the Kubernetes Secret
Imperative Method (using CLI)
This creates a Secret named db-credentials with two keys: username and password.
Declarative YAML Alternative
Mount the Secret into the Spring Boot Pod
Deployment YAML Snippet
Spring Boot Code to Read Credentials
We can use either:
Option 1: @Value with file: syntax
application.properties
Spring Boot will read the contents of the file /secrets/username and /secrets/password.
Make sure to pass SPRING_CONFIG_ADDITIONAL_LOCATION=file:/secrets/ as an environment variable or as a --spring.config.additional-location argument in our container.
Option 2: Read files programmatically
We can then use this service in our DB configuration or elsewhere.
Configure our DataSource (Optional)
If we are manually configuring our DataSource, we can use the credential service above:
Last updated