How to mount app directory as a persistent volume when the app starts?

I have some questions about disk space and usage. I have a sqlite app with a static file database (sqlite) and when I start the app I mount this as a volume to my Docker image.

docker run -v ./data:/mnt my_image

I’m trying to understand how to accomplish this using fly deploy.

First, I’m curious which directory the app files are mounted when I use a Dockerfile in my app deployment. Then I can tell my app in the container to use that volume to start itself.

Second, I’m wondering how much disk space does fly give me in the free tier? My app isn’t big, but I could need a 1GB-2GB of disk storage.

Persistent volumes need to be added separately. You’d need to do something like:

flyctl volumes create <name> --size 10 --region <region>

If you name it data, you can add this to your fly.toml to do the equivalent of your Docker volume:

source = "data"
destination = "/mnt"

Running instances use 5GB volumes, but these do not persist between reboots. You could copy your sqlite file elsewhere periodically and pull it down to the instance at boot time, but it’s not built in.

I added a volume and tried the [mount] clause, but it didn’t work. I think the error message was "/mnt already exists."

The issue isn’t creating or using a volume, but adding the local database to the volume from the commandline. How do I put the sqlite database into a volume without going through the webapp? The webapp needs the file to be there – otherwise it won’t start.

Ah! What kind of app is this?

It’s a little bit of a pain to get data onto a volume for the first time, you’ll need to add it to your Dockerfile, then create a script that copies the file to /mnt if it doesn’t already exist before it starts your app process.

It’s a datasette app. It’s fine to add the db to the image for now, which is what I did, but it limits the functionality because, as you said, the db won’t persist between restarts, and the app will need to be read-only.

So basically, you’re saying the first time I deploy I copy the db to the volume, and the next time I change the ENTRYPOINT and use the volume mount instead. I think that would work. But it’d be great if there was a cleaner solution.

Yes, although you don’t necessarily have to change the entrypoint between deploys. Here is an entrypoint we use to do some extra logic if there are files missing:

You could do that same kind of if block to copy the sqlite file from a temp Docker Image path to the mounted volume path.

Interesting. Yes, that should work.

We should have a better method of getting files into these VMs in the next few weeks, too. This is a pain. :smiley:

I’m having a similar issue with a rails application:

2021-07-15T13:00:41.998834016Z app[4e1687b4] syd [info] Mounting /dev/vdc at /tmp
2021-07-15T13:00:42.036695790Z app[4e1687b4] syd [info] directory /tmp already exists

Is there now a better way to handle this?

Are you trying to mount a volume at /tmp? It’s probably best to mount to a different location, almost every Docker image already has a tmp directory (and we can’t mount over an existing directory).

true, that should be /app/tmp in either case, best to handle this, remove the folder within the docker image?

You can try that with a RUN rm -rf /tmp but I’m not actually sure what it’ll do!

rm: cannot remove ‘/tmp/v8-compile-cache-0/8.4.371.23-node.67/zSoptzSyarn-v1.22.5zSbinzSyarn.js.BLOB’: Permission denied
rm: cannot remove ‘/tmp/v8-compile-cache-0/8.4.371.23-node.67/zSoptzSyarn-v1.22.5zSbinzSyarn.js.MAP’: Permission denied
unfortunately that did not work, could try removing it from my app

Odd, I’ve removed the directory form my app, added it to dockerignore, but I still see this in the logs:

2021-07-15T16:57:12.284426805Z app[b8256dd2] lhr [info] Mounting /dev/vdc at /app/tmp
2021-07-15T16:57:12.287599041Z app[b8256dd2] lhr [info] directory /app/tmp already exists

Is there a way to clear the docker build cache?

If you’re using our remote builder, you can grab the app name and just destroy it: fly apps destroy <name>. We’ll recreate it next time.

If you’re running Docker locally, I think docker system prune will help.

Changed my docker image, added tmp to the docker ignore file, added rm /app/tmp to my docker file, removed the tmp file from my app, but I still see:

directory /app/tmp already exists :thinking:

Thinking about this more it’s probably being created during the asset compilation.

Ideally I would like to mount the public folder or tmp but I could live without for this app, I could just mount a random folder to pin the app to a region

Moving Rails asset compilation out of the docker file, and into an entry point script seems to have solved the issue

1 Like