The approach as you've described it will not work reliably. Most application frameworks include some sort of database migration system, and a more robust approach will be to have your application run migrations on startup than to try to use a named volume like this.
Docker named volumes have a subtly tricky sequence for copying content into a volume. When a container is created that mounts the volume, if and only if the volume is totally empty, then content is copied from the mount point into the image. This only happens if the volume is empty (so it will never see changes to the image content), and it only happens for Docker named volumes and not other kinds of mounts (Docker bind mounts, Kubernetes PersistentVolumeClaims, ...).
What this sequence means is that Compose will
- Create the named volume
- Create and start the
db
container, mounting the empty volume
- Create and start the
web
container, at which point Docker will copy the script into the volume
This leads to a race condition where it's not certain whether the web
container startup will copy the file first, or the db
container starts looking through that directory for initialization scripts.
If you extend this setup to use a health check to wait until the database is running, then this won't work at all. The web
container won't be created until the db
container has finished its initialization, which means you have a guarantee that the volume will be empty when the /docker-entrypoint-initdb.d
directory is scanned.
Again, remember that Docker won't ever update the contents of the volume, so if you change the initialization script, the volume will still have the old one. The standard database images also only run /docker-entrypoint-initdb.d
if their data directory is uninitialized. Running a migration system avoids both of these problems.