Skip to content

About

πŸ—„οΈ Database images for Drupal with the database captured as container layers.

Topics

Resources

Contributing

Security policy

Stars

7 stars

Watchers

1 watching

Forks

Latest commit

Β 

History

237 Commits

Folders and files

Repository files navigation

Database Data Images logo

Database images for Drupal with the database captured as Docker layers.

GitHub Issues GitHub Pull Requests Test codecov GitHub release (latest by date) LICENSE Renovate

MariaDB Docker Pulls MySQL Docker Pulls amd64 arm64

Vortex Ecosystem

Importing a large Drupal database can take many minutes. Every developer machine and every CI build repeats that import. These images store the database inside the image, so a new container starts with all the data in place.

How it works

Usually, a database server uses a data directory specified as a Docker volume that is mounted onto host: this allows retaining data after container restarts.

The images in this project use custom location /home/db-data (not a Docker volume) to store expanded database files. These files then can be captured as a Docker layer and stored as an image to docker registry.

Image consumers download the image and start containers with instantaneously available data (no time-consuming database imports required).

Technically, the majority of the functionality relies on the upstream Lagoon images:

Supported images

Pick the image that matches the database engine your project runs:

Engine Version Image Seed script Architectures
MariaDB 10.11 drevops/db-data-mariadb-10.11 seed.mariadb.sh linux/amd64, linux/arm64
MySQL 8.4 drevops/db-data-mysql-8.4 seed.mysql.sh linux/amd64, linux/arm64

We release every month. Each release updates both images under the same version tag, and latest points to the newest release. To update, change the tag you use or seed your image again from the newest base image.

Move from drevops/mariadb-drupal-data

The drevops/mariadb-drupal-data image is an exact copy of drevops/db-data-mariadb-10.11, and the seed.sh release asset is an exact copy of seed.mariadb.sh. We publish both copies until 1 March 2027. After that date, the old image's existing tags still pull, but its latest and canary tags stop updating. The releases/latest/download/seed.sh URL then returns a 404.

To stay on MariaDB, replace the old names:

Old name New name
drevops/mariadb-drupal-data drevops/db-data-mariadb-10.11
releases/latest/download/seed.sh releases/latest/download/seed.mariadb.sh
./seed.sh ./seed.mariadb.sh

Your existing data keeps working, because the new image is the same image.

To move to MySQL, seed a new image from a database dump, because MySQL can't open a MariaDB data directory:

curl -LO https://github.com/drevops/database-data-images/releases/latest/download/seed.mysql.sh
chmod +x seed.mysql.sh
./seed.mysql.sh path/to/db.sql myorg/myimage:latest

Use case

Drupal website with a large database.

  1. CI process builds a website overnight.
  2. CI process captures the latest database as a new Docker layer in the database image.
  3. CI process tags and pushes image to the Docker registry.
  4. Website developers pull the latest image from the registry and build site locally. OR Subsequent CI builds pull the latest image from the registry and build site.

When required, website developers restart docker stack locally with an already imported database, which saves a significant amount of time for database imports.

Seeding image with your database

The examples use seed.mysql.sh. For the MariaDB image, use seed.mariadb.sh instead.

  1. Download the seed script for your engine from this repository:
curl -LO https://github.com/drevops/database-data-images/releases/latest/download/seed.mysql.sh
chmod +x seed.mysql.sh
  1. Run the script with the path to your database dump and the image name:
./seed.mysql.sh path/to/db.sql myorg/myimage:latest

# with the destination image from the environment
DESTINATION_IMAGE=myorg/myimage:latest ./seed.mysql.sh path/to/db.sql

# to a registry other than Docker Hub
./seed.mysql.sh path/to/db.sql ghcr.io/myorg/myimage:latest

# with database sanitization using the queries from ./scripts/sanitize.sql
SANITIZE_PROCEED=1 ./seed.mysql.sh path/to/db.sql myorg/myimage:latest

# with forced source platform
DOCKER_DEFAULT_PLATFORM=linux/amd64 ./seed.mysql.sh path/to/db.sql myorg/myimage:latest

# for multi-platform image
DESTINATION_PLATFORMS=linux/amd64,linux/arm64 ./seed.mysql.sh path/to/db.sql myorg/myimage:latest

# with a custom base image (e.g., canary)
BASE_IMAGE=drevops/db-data-mysql-8.4:canary ./seed.mysql.sh path/to/db.sql myorg/myimage:latest

By default, the script builds an image for the host platform (linux/amd64 on Intel hosts, linux/arm64 on Apple Silicon), so importing, building, and the final test stage all run natively on the machine that invokes it. Multi-platform builds are opt-in via DESTINATION_PLATFORMS and require a Docker buildx builder that supports them (Docker Desktop with the containerd image store, or a docker-container builder).

You can also set the destination image in DESTINATION_IMAGE, which takes precedence over the second argument. DST_IMAGE is a deprecated alias for it: the script accepts it with lower precedence than DESTINATION_IMAGE and prints a deprecation notice when it's set.

The destination image can be on any registry, like ghcr.io/myorg/myimage:latest or a local localhost:5000/myorg/myimage:latest. A destination without a tag gets latest. When seeding finishes, the script prints a link to the image's tags on Docker Hub, or the image reference for any other registry.

Note that you should already be logged in to the registry as the seed script will be pushing an image as a part of docker buildx process.

Sanitizing the database

Set SANITIZE_PROCEED=1, and the seed script runs the SQL queries from SANITIZE_FILE against the imported database before it captures the database into the image. It's the place to replace personal data and to empty the tables developers don't need, like logs, sessions and caches:

# with the queries from ./scripts/sanitize.sql
SANITIZE_PROCEED=1 ./seed.mysql.sh path/to/db.sql myorg/myimage:latest

# with the queries from another file
SANITIZE_PROCEED=1 SANITIZE_FILE=path/to/sanitize.sql ./seed.mysql.sh path/to/db.sql myorg/myimage:latest

Sanitization is opt-in. SANITIZE_PROCEED is 0 by default, and only the value 1 turns it on: true or yes leave it off. While it's off, the image holds the database exactly as it was in the dump, and SANITIZE_FILE on its own changes nothing. The script prints which of the 2 it's doing before any work starts, so the CI log always shows what kind of image it pushed:

Sanitization: enabled; the queries from ./scripts/sanitize.sql run before the database is captured.

SANITIZE_FILE defaults to ./scripts/sanitize.sql, relative to the directory you run the seed script from, which is where Vortex projects keep their sanitization queries. If the file doesn't exist, seeding stops before it starts any container.

The queries run with the mysql client against the database the dump was imported into, so table names don't need a database prefix. The client uses utf8mb4, so text with emoji works without a SET NAMES line. If any query fails, seeding stops before the image is built, so a half-sanitized image never reaches the registry.

A file like Vortex's scripts/sanitize.sql works as is. Keep in mind that Vortex runs that file after drush sql:sanitize, while the seed script runs only your queries, so email addresses and passwords stay as they are unless the file changes them:

-- Replace email addresses, so no message can reach a real user.
UPDATE `users_field_data` SET `mail` = CONCAT('user+', `uid`, '@localhost'), `init` = CONCAT('user+', `uid`, '@localhost') WHERE `uid` > 0;

-- Remove sessions.
TRUNCATE TABLE `sessions`;

Why sanitizing takes a second import

MariaDB and MySQL keep recent changes in a redo log, and the redo log is part of the data that the seed script captures. Sanitizing the captured database in place would leave the original values readable in the image. So the seed script imports the dump and runs your queries in a separate container, exports the result, and imports that export into the container it captures, which never holds the original values.

The cost is time: the database is imported twice. The export, .db-sanitized.sql in the working directory, also takes up disk space while seeding runs. The seed script removes it once it's imported or when seeding fails, and won't start if a file already exists at that path, so it never deletes a file it didn't create.

The export carries your databases, not the server's own mysql database, where accounts, grants and time zone data live. If the dump or your queries change them, for example with CREATE USER or GRANT, seeding with sanitization stops before it builds anything, because those changes wouldn't make it into the image. Dumps made with drush sql:dump don't touch the mysql database.

The seed script doesn't change the dump file itself. If the dump mustn't leave production in the first place, sanitize it as you export it, for example with Drush GDPR Dumper or MTK.

Forcing a database upgrade on start

This section applies to the MariaDB image. The MySQL image has no such flag, because the MySQL server upgrades its data directory when it starts.

Containers skip mariadb-upgrade by default, so a container started from a seeded image doesn't check every table before the server comes up. Set MARIADB_FORCE_UPGRADE=1 when you do need the upgrade, for example when the database files came from an older MariaDB server than the one in the image:

docker run -e MARIADB_FORCE_UPGRADE=1 myorg/myimage:latest

The entrypoint then runs mariadb-upgrade --force before the server starts accepting connections. It only does this when the data directory isn't empty, as in a seeded image, so the flag has no effect on a container that's initializing an empty data directory. Only the value 1 turns it on: true or yes leave it off.

FORCE_MYSQL_UPGRADE is a deprecated alias for MARIADB_FORCE_UPGRADE: the entrypoint falls back to it when MARIADB_FORCE_UPGRADE is unset or empty, and prints a deprecation notice whenever it has a value.

Maintenance and releasing

Running tests

Tests run for the host platform by default.

npm --prefix tests/bats ci

# All tests.
tests/bats/node_modules/.bin/bats tests/bats --tap

# Individual test files.
tests/bats/node_modules/.bin/bats tests/bats/image.mariadb.bats --tap
tests/bats/node_modules/.bin/bats tests/bats/image.mysql.bats --tap
tests/bats/node_modules/.bin/bats tests/bats/seed.mariadb.bats --tap
tests/bats/node_modules/.bin/bats tests/bats/seed.mysql.bats --tap
tests/bats/node_modules/.bin/bats tests/bats/seed-surface.bats --tap
tests/bats/node_modules/.bin/bats tests/bats/helper.bats --tap

Versioning

This project uses Year-Month-Patch versioning:

  • YY: Last two digits of the year, e.g., 23 for 2023.
  • m: Numeric month, e.g., April is 4.
  • patch: Patch number for the month, starting at 0.

Example: 23.4.2 indicates the third patch in April 2023.

Versions follow the versions of the upstream MariaDB and MySQL images to ease maintenance.

Releasing

Releases are scheduled to occur at a minimum of once per month.

GitHub Actions builds both images and tags them as follows:

  • YY.m.patch tag - when release tag is published on GitHub.
  • latest - when release tag is published on GitHub.
  • canary - on every push to main branch

GitHub Actions uploads the seed.mariadb.sh and seed.mysql.sh scripts as release assets, so you can download them from the latest release.

Dependencies update

Renovate bot is used to update dependencies. It creates a PR with the changes and automatically merges it if CI passes. These changes are then released as a canary version.

Contributing

See CONTRIBUTING.md for local development setup and the linting and testing commands.

Updating

To pull the latest infrastructure from the template into this project, ask Claude Code to "update scaffold" - see AGENTS.md for details.


This repository was created using the Scaffold project template

About

πŸ—„οΈ Database images for Drupal with the database captured as container layers.

Topics

Resources

Contributing

Security policy

Stars

7 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages