Docker compose:
version: "3"
services:
db:
container_name: db
image: mysql
ports:
- "3306:3306"
volumes:
- initdb:/docker-entrypoint-initdb.d/:ro
web:
container_name: web
image: my_web
volumes:
- initdb:/initdb/:ro
depends_on:
- db
volumes:
initdb:
my_web image contains /initdb/create_schema.sql.
web depends on db. So the service db will start before web. Will the create_schema.sql from web be available for the db to consume?
From testing, it is available. Is this guaranteed or by random?
The create_schema.sql is generated when building my_web image. It is not on host disk.
Trying to understand when volumes are created and mapped to containers. If they are created and mapped before starting all containers, then the shared data via volumes will be guaranteed to be available.
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
db
container, mounting the empty volumeweb
container, at which point Docker will copy the script into the volumeThis 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.