A comprehensive Docker client library for Java applications providing programmatic Docker API access with container lifecycle management, image operations, and Docker Swarm support.
—
This document covers Docker volume management including creation, inspection, mounting, and lifecycle operations for persistent data storage.
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.messages.Volume;
import com.spotify.docker.client.messages.VolumeList;
// List all volumes
VolumeList volumeList = docker.listVolumes();
List<Volume> volumes = volumeList.volumes();
List<String> warnings = volumeList.warnings();
// Display volume information
for (Volume volume : volumes) {
System.out.println("Volume: " + volume.name());
System.out.println("Driver: " + volume.driver());
System.out.println("Mountpoint: " + volume.mountpoint());
System.out.println("Scope: " + volume.scope());
}
// Check for warnings
if (!warnings.isEmpty()) {
System.out.println("Warnings: " + warnings);
}// Filter volumes by name
VolumeList namedVolumes = docker.listVolumes(
ListVolumesParam.name("my-data-volume")
);
// Filter dangling volumes (not attached to any container)
VolumeList danglingVolumes = docker.listVolumes(
ListVolumesParam.dangling(true)
);
// Filter by driver
VolumeList localVolumes = docker.listVolumes(
ListVolumesParam.driver("local")
);
// Custom filters
VolumeList filtered = docker.listVolumes(
ListVolumesParam.filter("label", "environment=production")
);// Inspect specific volume
Volume volume = docker.inspectVolume("volume-name-or-id");
System.out.println("Name: " + volume.name());
System.out.println("Driver: " + volume.driver());
System.out.println("Mountpoint: " + volume.mountpoint());
System.out.println("Scope: " + volume.scope());
// Volume labels
Map<String, String> labels = volume.labels();
if (labels != null) {
System.out.println("Labels:");
for (Map.Entry<String, String> entry : labels.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
}
// Driver options
Map<String, String> options = volume.options();
if (options != null) {
System.out.println("Driver Options:");
for (Map.Entry<String, String> entry : options.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
}// Create anonymous volume (Docker generates name)
Volume anonymousVolume = docker.createVolume();
System.out.println("Created anonymous volume: " + anonymousVolume.name());import com.spotify.docker.client.messages.Volume;
// Create simple named volume
Volume simpleVolume = Volume.builder()
.name("my-data-volume")
.build();
Volume created = docker.createVolume(simpleVolume);
System.out.println("Created volume: " + created.name());// Create volume with custom driver and options
Volume advancedVolume = Volume.builder()
.name("production-data")
.driver("local")
.labels(Map.of(
"environment", "production",
"application", "database",
"backup", "enabled"
))
.options(Map.of(
"type", "tmpfs",
"device", "tmpfs",
"o", "size=500m,uid=1000,gid=1000"
))
.build();
Volume created = docker.createVolume(advancedVolume);// Local driver with bind mount
Volume bindVolume = Volume.builder()
.name("host-bind-volume")
.driver("local")
.options(Map.of(
"type", "bind",
"o", "bind",
"device", "/host/path/data"
))
.build();
// NFS volume
Volume nfsVolume = Volume.builder()
.name("nfs-shared-volume")
.driver("local")
.options(Map.of(
"type", "nfs",
"o", "addr=nfs.example.com,rw",
"device", ":/path/to/shared/data"
))
.build();
// tmpfs volume for temporary data
Volume tmpfsVolume = Volume.builder()
.name("temp-volume")
.driver("local")
.options(Map.of(
"type", "tmpfs",
"device", "tmpfs",
"o", "size=1g,mode=1777"
))
.build();
docker.createVolume(bindVolume);
docker.createVolume(nfsVolume);
docker.createVolume(tmpfsVolume);// Using volumes in container configuration
ContainerConfig config = ContainerConfig.builder()
.image("postgres:13")
.env("POSTGRES_DB=myapp", "POSTGRES_PASSWORD=secret")
// Volume mount points (creates anonymous volumes)
.volumes("/var/lib/postgresql/data", "/var/log/postgresql")
.build();
// Host configuration with volume binds
HostConfig hostConfig = HostConfig.builder()
// Named volume mounts
.binds(
"postgres-data:/var/lib/postgresql/data",
"postgres-logs:/var/log/postgresql",
"/host/config:/etc/postgresql/conf.d:ro" // Read-only bind
)
// Alternative: using Mount objects for more control
.mounts(
Mount.builder()
.type("volume")
.source("postgres-data")
.target("/var/lib/postgresql/data")
.build(),
Mount.builder()
.type("bind")
.source("/host/backup")
.target("/backup")
.readOnly(true)
.build()
)
.build();
ContainerConfig fullConfig = config.toBuilder()
.hostConfig(hostConfig)
.build();
ContainerCreation container = docker.createContainer(fullConfig);// Mount with detailed configuration
Mount dataMount = Mount.builder()
.type("volume")
.source("app-data")
.target("/app/data")
.readOnly(false)
// Volume options
.volumeOptions(VolumeOptions.builder()
.noCopy(false) // Copy data from container to volume on first mount
.labels(Map.of("mount-type", "data"))
.driverConfig(Driver.builder()
.name("local")
.options(Map.of("type", "ext4"))
.build())
.build())
// Bind options (for bind mounts)
.bindOptions(BindOptions.builder()
.propagation("rprivate")
.build())
// tmpfs options (for tmpfs mounts)
.tmpfsOptions(TmpfsOptions.builder()
.sizeBytes(1024L * 1024 * 1024) // 1GB
.mode(0755)
.build())
.build();
HostConfig hostConfig = HostConfig.builder()
.mounts(dataMount)
.build();public class VolumeBindingPatterns {
public void demonstrateBindPatterns(DockerClient docker)
throws DockerException, InterruptedException {
// 1. Named volume for persistent data
Volume dataVolume = Volume.builder()
.name("app-persistent-data")
.labels(Map.of("purpose", "application-data"))
.build();
docker.createVolume(dataVolume);
// 2. Bind mount for configuration
String configBind = "/host/app/config:/app/config:ro";
// 3. tmpfs for temporary/cache data
String tmpfsBind = "tmpfs:/tmp:tmpfs,size=500m";
// 4. Anonymous volume for logs
ContainerConfig config = ContainerConfig.builder()
.image("myapp:latest")
.volumes("/app/logs") // Anonymous volume
.hostConfig(HostConfig.builder()
.binds(
"app-persistent-data:/app/data", // Named volume
configBind, // Read-only bind
tmpfsBind // tmpfs mount
)
.build())
.build();
ContainerCreation container = docker.createContainer(config);
}
}// Remove volume by name
docker.removeVolume("volume-name");
// Remove volume object
Volume volume = docker.inspectVolume("my-volume");
docker.removeVolume(volume);public void safeVolumeRemoval(DockerClient docker, String volumeName) {
try {
// Check if volume exists
Volume volume = docker.inspectVolume(volumeName);
// Check if volume is in use by any containers
List<Container> containers = docker.listContainers(
DockerClient.ListContainersParam.allContainers()
);
boolean inUse = false;
for (Container container : containers) {
ContainerInfo info = docker.inspectContainer(container.id());
// Check mounts
for (ContainerMount mount : info.mounts()) {
if (volumeName.equals(mount.name()) ||
volumeName.equals(mount.source())) {
System.out.println("Volume in use by container: " + container.id());
inUse = true;
break;
}
}
}
if (!inUse) {
docker.removeVolume(volumeName);
System.out.println("Successfully removed volume: " + volumeName);
} else {
System.out.println("Volume is in use and cannot be removed");
}
} catch (DockerException | InterruptedException e) {
System.err.println("Error removing volume: " + e.getMessage());
}
}public void cleanupUnusedVolumes(DockerClient docker)
throws DockerException, InterruptedException {
// Get all dangling volumes
VolumeList danglingList = docker.listVolumes(
ListVolumesParam.dangling(true)
);
List<Volume> danglingVolumes = danglingList.volumes();
System.out.println("Found " + danglingVolumes.size() + " dangling volumes");
for (Volume volume : danglingVolumes) {
try {
docker.removeVolume(volume.name());
System.out.println("Removed dangling volume: " + volume.name());
} catch (DockerException e) {
System.err.println("Failed to remove volume " + volume.name() + ": " + e.getMessage());
}
}
// Remove volumes with specific labels (e.g., temporary volumes)
VolumeList allVolumes = docker.listVolumes();
for (Volume volume : allVolumes.volumes()) {
Map<String, String> labels = volume.labels();
if (labels != null && "true".equals(labels.get("temporary"))) {
try {
docker.removeVolume(volume.name());
System.out.println("Removed temporary volume: " + volume.name());
} catch (DockerException e) {
System.err.println("Failed to remove temporary volume " + volume.name() + ": " + e.getMessage());
}
}
}
}public void backupVolume(DockerClient docker, String volumeName, String backupPath)
throws DockerException, InterruptedException {
System.out.println("Starting backup of volume: " + volumeName);
// Create a temporary container to access the volume
ContainerConfig backupConfig = ContainerConfig.builder()
.image("alpine:latest")
.cmd("tar", "czf", "/backup/volume-backup.tar.gz", "-C", "/data", ".")
.volumes("/backup")
.hostConfig(HostConfig.builder()
.binds(
volumeName + ":/data:ro", // Mount volume as read-only
backupPath + ":/backup" // Mount backup destination
)
.autoRemove(AutoRemove.always()) // Auto-remove when done
.build())
.build();
ContainerCreation backupContainer = docker.createContainer(backupConfig);
try {
// Start backup process
docker.startContainer(backupContainer.id());
// Wait for completion
ContainerExit exit = docker.waitContainer(backupContainer.id());
if (exit.statusCode() == 0) {
System.out.println("Volume backup completed successfully");
} else {
System.err.println("Backup failed with exit code: " + exit.statusCode());
}
} finally {
// Container is auto-removed due to autoRemove setting
System.out.println("Backup container cleaned up");
}
}public void restoreVolume(DockerClient docker, String volumeName, String backupFile)
throws DockerException, InterruptedException {
System.out.println("Restoring volume: " + volumeName + " from " + backupFile);
// Ensure target volume exists
try {
docker.inspectVolume(volumeName);
} catch (Exception e) {
// Create volume if it doesn't exist
Volume newVolume = Volume.builder()
.name(volumeName)
.build();
docker.createVolume(newVolume);
System.out.println("Created new volume: " + volumeName);
}
// Create restore container
ContainerConfig restoreConfig = ContainerConfig.builder()
.image("alpine:latest")
.cmd("tar", "xzf", "/backup/" + new File(backupFile).getName(), "-C", "/data")
.volumes("/backup", "/data")
.hostConfig(HostConfig.builder()
.binds(
new File(backupFile).getParent() + ":/backup:ro",
volumeName + ":/data"
)
.autoRemove(AutoRemove.always())
.build())
.build();
ContainerCreation restoreContainer = docker.createContainer(restoreConfig);
try {
docker.startContainer(restoreContainer.id());
ContainerExit exit = docker.waitContainer(restoreContainer.id());
if (exit.statusCode() == 0) {
System.out.println("Volume restore completed successfully");
} else {
System.err.println("Restore failed with exit code: " + exit.statusCode());
}
} finally {
System.out.println("Restore container cleaned up");
}
}public void migrateVolumeData(DockerClient docker, String sourceVolume, String targetVolume)
throws DockerException, InterruptedException {
System.out.println("Migrating data from " + sourceVolume + " to " + targetVolume);
// Ensure target volume exists
Volume target = Volume.builder()
.name(targetVolume)
.build();
docker.createVolume(target);
// Create migration container
ContainerConfig migrationConfig = ContainerConfig.builder()
.image("alpine:latest")
.cmd("sh", "-c", "cp -av /source/. /target/")
.volumes("/source", "/target")
.hostConfig(HostConfig.builder()
.binds(
sourceVolume + ":/source:ro",
targetVolume + ":/target"
)
.autoRemove(AutoRemove.always())
.build())
.build();
ContainerCreation migrationContainer = docker.createContainer(migrationConfig);
try {
docker.startContainer(migrationContainer.id());
// Monitor progress with logs
try (LogStream logs = docker.logs(migrationContainer.id(),
DockerClient.LogsParam.follow(),
DockerClient.LogsParam.stdout(),
DockerClient.LogsParam.stderr())) {
logs.forEachRemaining(logMessage -> {
System.out.println("Migration: " + logMessage.content().toStringUtf8().trim());
});
}
ContainerExit exit = docker.waitContainer(migrationContainer.id());
if (exit.statusCode() == 0) {
System.out.println("Volume migration completed successfully");
// Verify migration
verifyVolumeMigration(docker, sourceVolume, targetVolume);
} else {
System.err.println("Migration failed with exit code: " + exit.statusCode());
}
} finally {
System.out.println("Migration container cleaned up");
}
}
private void verifyVolumeMigration(DockerClient docker, String sourceVolume, String targetVolume)
throws DockerException, InterruptedException {
// Create verification container
ContainerConfig verifyConfig = ContainerConfig.builder()
.image("alpine:latest")
.cmd("sh", "-c",
"echo 'Source files:' && find /source -type f | wc -l && " +
"echo 'Target files:' && find /target -type f | wc -l && " +
"echo 'Source size:' && du -sh /source && " +
"echo 'Target size:' && du -sh /target")
.hostConfig(HostConfig.builder()
.binds(
sourceVolume + ":/source:ro",
targetVolume + ":/target:ro"
)
.autoRemove(AutoRemove.always())
.build())
.build();
ContainerCreation verifyContainer = docker.createContainer(verifyConfig);
docker.startContainer(verifyContainer.id());
try (LogStream logs = docker.logs(verifyContainer.id(),
DockerClient.LogsParam.stdout(),
DockerClient.LogsParam.stderr())) {
String verification = logs.readFully();
System.out.println("Migration verification:\n" + verification);
}
docker.waitContainer(verifyContainer.id());
}public void analyzeVolumeUsage(DockerClient docker)
throws DockerException, InterruptedException {
VolumeList volumeList = docker.listVolumes();
System.out.println("Volume Usage Analysis:");
System.out.println("Total volumes: " + volumeList.volumes().size());
Map<String, Integer> driverCount = new HashMap<>();
Map<String, List<Volume>> volumesByLabel = new HashMap<>();
for (Volume volume : volumeList.volumes()) {
// Count by driver
driverCount.merge(volume.driver(), 1, Integer::sum);
// Group by labels
Map<String, String> labels = volume.labels();
if (labels != null) {
for (String labelValue : labels.values()) {
volumesByLabel.computeIfAbsent(labelValue, k -> new ArrayList<>()).add(volume);
}
}
// Get size information (requires container to check)
getVolumeSize(docker, volume);
}
System.out.println("Volumes by driver:");
driverCount.forEach((driver, count) ->
System.out.println(" " + driver + ": " + count));
System.out.println("Volumes by label value:");
volumesByLabel.forEach((label, volumes) ->
System.out.println(" " + label + ": " + volumes.size() + " volumes"));
}
private void getVolumeSize(DockerClient docker, Volume volume) {
try {
ContainerConfig sizeCheckConfig = ContainerConfig.builder()
.image("alpine:latest")
.cmd("du", "-sh", "/data")
.hostConfig(HostConfig.builder()
.binds(volume.name() + ":/data:ro")
.autoRemove(AutoRemove.always())
.build())
.build();
ContainerCreation container = docker.createContainer(sizeCheckConfig);
docker.startContainer(container.id());
try (LogStream logs = docker.logs(container.id(),
DockerClient.LogsParam.stdout())) {
String sizeOutput = logs.readFully().trim();
System.out.println("Volume " + volume.name() + " size: " + sizeOutput);
}
docker.waitContainer(container.id());
} catch (Exception e) {
System.err.println("Could not get size for volume " + volume.name() + ": " + e.getMessage());
}
}// Filter by volume name
ListVolumesParam.name("exact-volume-name")
// Filter dangling volumes
ListVolumesParam.dangling()
ListVolumesParam.dangling(true)
// Filter by driver
ListVolumesParam.driver("local")
ListVolumesParam.driver("nfs")
// Custom filters
ListVolumesParam.filter("scope", "local")
ListVolumesParam.filter("label", "environment=production")
ListVolumesParam.filter("label", "backup") // Has label keypublic class VolumeManagementExample {
public void demonstrateVolumeManagement(DockerClient docker)
throws DockerException, InterruptedException {
System.out.println("Starting comprehensive volume management demo...");
// 1. Create volumes for different purposes
createApplicationVolumes(docker);
// 2. Deploy application with volume mounts
deployApplicationWithVolumes(docker);
// 3. Perform volume operations
performVolumeOperations(docker);
// 4. Cleanup
cleanupVolumeDemo(docker);
}
private void createApplicationVolumes(DockerClient docker)
throws DockerException, InterruptedException {
System.out.println("Creating application volumes...");
// Database data volume
Volume dbData = Volume.builder()
.name("webapp-db-data")
.driver("local")
.labels(Map.of(
"application", "webapp",
"tier", "database",
"backup", "enabled"
))
.build();
// Application logs volume
Volume appLogs = Volume.builder()
.name("webapp-logs")
.driver("local")
.labels(Map.of(
"application", "webapp",
"tier", "application",
"retention", "30days"
))
.build();
// Cache volume (tmpfs)
Volume cacheVolume = Volume.builder()
.name("webapp-cache")
.driver("local")
.options(Map.of(
"type", "tmpfs",
"device", "tmpfs",
"o", "size=1g,mode=0755"
))
.labels(Map.of(
"application", "webapp",
"tier", "cache",
"temporary", "true"
))
.build();
docker.createVolume(dbData);
docker.createVolume(appLogs);
docker.createVolume(cacheVolume);
System.out.println("Created application volumes successfully");
}
private void deployApplicationWithVolumes(DockerClient docker)
throws DockerException, InterruptedException {
System.out.println("Deploying application with volume mounts...");
// Database container
ContainerConfig dbConfig = ContainerConfig.builder()
.image("postgres:13")
.env("POSTGRES_DB=webapp", "POSTGRES_USER=app", "POSTGRES_PASSWORD=secret")
.hostConfig(HostConfig.builder()
.binds("webapp-db-data:/var/lib/postgresql/data")
.build())
.build();
// Application container
ContainerConfig appConfig = ContainerConfig.builder()
.image("nginx:latest")
.hostConfig(HostConfig.builder()
.binds(
"webapp-logs:/var/log/nginx",
"webapp-cache:/var/cache/nginx"
)
.portBindings(Map.of("80/tcp",
List.of(PortBinding.of("0.0.0.0", "8080"))))
.build())
.build();
ContainerCreation dbContainer = docker.createContainer(dbConfig, "webapp-db");
ContainerCreation appContainer = docker.createContainer(appConfig, "webapp-app");
docker.startContainer(dbContainer.id());
docker.startContainer(appContainer.id());
System.out.println("Application deployed with volume mounts");
// Verify mounts
verifyContainerMounts(docker, appContainer.id());
}
private void verifyContainerMounts(DockerClient docker, String containerId)
throws DockerException, InterruptedException {
ContainerInfo info = docker.inspectContainer(containerId);
System.out.println("Container mounts for " + containerId + ":");
for (ContainerMount mount : info.mounts()) {
System.out.println(" Type: " + mount.type());
System.out.println(" Source: " + mount.source());
System.out.println(" Destination: " + mount.destination());
System.out.println(" Mode: " + mount.mode());
System.out.println(" RW: " + mount.rw());
System.out.println(" ---");
}
}
private void performVolumeOperations(DockerClient docker)
throws DockerException, InterruptedException {
System.out.println("Performing volume operations...");
// Backup database volume
backupVolume(docker, "webapp-db-data", "/tmp/backup");
// Analyze volume usage
analyzeVolumeUsage(docker);
// List volumes with specific labels
VolumeList webappVolumes = docker.listVolumes(
ListVolumesParam.filter("label", "application=webapp")
);
System.out.println("Webapp volumes:");
for (Volume volume : webappVolumes.volumes()) {
System.out.println(" " + volume.name() + " (" + volume.driver() + ")");
}
}
private void cleanupVolumeDemo(DockerClient docker) {
try {
System.out.println("Cleaning up volume demo...");
// Stop and remove containers
List<Container> containers = docker.listContainers(
DockerClient.ListContainersParam.allContainers()
);
for (Container container : containers) {
if (container.names().stream().anyMatch(name -> name.contains("webapp-"))) {
docker.stopContainer(container.id(), 5);
docker.removeContainer(container.id());
System.out.println("Removed container: " + container.id());
}
}
// Remove demo volumes
String[] volumesToRemove = {"webapp-db-data", "webapp-logs", "webapp-cache"};
for (String volumeName : volumesToRemove) {
try {
docker.removeVolume(volumeName);
System.out.println("Removed volume: " + volumeName);
} catch (Exception e) {
System.err.println("Could not remove volume " + volumeName + ": " + e.getMessage());
}
}
} catch (Exception e) {
System.err.println("Cleanup error: " + e.getMessage());
}
}
}The volume management system provides comprehensive control over persistent storage with support for multiple storage drivers, backup strategies, data migration, and lifecycle management for containerized applications.
Install with Tessl CLI
npx tessl i tessl/maven-com-spotify--docker-client