12

I'm trying to build a Dockerfile for a webapp that uses a file-based database. I would like to be able to mount the file from the host* The file is in the root of the complete software install, so it's not really ideal to mount that complete dir.

Another problem is that before the first use, the database-file isn't created yet. A first time user won't have a database, but another user might. I can't 'mount' anything during a build** I believe.

It could probably work like this:

  • First/new database start:
    • Start the container (without mount).
    • The webapp creates a database.
    • Stop the container
  • subsequent starts:
    • Start the container using a -v to mount the file

It would be better if that extra start/stop isn't needed for a user. Even if it is, I'm still looking for a way to do this userfriendly, possibly having 2 'methods' of starting it (maybe I can define a first-boot thing in docker-compose as well as a 'normal' method?).

How can I do this in a simpel way, so that it's clear for any first time users?

* The reason is that you can copy your Dockerfile and the database file as a backup, and be up and running with just those 2 elements.

** How to mount host volumes into docker containers in Dockerfile during build

Community
  • 1
  • 1
Nanne
  • 64,065
  • 16
  • 119
  • 163
  • 2
    Regarding the close vote: Docker is a legit programming tool? I'm not trying to mount a harddisk or use some software, I'm trying to build a good Dockerfile so I can deploy software. Sounds ontopic to me? – Nanne Aug 01 '15 at 19:20
  • Can you specify the DB file path? If so, you could mount a dir which cointains or will contain the DB file and (1) if the file exists, the webapp will use it, or (2) if the file doesn't exist, the webapp (inside the container) will create it and it will be available for next runs. Does that make sense? – Felipe Arenales Aug 01 '15 at 19:22
  • good point, I tried that and it didn't work, forgot to add, sorry. The db-file is in the root of the install path of the software. I'll edit the question :) – Nanne Aug 01 '15 at 19:24
  • Just to be sure, you can't specify another path for the DB file, right? – Felipe Arenales Aug 01 '15 at 19:30
  • No, that's probably a last resort: I'll have to change some code in the base libraries, making it non-compatible with upstream :( – Nanne Aug 01 '15 at 19:31

3 Answers3

2

One approach that may work is:

  • Start the database in the build file in such a way that it has time to create the default file before exiting.
  • Declare a VOLUME in the Dockerfile for the file after the above instruction. This will cause the file to be copied into the volume when a container is started, assuming you don't explicitly provide a host path
  • Use data-containers rather than volumes. So the normal usage would be:

     docker run --name data_con my_db echo "my_db data container"
     docker run -d --volumes-from  data_con my_db
     ...
    

The first container should exit immediately but set up the volume that is used in the second container.

Adrian Mouat
  • 44,585
  • 16
  • 110
  • 102
  • Hmm, thanks! I think I see, sounds reasonable! I'd have to figure out how ease I can copy/backup the file from the container, but that should be doable.. – Nanne Aug 02 '15 at 17:53
  • 1
    @Nanne for backups you could use this specific tool as long as you run Docker on a real host (so not in boot2docker): https://github.com/discordianfish/docker-backup – Henk Aug 02 '15 at 19:00
  • This sounds like the best way, but I'm having some trouble figuring out how to let the app create the databasefile in a ... predictable manner. I'm currently just sleeping a bit after running the daemon, but thats a bit of a hack if you ask me. So currently the first thing is to get the creation-process fixed; for the file-issue this sounds like a very good option though. – Nanne Aug 04 '15 at 06:55
  • Yeah, that is a pain. You might find that waiting a few seconds then sending a SIGSTOP or SIGTERM as opposed to a SIGKILL will work. – Adrian Mouat Aug 04 '15 at 07:59
1

I was trying to achieve something similar and managed to do it by mounting a folder, instead of the file, and creating a symlink in the Dockerfile, initially pointing to a non-existing file:

docker-compose.yml

version: '3.0'

services:
        bash:
                build: .
                volumes:
                        - ./data:/data
                command: ['bash']

Dockerfile

FROM bash:latest

RUN ln -s /data/.bash_history /root/.bash_history

Then you can run the container with:

docker-compose run --rm bash

With this setup, you can push an empty "data" folder into the repository for example (and exclude its content with .gitignore). In the first run, inside the container /root/.bash_history will be a "broken" symlink, pointing to a file that does not exist. When you exit the shell, bash will write the history to /root/.bash_history, which will end up in /data/.bash_history.

Thiago Barcala
  • 6,463
  • 2
  • 20
  • 23
1

This is probably not the correct approach.

If you have multiple containers that are trying to share some information through the file-system, you should probably let them share some directory.

That way, the flow is simple and very hard to get wrong. You simply mount the same directory, say /data (from the host's perspective) into all the containers that are trying to use it.

When an application starts and it can't find anything inside that directory, it can gracefully stop and exit with a code that says: "Cannot start, DB not initialized yet". You can then configure some mechanism with a growing timeout to try and restart that container until you're successful.

On the other hand, the app that creates the DB can start and create it inside the directory or find an existing file to use.

Daniel Trugman
  • 8,186
  • 20
  • 41
  • This has been a long time so I don't know what was the most effective way to fix this, but there weren't multiple containers. There was either a file available for some reason (pre-installed, backup, manual creation, etc) or the app needed to create one. I wanted to have a single way to start either with or without an available file. – Nanne Sep 08 '21 at 11:08