Docker containers are designed to be ephemeral - once stopped or removed, any data stored inside is lost.
Let’s take a quick CLI tour to see just how ephemeral Docker containers really are.
# Run a container
# -w is to specify the working directory
$ docker run -it -w /app ubuntu:24.04 bash
# Once inside the container, create a file
$ root@kecapabc:/app# echo "Hello" > hello.txt
# Exit the container with `ctrl + d`
# Run the container again
$ docker run -it -w /app ubuntu:24.04 bash
# Oops, the file is not there
root@kecapabc:/app# ls
This stateless nature works well for many use cases, but for applications like databases or web apps often we need to persist data across restarts and rebuilds. Docker solves this with volumes and mounts.
In this blog post, we'll explore how Docker handles data persistence and how to seamlessly set it up for your web application development.
To volume is to use a persistent storage outside the container, so data stored in a volume remains outside the container even if the container is deleted.
Here's a quick CLI tour of using volumes with Docker.
# Create a docker volume
$ docker volume create myvolume
# Check the volume
$ docker volume ls
# Run the container with the volume
# -it is to run in interactive mode
# -w is to specify the working directory
# -v is to mount the volume
$ docker run -it -w /app -v myvolume:/app ubuntu:24.04 bash
# Once inside the container, create a file
$ root@kecapabc:/app# echo "Hello" > hello.txt
# Exit the container with `ctrl + d`
# Run the container again
$ docker run -it -w /app -v myvolume:/app ubuntu:24.04 bash
# Voila, the file is still there
$ root@kecapabc:/app# cat hello.txt
Here are a few essential commands to help you manage Docker volumes effectively:
# List all volumes
$ docker volume ls
# Inspect a volume
$ docker volume inspect <volume-name>
# Remove a volume
$ docker volume rm <volume-name>
# Clean up unused data in your Docker environment
$ docker system prune
To bind mount is to link a specific file or directory from your host machine directly into the container. With such link, changes made in either place are reflected instantly in the other.
$ docker run -v /host/path:/container/path ubuntu:24.04
Thanks to its data persistence and virtualization features, Docker makes web development more portable and hassle-free.
Here's a docker-compose.yml
for Django development that leverages Docker volumes and bind mounts.
services:
web:
build: .
command: python /code/manage.py runserver 0.0.0.0:8000
volumes:
# Bind mount
- .:/code
ports:
- 8000:8000
depends_on:
- db
db:
image: postgres:17
volumes:
# Use volume
- postgres_data:/var/lib/postgresql/data/
environment:
- "POSTGRES_HOST_AUTH_METHOD=trust"
volumes:
postgres_data:
Use Case | Mount Type | Example in Compose | When to Use |
---|---|---|---|
Code live reload | Bind mount | - .:/code |
Development |
DB persistence | Volume | - postgres_data:/var/lib/postgresql/data/ |
Databases data |
To make data persistent in Docker, use volumes for databases and bind mounts for live code during development. With Docker Compose, managing both becomes simple — ideal for developing web applications like those built with Django.