This flow will spin up a Postgresql database and apply migrations to it using raw SQL commands, this is simliar to my Docker Compose Demo but the raw SQL resides with the code and the baseline command is auto-magic💕 This is useful for applying migrations locally.
The code I use in this post can be found at https://github.com/carlpaton/flyway-migration-demo/tree/main
Disclaimer: I personally think a Model First approach like EF Core is easier but there is merit in knowing more than one way to do db migrations.
Define Raw SQL
Migrations
Flyway has a naming pattern that we need to follow, for simplicity I just used an existing example in my public github
Initialization Scripts
This is useful to create users
, schemas
, set roles
ect and is auto-magically run though a docker volumn mapped to docker-entrypoint-initdb.d
, this script will only run the first time the container started as it checks the data directory. Also see hub.docker.com - postgres
I called my file initialize-database.sql, its sensible to have users with different access level, the application user should not have elevated access like this, it should only be allowed to do what the application does, normally just CRUD stuff.
1 | CREATE USER demo_schema_manager WITH PASSWORD 'password'; |
Define Compose File
This needs to run services demo-db
, demo-db-migration
and demo-pgadmin
demo-db
1 | demo-db: |
demo-db-migration
1 | demo-db-migration: |
demo-pgadmin
pgadmin4-server-file.json just imports my server configuration, you can take out the env PGADMIN_SERVER_JSON_FILE
if you just want to use the UI to define your own.
1 | demo-pgadmin: |
Run The Migrations Locally
You can just clone flyway-migration-demo or copy the examples above but I encourage you to type it out, think about what you actually typing, you will learn more this way.
- Save the files as
- migrations in
C:\dev\flyway-migration-demo\migrations
- initialize file in the root
C:\dev\flyway-migration-demo\initialize-database.sql
- - compose file in the root
C:\dev\flyway-migration-demo\docker-compose.yml
- migrations in
- Run
docker compose up --wait
(docker desktop may ask for permissions to share the files to the volumns) - Wait for compose to confirm the services are healthy
- Wait a few seconds for pgAdmin to load the servers and then navigate to http://localhost:5050/browser/
- The login is
user@domain.com
and password ispostgres
- The server will need a password, its
postgres
because we are using the administrator user
- The login is
You could also install pgAdmin locally if you dont want to use the container.
- Check the migrations have been applied
- (OPTIONAL) To tear down the containers run
docker compose down
Future Migrations
Tear Down Approach
- Locally add a new migration, example migrations-new/V1.0.3__fizzbuzz_data2.sql
- This needs to be added to the
migrations
folder with the v101 and v102 files
- This needs to be added to the
- Tear down the stack with
docker compose down
- Run
docker compose up --wait
and follow the steps above to see the applied migrations
Rolling Forward
You may care about your local test data that was not auto-magically seeded or you want to test the new migration the same way it would be applied in Production you can use most of the above and run the info
command in another short lived container.
- Use a new container to connect to the db and run the
flyway info
command. It would be sensible to add this command to a make file, alternatively you can use the Flyway CLI locally and store the configuration as TOML.
1 | docker run --rm --name flyway-manual-commands flyway/flyway:11 -user=demo_schema_manager -password=password -url=jdbc:postgresql://host.docker.internal:5432/demo_db -defaultSchema=demo info |
Expected output below, as we only checking flyways info
command the WARNING
doesnt matter.
1 | WARNING: No locations configured and default location 'sql' not found. |
This is the same data as checking demo.flyway_schema_history
but I think the info
command is cool and helps understand the possible CLI commands.
Copy the new migration into the
migrations
folder, same example as migrations-new/V1.0.3__fizzbuzz_data2.sqlRun the
MIGRATE
command using the existing compose container
1 | docker compose up demo-db-migration |
Expected output
1 | [+] Running 2/0 |
Running the
INFO
command again should then show version1.0.3.
Check the migrations have been applied, feels repetitive … but I do what I want ( ͡° ͜ʖ ͡°)
Next steps would be to apply the migration in a CICD pipeline, Github Actions is the cool kid on the block right?