How to Deal with Docker Container Persistence and Storage

Docker logo.

Docker is a containerization service, designed to run applications in their own environment on any system. It is designed to be platform independent, but if you need to store data on a disk it can be done with volume and link mounts.

Use an external database or object store

This is the method that most people will recommend. Storing state as a file on disk does not conform to Docker’s model, and while it can be done, it is always best to be aware of this. Do you really need it?

For example, suppose you are running a web application in Docker that needs to store data in a database. It doesn’t make much sense to run MySQL in a Docker container, so you should instead deploy MySQL to RDS or EC2 and the Docker container connects directly to it. The Docker container is completely stateless as it is supposed to be; it can be stopped, started, or hit with a hammer, and a new one can be turned in its place, all without loss of data. Using IAM permissions, this can be accomplished securely, entirely in your VPC.

If you really need to store files, such as user uploaded photos and videos, you should definitely use AWS Simple storage service (S3). It’s much cheaper than EBS-based storage, and far cheaper than EFS storage, which is your first choice for a shared file system for ECS containers. Rather than storing a file on disk, you upload directly to S3. This method also allows you to run additional processing using Lambda functions on downloaded content, like compressing images or videos, which can save you a lot on bandwidth costs.

Simple solution: mount a drive on a container

Docker offers two methods to achieve persistence: volume mounts and link mounts. Link mounts allow you to mount a particular location on your server’s file system to a location inside the Docker container. This link can be read-only, but also read / write, where files written by the Docker container will persist on disk.

You can link individual host directories to target directories in the Docker container, which is useful, but the recommended way is to create a new “volume”, managed by Docker. This makes it easier to back up, transfer, and share volumes between different container instances.

A word of warning: If you don’t have direct access to the server you’re running Docker on, as with managed deployments like Elastic Container Service (ECS) from AWS and Kubernetes, you need to be careful with this. It is tied to the server’s disk space, which is usually ephemeral. You’ll want to use an external file store like EFS to achieve true persistence with ECS (more on that later).

However, link and volume mounts work well if you’re just using Docker to run an easy install of an app on your server, or if you just want fast persistence for testing. Either way, the method of creating volumes will be the same regardless of where you store them.

You can create a new volume from the command line with:

docker volume create nginx-config

And then when you go to run your Docker container, link it to the target in the container with the --mount flag:

docker run -d 
--name devtest 
--mount source=nginx-config,target=/etc/nginx 
nginx:latest

If you run docker inspect , you will see the volume listed under Mounts section.

If you’re using Docker Compose, setup is also straightforward. Just add a volumes for each container service you have, and then map a volume name to a location in the guest. You will also need to provide a list of volumes at a higher level volumes key for Compose to provision.

version: "3.0"
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - nginx-config:/etc/nginx/
volumes:
  nginx-config:

This will automatically create the volume for this Compose. If you want to use a predefined volume outside of Compose, specify external: true in the volume configuration:

volumes:
  cms-content:
    external: true

If you just want to perform a link mount and not worry about volumes, just enter a path name instead of the volume name and leave the volume names blank.

version: "3.0"
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - /docker/nginx-config/:/etc/nginx/

You can read Complete Docker documentation on using volumes with Compose if your use case requires something more specific than that.

For managed deployments, use a shared file system (AWS EFS)

If you are deploying to AWS ECS, you won’t be able to use a normal link or volume mount, because after you stop the container, you probably won’t be running on the same machine the next time you restart it. , which defeats the purpose of perseverance.

However, you can still achieve persistence using another AWS service: Elastic File System (EFS). EFS is a shared network file system. You can mount it on multiple EC2 servers and the accessed data will be synchronized on all of them. For example, you can use it to host static content and code for your website, and then run all your worker nodes on ECS to handle the actual delivery of your content. This circumvents the restriction of not storing data on disk because the volume mount is tied to an external drive that persists in ECS deployments.

To configure this, you need to create an EFS file system. This is quite simple and can be done from the EFS Management Console, but you will want to write down the volume identifier, as you will need it to work with the volume.

If you need to manually add or modify files in your EFS volume, you can mount it on any EC2 instance. You will need to install amazon-efs-utils:

sudo yum install -y amazon-efs-utils

And then mount it with the following command, using the id:

sudo mount -t efs fs-12345678:/ /mnt/efs

This way you can directly view and edit the contents of your EFS volume as if it were another hard drive on your server. You will want to make sure that you have nfs-utils installed for it to work properly.

Then you will need to connect ECS to this volume. Create a new task definition in the ECS management console. Scroll down and select “Configure via JSON”. Then replace the empty “volumes” key with the following JSON, adding the “family” key at the end:

"volumes": [
        {
            "name": "efs-demo",
            "host": null,
            "dockerVolumeConfiguration": {
                "autoprovision": true,
                "labels": null,
                "scope": "shared",
                "driver": "local",
                "driverOpts": {
                    "type": "nfs",
                    "device": ":/",
                    "o": "addr=fs-XXXXXX.efs.us-east-1.amazonaws.com,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport"
                }
            }
        }
    ],
"family":"nginx",

Replace fs-XXXXXX.efs.us-east-1.amazonaws.com with the actual address of your EFS volume. You should see a new volume:

DHW new volume

You can use it in your container definition as a mount point. Select “Add container” (or modify an existing one), and under “Storage and logging” select the newly created volume and specify a container path.

add a mount point

Save the task definition and when you launch a cluster with this new definition, all containers will be able to access your shared file system.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.