Skip to content

DigitalOcean Volumes (Block Storage) Overview

Introduction

DigitalOcean Volumes provide highly available block storage that can be attached to Droplets. They offer persistent, scalable storage independent of Droplet lifecycle, perfect for databases, file storage, and applications requiring persistent data.

Key Features

  • Persistent Storage: Data persists independently of Droplets
  • Scalable: 1 GB to 16 TB per volume
  • High Performance: SSD-backed storage
  • Snapshots: Point-in-time backups
  • Resizable: Increase size without downtime
  • Highly Available: Replicated across multiple drives
  • Flexible Attachment: Attach/detach from Droplets
  • Kubernetes Integration: Use as Persistent Volumes
  • Affordable: $0.10/GB/month
  • Regional: Available in all regions

Volume Architecture

┌─────────────────────────────────────────────────────────────┐
│                    DigitalOcean Region                       │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              Block Storage System                       │ │
│  │  ┌──────────────────────────────────────────────────┐  │ │
│  │  │  Volume: db-data (100 GB)                        │  │ │
│  │  │  ├─> Replicated across multiple drives           │  │ │
│  │  │  ├─> SSD-backed                                   │  │ │
│  │  │  └─> Highly available                             │  │ │
│  │  └──────────────────────────────────────────────────┘  │ │
│  └────────────────────────────┬───────────────────────────┘ │
│                                │                             │
│                       ┌────────▼────────┐                    │
│                       │  Attached to    │                    │
│                       └────────┬────────┘                    │
│                                │                             │
│  ┌────────────────────────────▼───────────────────────────┐ │
│  │              Droplet (Database Server)                  │ │
│  │  ┌──────────────────────────────────────────────────┐  │ │
│  │  │  Local SSD: 25 GB (OS, apps)                     │  │ │
│  │  └──────────────────────────────────────────────────┘  │ │
│  │  ┌──────────────────────────────────────────────────┐  │ │
│  │  │  Volume: /mnt/db-data (100 GB)                   │  │ │
│  │  │  └─> PostgreSQL data directory                   │  │ │
│  │  └──────────────────────────────────────────────────┘  │ │
│  └──────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘

Volume can be detached and reattached to different Droplets

Volume vs Local Storage

Feature Volume (Block Storage) Local Droplet Storage
Persistence Independent of Droplet Tied to Droplet
Size 1 GB - 16 TB Fixed with Droplet
Resizable Yes (increase only) No
Snapshots Yes Droplet snapshots only
Attachment Detach/reattach Cannot detach
Performance SSD, consistent SSD, local
Cost $0.10/GB/month Included with Droplet
Use Case Databases, persistent data OS, applications

Use Cases

1. Database Storage

PostgreSQL/MySQL/MongoDB:
├─> Store database files on volume
├─> Separate data from OS
├─> Easy backup with snapshots
├─> Resize as data grows
└─> Migrate between Droplets

Benefits:
├─> Data persistence
├─> Independent scaling
├─> Disaster recovery
└─> Performance isolation

2. File Storage

Application Files:
├─> User uploads
├─> Media files
├─> Document storage
├─> Shared storage
└─> Log files

Benefits:
├─> Scalable capacity
├─> Persistent storage
├─> Easy backup
└─> Flexible attachment

3. Kubernetes Persistent Volumes

Container Storage:
├─> StatefulSets
├─> Database pods
├─> Shared volumes
├─> Configuration storage
└─> Log aggregation

Benefits:
├─> Pod-independent storage
├─> Dynamic provisioning
├─> Snapshot support
└─> Automatic attachment

4. Backup and Archive

Data Protection:
├─> Database backups
├─> Application backups
├─> Log archives
├─> Disaster recovery
└─> Compliance storage

Benefits:
├─> Cost-effective
├─> Snapshot capability
├─> Long-term retention
└─> Easy restoration

5. Development Environments

Dev/Test Data:
├─> Test databases
├─> Development files
├─> Shared datasets
├─> CI/CD artifacts
└─> Build caches

Benefits:
├─> Quick provisioning
├─> Easy cloning
├─> Cost-effective
└─> Flexible sizing

Creating Volumes

Via Control Panel

1. Navigate to Volumes
2. Click "Create Volume"
3. Configure:
   ├─> Name: db-data
   ├─> Size: 100 GB
   ├─> Region: NYC3 (match Droplet)
   └─> Attach to Droplet (optional)
4. Click "Create Volume"
5. Format and mount (if new)

Via doctl CLI

# Create volume
doctl compute volume create db-data \
  --region nyc3 \
  --size 100GiB \
  --desc "Database storage"

# List volumes
doctl compute volume list

# Attach to Droplet
doctl compute volume-action attach VOLUME_ID DROPLET_ID

# Detach from Droplet
doctl compute volume-action detach VOLUME_ID DROPLET_ID

Via API

# Create volume
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DO_TOKEN" \
  -d '{
    "size_gigabytes": 100,
    "name": "db-data",
    "description": "Database storage",
    "region": "nyc3",
    "filesystem_type": "ext4"
  }' \
  "https://api.digitalocean.com/v2/volumes"

# Attach volume
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DO_TOKEN" \
  -d '{
    "type": "attach",
    "droplet_id": 12345678,
    "region": "nyc3"
  }' \
  "https://api.digitalocean.com/v2/volumes/VOLUME_ID/actions"

Formatting and Mounting

First-Time Setup (New Volume)

# SSH into Droplet
ssh root@droplet-ip

# Find volume device
lsblk

# Format volume (ext4)
sudo mkfs.ext4 /dev/disk/by-id/scsi-0DO_Volume_db-data

# Create mount point
sudo mkdir -p /mnt/db-data

# Mount volume
sudo mount -o discard,defaults /dev/disk/by-id/scsi-0DO_Volume_db-data /mnt/db-data

# Verify mount
df -h /mnt/db-data

# Make permanent (add to /etc/fstab)
echo '/dev/disk/by-id/scsi-0DO_Volume_db-data /mnt/db-data ext4 defaults,nofail,discard 0 0' | sudo tee -a /etc/fstab

Mounting Existing Volume

# Create mount point
sudo mkdir -p /mnt/db-data

# Mount volume (already formatted)
sudo mount -o discard,defaults /dev/disk/by-id/scsi-0DO_Volume_db-data /mnt/db-data

# Add to /etc/fstab for auto-mount
echo '/dev/disk/by-id/scsi-0DO_Volume_db-data /mnt/db-data ext4 defaults,nofail,discard 0 0' | sudo tee -a /etc/fstab

Resizing Volumes

Increase Volume Size

# Via doctl
doctl compute volume-action resize VOLUME_ID --size 200 --region nyc3

# Via API
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DO_TOKEN" \
  -d '{
    "type": "resize",
    "size_gigabytes": 200,
    "region": "nyc3"
  }' \
  "https://api.digitalocean.com/v2/volumes/VOLUME_ID/actions"

Resize Filesystem

# For ext4 filesystem
sudo resize2fs /dev/disk/by-id/scsi-0DO_Volume_db-data

# For XFS filesystem
sudo xfs_growfs /mnt/db-data

# Verify new size
df -h /mnt/db-data

Note: Volumes can only be increased in size, not decreased.

Snapshots

Creating Snapshots

# Via doctl
doctl compute volume-snapshot create \
  --volume-id VOLUME_ID \
  --snapshot-name "db-data-backup-2026-01-10"

# List snapshots
doctl compute volume-snapshot list

# Delete snapshot
doctl compute volume-snapshot delete SNAPSHOT_ID

Restoring from Snapshot

# Create new volume from snapshot
doctl compute volume create db-data-restored \
  --region nyc3 \
  --snapshot-id SNAPSHOT_ID

# Attach to Droplet
doctl compute volume-action attach VOLUME_ID DROPLET_ID

# Mount volume
sudo mount /dev/disk/by-id/scsi-0DO_Volume_db-data-restored /mnt/restored

Kubernetes Integration

Storage Class

# Default storage class (pre-configured)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: do-block-storage
provisioner: dobs.csi.digitalocean.com
parameters:
  type: pd-ssd
allowVolumeExpansion: true

Persistent Volume Claim

# Request persistent storage
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: do-block-storage

Using in Pod

# StatefulSet with persistent storage
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_PASSWORD
          value: "password"
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: postgres-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: do-block-storage
      resources:
        requests:
          storage: 10Gi

Volume Expansion

# Edit PVC to increase size
kubectl edit pvc postgres-pvc

# Change storage request
spec:
  resources:
    requests:
      storage: 20Gi  # Increased from 10Gi

# Verify expansion
kubectl get pvc postgres-pvc

Database Configuration

PostgreSQL

# Stop PostgreSQL
sudo systemctl stop postgresql

# Move data to volume
sudo rsync -av /var/lib/postgresql/ /mnt/db-data/

# Update PostgreSQL config
sudo nano /etc/postgresql/15/main/postgresql.conf
# Change: data_directory = '/mnt/db-data/15/main'

# Update permissions
sudo chown -R postgres:postgres /mnt/db-data

# Start PostgreSQL
sudo systemctl start postgresql

MySQL/MariaDB

# Stop MySQL
sudo systemctl stop mysql

# Move data to volume
sudo rsync -av /var/lib/mysql/ /mnt/db-data/

# Update MySQL config
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
# Change: datadir = /mnt/db-data

# Update AppArmor (Ubuntu)
sudo nano /etc/apparmor.d/usr.sbin.mysqld
# Add: /mnt/db-data/ r,
#      /mnt/db-data/** rwk,

sudo systemctl reload apparmor

# Start MySQL
sudo systemctl start mysql

MongoDB

# Stop MongoDB
sudo systemctl stop mongod

# Move data to volume
sudo rsync -av /var/lib/mongodb/ /mnt/db-data/

# Update MongoDB config
sudo nano /etc/mongod.conf
# Change: dbPath: /mnt/db-data

# Update permissions
sudo chown -R mongodb:mongodb /mnt/db-data

# Start MongoDB
sudo systemctl start mongod

Performance Optimization

Best Practices

1. Use Appropriate Filesystem
   ├─> ext4: General purpose
   ├─> XFS: Large files, databases
   └─> Avoid: FAT32, NTFS

2. Enable Discard/TRIM
   ├─> Mount option: discard
   ├─> Improves performance
   └─> Reduces wear

3. Optimize I/O Scheduler
   ├─> Use deadline or noop
   ├─> Better for SSDs
   └─> Reduces latency

4. Monitor Performance
   ├─> iostat
   ├─> iotop
   └─> DigitalOcean metrics

5. Right-Size Volumes
   ├─> Don't over-provision
   ├─> Monitor usage
   └─> Resize as needed

I/O Scheduler Configuration

# Check current scheduler
cat /sys/block/sda/queue/scheduler

# Set to deadline (recommended for volumes)
echo deadline | sudo tee /sys/block/sda/queue/scheduler

# Make permanent
echo 'ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="deadline"' | sudo tee /etc/udev/rules.d/60-scheduler.rules

Monitoring

Check Volume Usage

# Disk usage
df -h /mnt/db-data

# Inode usage
df -i /mnt/db-data

# Detailed usage
du -sh /mnt/db-data/*

I/O Performance

# Install iostat
sudo apt-get install sysstat

# Monitor I/O
iostat -x 1

# Monitor specific device
iostat -x /dev/sda 1

# Top I/O processes
sudo iotop

DigitalOcean Metrics

# Via doctl
doctl compute volume get VOLUME_ID

# View in control panel
# Navigate to Volumes → Select Volume → Graphs

Backup Strategies

1. Volume Snapshots

# Automated snapshot script
#!/bin/bash
VOLUME_ID="your-volume-id"
DATE=$(date +%Y%m%d-%H%M%S)

doctl compute volume-snapshot create \
  --volume-id $VOLUME_ID \
  --snapshot-name "backup-$DATE"

# Keep only last 7 snapshots
doctl compute volume-snapshot list --format ID,Created | \
  tail -n +8 | \
  awk '{print $1}' | \
  xargs -I {} doctl compute volume-snapshot delete {}

2. Application-Level Backups

# PostgreSQL backup to volume
pg_dump dbname | gzip > /mnt/db-data/backups/db-$(date +%Y%m%d).sql.gz

# MySQL backup to volume
mysqldump --all-databases | gzip > /mnt/db-data/backups/db-$(date +%Y%m%d).sql.gz

# MongoDB backup to volume
mongodump --out /mnt/db-data/backups/mongo-$(date +%Y%m%d)

3. Sync to Spaces

# Install s3cmd
sudo apt-get install s3cmd

# Configure s3cmd
s3cmd --configure

# Sync volume to Spaces
s3cmd sync /mnt/db-data/ s3://my-bucket/backups/

Cost Optimization

Strategies

1. Right-Size Volumes
   ├─> Monitor actual usage
   ├─> Don't over-provision
   └─> Start small, grow as needed

2. Delete Unused Volumes
   ├─> Identify detached volumes
   ├─> Remove old test volumes
   └─> Clean up regularly

3. Manage Snapshots
   ├─> Delete old snapshots
   ├─> Keep only necessary backups
   └─> Automate retention policy

4. Use Appropriate Storage
   ├─> Volumes for persistent data
   ├─> Local storage for temporary
   └─> Spaces for archives

5. Monitor Costs
   ├─> Track volume count
   ├─> Monitor snapshot usage
   └─> Review monthly bills

Cost Calculation

Volume Pricing: $0.10/GB/month

Examples:
├─> 10 GB volume: $1/month
├─> 100 GB volume: $10/month
├─> 1 TB volume: $100/month
└─> 16 TB volume: $1,600/month

Snapshots: $0.05/GB/month
├─> 100 GB snapshot: $5/month
└─> Cheaper than keeping volume

Troubleshooting

Volume Not Visible

# Check if attached
doctl compute volume list

# Check device
lsblk

# Check dmesg
dmesg | grep sd

# Rescan SCSI bus
echo "- - -" | sudo tee /sys/class/scsi_host/host*/scan

Mount Failures

# Check filesystem
sudo fsck /dev/disk/by-id/scsi-0DO_Volume_db-data

# Check fstab
cat /etc/fstab

# Try manual mount
sudo mount -v /dev/disk/by-id/scsi-0DO_Volume_db-data /mnt/db-data

# Check mount options
mount | grep db-data

Performance Issues

# Check I/O wait
top
# Look for high %wa

# Check disk I/O
iostat -x 1

# Check for errors
dmesg | grep error

# Verify mount options
mount | grep db-data
# Should include: discard

Limitations

  • Attachment: One volume per Droplet at a time
  • Region: Must be in same region as Droplet
  • Size: 1 GB minimum, 16 TB maximum
  • Resize: Can only increase, not decrease
  • Access Mode: ReadWriteOnce (single Droplet)
  • Snapshots: Charged at $0.05/GB/month

Pricing

Volume Storage: $0.10/GB/month
├─> 10 GB: $1/month
├─> 100 GB: $10/month
└─> 1 TB: $100/month

Snapshots: $0.05/GB/month
├─> 50% of volume cost
└─> Good for backups

No additional charges for:
├─> Attachment/detachment
├─> I/O operations
└─> Data transfer

Documentation Structure

  1. Volumes Overview - This page
  2. Creating Volumes - Setup guide
  3. Managing Volumes - Operations
  4. Kubernetes Volumes - K8s integration

Next Steps

Additional Resources