Containers are meant to immutable and ephemeral. In the ideal scenario the "immutable infrastructure" only re-deploy containers, but never change (unless a new image is created).
But what about databases or unique data?
Fortunately Docker gives us some features to ensure these "separation of concerns" (application vs. data):
Pro-tip: researching the Dockerfile of a database image (like mysql or postgresql) can be a good inspiration, as they probably follow "best-practices".
We can see in the mysql:debian Dockerfile that it creates a VOLUME for /var/lib/mysql.
# let's create a container:
docker container run \
--detach \
--name mysql \
-e MYSQL_ALLOW_EMPTY_PASSWORD=true \
mysql:debian
# check if it's running
docker container ls
# inspecting the container
docker container inspect mysql
# look for Config.Volumes and Mounts
# In the "Mounts", you'll see a property
# with Type: volume. The "Source" is where
# the data is placed in the host OS, and
# the "Destination" is the path inside the
# container.
# list the volumes
docker volume ls
# tip: you'll probably want to do a
# `docker volume prune` sometimes.
# inspecting the volume (use <tab> for autocompletion)
docker volume inspect <tab><tab>
# in the "Mountpoint" you'll see where the
# data lives in the host OS.
Problem: if you create a new container with a new volume, it'll create a volume with a random hash, and it's hard to know which volume is being used by which container.
Solution: named volumes
With named volumes you can delete the container and keep the data and then reuse the data in different containers.
Example:
# let's create a mysql container with
# a named volume 'mysql-db'
docker container run \
--detach \
--name mysql \
-e MYSQL_ALLOW_EMPTY_PASSWORD=true \
-v mysql-db:/var/lib/mysql \
mysql:debian
# inspect the container's Mounts
docker container inspect mysql
# check that it says
# "Source": "/var/lib/docker/volumes/mysql-db/_data"
# delete the container
docker container rm -f mysql
# list the volume and confirm the volume still exists
docker volume ls
# it should list the volume 'mysql-db'
# create a new container using the 'mysql-db' volume
docker container run \
--detach \
--name new-mysql \
-e MYSQL_ALLOW_EMPTY_PASSWORD=true \
-v mysql-db:/var/lib/mysql \
mysql:debian
Note: There are cases where we may want to create the named volume before the docker container run command. For this, use the docker volume create command.
Dockerfile, only in docker container run.