Configuring Docker Volumes for Persistent Data Storage

Containers are ephemeral: upon restart, data inside can be irretrievably lost. We configure Docker Volumes and persistent storage to keep your databases and files safe. Our team delivers a turnkey project—from audit to implementation—ensuring reliable operation and ongoing support.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Configuring Docker Volumes for Persistent Data Storage

Containers are ephemeral by nature—when you run docker rm, everything inside disappears. For databases, uploads, logs, and configs this means data loss on every restart. Docker Volumes solve this, but misconfiguration leads to two opposite problems: data still gets lost, or volumes grow uncontrollably and fill the host disk. In our practice, we had a case: after docker compose down && up on a PostgreSQL project, we lost 300 GB of data—anonymous volumes were not removed, new ones were created over old ones, and data became inaccessible. In this article, we break down how to set up reliable persistent storage and avoid typical mistakes. Our engineers with 5+ years of DevOps experience guarantee that after setup your volumes will work like clockwork. Request a volume audit—we will show where the risks are hidden.

Three Mount Types—Where Each Fits

Named volumes are the primary tool for production. Docker manages their location on the host (/var/lib/docker/volumes/), and you can use drivers for NFS, S3, Ceph. They are portable between environments via docker volume create.

Bind mounts attach a specific host path. Convenient for development (hot reload of code), dangerous in production: If the path is wrong, the container gets an empty directory or wrong content, which is not always obvious from logs.

tmpfs mounts are only in memory, not written to disk. For secrets, temporary files, cache that does not need to survive restart.

Type Purpose Backup Performance
Named volume Production, databases, files Simple via temporary container Native, with driver possibilities
Bind mount Development, configs, logs Manual copy from host Direct disk access
tmpfs mount Secrets, cache, temp data Not required (in-memory) Highest (in-memory)

Why Named Volumes Are Better Than Bind Mounts

Bind mounts in production are a frequent cause of incidents. According to our practice statistics, 90% of storage problems in Docker are related to bind mounts. Imagine: during deployment you accidentally mount an empty directory, and the application writes data there. After restart, real data ends up elsewhere, and garbage is in the mounted directory. With named volumes this does not happen: Docker creates the directory and controls its contents. Also, named volumes are easy to back up and move between servers using drivers. Volume storage optimization can save up to 40% of disk space through deduplication and proper rotation.

How to Configure Named Volumes in Compose

services:
  postgres:
    image: postgres:16
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: app
  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes --appendfsync everysec
  minio:
    image: minio/minio:latest
    volumes:
      - minio_data:/data
    command: server /data --console-address ":9001"
volumes:
  postgres_data:
    driver: local
  redis_data:
    driver: local
  minio_data:
    driver: local

Explicit declaration of volumes in the volumes: section is mandatory—without it, Compose creates an anonymous volume with a random hash name, which accumulates on every docker compose down && up and is not removed without docker volume prune. Each such anonymous volume can take up several gigabytes, and with dozens of them, disk fills with garbage.

Backing Up Named Volumes (Step by Step)

  1. Create a dump of the database through the running container: docker exec postgres_container pg_dump -U app myapp | gzip > backup_$(date +%Y%m%d).sql.gz
  2. For binary data, use a temporary container with read-only mount:
    docker run --rm \
     -v postgres_data:/source:ro \
     -v /backup:/dest \
     alpine tar czf /dest/postgres_data_$(date +%Y%m%d).tar.gz -C /source .

    Mounting with :ro (read-only) during backup is a good practice: accidental writes to source will not corrupt data.

    How to Use NFS for Shared Storage

    For multi-host environments (Docker Swarm, multiple servers), local volumes do not work—data is tied to a specific node. The solution is an NFS volume driver or specialized plugins.

    ---
    volumes:
      shared_uploads:
        driver: local
        driver_opts:
          type: nfs
          o: "addr=nfs-server.internal,rw,nfsvers=4"
          device: ":/exports/uploads"

    For AWS, EFS mounts to multiple EC2 instances simultaneously, unlike EBS. If you use the cloud, we help configure the optimal storage driver for your infrastructure.

    How to Solve Permission Issues

    The most common problem with volumes in production: the container runs under an unprivileged user, but the volume is created with root permissions. The result: Permission denied on the first write.

    # In Dockerfile, explicitly create the directory with correct permissions BEFORE declaring VOLUME
    RUN mkdir -p /app/data && chown -R appuser:appuser /app/data
    USER appuser

    Or on first run:

    services: app: user: "1001:1001" volumes: - app_data:/app/data volumes: app_data: driver: local 

    docker volume inspect app_data will show Mountpoint on the host—there you can manually fix permissions if something went wrong. As part of setup, we always check UID/GID and adjust rights if needed. In 80% of cases, the error is resolved in 5 minutes.

    Typical Volume Configuration Mistakes

    • Anonymous volumes in Compose—use named ones.
    • Missing user: in docker-compose—root rights inside container.
    • Forgetting :ro during backup—risk of data modification.
    • NFS version below 4—issues with locks.
    • No backup rotation—disk fills up in a week.

    What Is Included in End-to-End Volume Setup

    • Current volume audit: inventory of all volumes, types, data criticality, backup status.
    • Migration of anonymous volumes to named with explicit naming.
    • Driver configuration tailored to your infrastructure: local, NFS, cloud (AWS EFS, Azure Files).
    • Permission configuration for each volume considering the container user.
    • Backup strategy: automation via cron or CI/CD, archive rotation.
    • Restoration documentation: runbook with instructions for on-call team.
    • Team training: how to add new volumes, how to check status.

    After completion, you receive a transparent storage scheme with a guarantee that volumes will not be lost on restart and will not clog the disk.

    Scope of Work Estimated Time Typical Cost
    Compose stack cleanup 4–8 hours $500–$1,500
    NFS or cloud volume driver 1–2 days $1,000–$3,000
    Swarm + multi-host shared storage 2–3 days $2,500–$6,000

    The cost is calculated individually after auditing your current data and storage infrastructure. Our team has 10+ years of containerization experience and over 100 successful projects, ensuring a reliable outcome. Contact us to evaluate your project and get a consultation from a certified DevOps engineer. Request an audit of your Docker volumes—we will show where the risks are stored and how to eliminate them. Over 50 successful projects—your guarantee of reliability.