Docker image for MariaDB + Galera Cluster. Designed for Compose and Swarm, supports arbitrary node startup order, and exposes an HTTP health check for HAProxy.
- Docker Hub:
galeriadb/12.1 - Tag:
latest(image name encodes MariaDB version, e.g.galeriadb/12.1:latest)
Branch main tracks MariaDB 12.1. Older versions are available in versioned branches (e.g. 11.8 for MariaDB 11.8).
- Cluster discovery from
GALERIA_PEERSwith bootstrap candidate logic. - HAProxy-friendly health check on port 9200 (Synced + wsrep_ready=ON).
- Hot backups to S3 with optional retention and cron scheduling.
- Restore (clone) from S3 when the data directory is empty.
From the example Compose stack:
cd examples/docker-compose
docker compose up -dConnect via HAProxy on port 3306:
mariadb -h 127.0.0.1 -P 3306 -u root -psecretThe container exits immediately if any required variable is missing or empty.
| Variable | Description | Example |
|---|---|---|
GALERIA_PEERS |
Comma-separated peer list. Use Compose service names, Swarm task names (tasks.galera), or IPs/hostnames. |
galera1,galera2,galera3 / tasks.galera / 10.0.0.1,10.0.0.2 |
GALERIA_ROOT_PASSWORD |
Password for MariaDB root user (no default). |
secret |
GALERIA_BOOTSTRAP_CANDIDATE |
Hostname of the node that may bootstrap a new cluster when none is found. Must match one of your node hostnames. | galera1 |
| Variable | Description | Default |
|---|---|---|
GALERIA_CLUSTER_NAME |
Galera cluster name (wsrep_cluster_name). |
galera_cluster |
GALERIA_DISCOVERY_TIMEOUT |
Total seconds to resolve peers before continuing. | 5 |
GALERIA_DISCOVERY_INTERVAL |
Seconds between resolution attempts. | 1 |
GALERIA_JOIN_PRIMARY_TIMEOUT |
For non-candidates without an initial Synced peer: seconds to pre-check for a reachable Synced peer before exit (for orchestrator restart). | 30 |
GALERIA_MARIADB_LOGS |
MariaDB/Galera server logs to container stdout/stderr. Set to on to enable; any other value keeps only entrypoint/script logs in docker logs. |
off |
GALERIA_NODE_ADDRESS |
Override this node's IP address if auto-detection is wrong. | auto-detected |
Discovery behavior:
- The image resolves
GALERIA_PEERSand looks for a Synced node. - If a Synced node is found, this node joins it.
- If none is found within the discovery window, only the bootstrap candidate starts a new cluster.
- Non-candidates run a pre-check for up to
GALERIA_JOIN_PRIMARY_TIMEOUT; if no Synced peer appears, they exit so the orchestrator can restart later. - In Swarm or Kubernetes, peer DNS may be empty during the first task start. The discovery window avoids long waits while still allowing late joiners.
The image starts an HTTP listener on port 9200 and returns 200 only when the node is Synced and wsrep_ready=ON.
Optional:
| Variable | Description | Default |
|---|---|---|
GALERIA_HEALTHCHECK_USER |
MySQL user for health check queries. | root |
GALERIA_HEALTHCHECK_PASSWORD |
Password for health check user. | GALERIA_ROOT_PASSWORD |
If both GALERIA_HEALTHCHECK_USER and GALERIA_HEALTHCHECK_PASSWORD are set and the user is not root, the entrypoint will create/update that user and grant the minimal permissions required for the check.
Hot backups run only on nodes in Synced state.
| Variable | Description | Default |
|---|---|---|
GALERIA_BACKUP_SCHEDULE |
Cron schedule for backups. Empty disables cron. | empty |
GALERIA_BACKUP_S3_URI |
Full S3 URI for backups (overrides bucket+path). | — |
GALERIA_BACKUP_S3_BUCKET |
S3 bucket name. | — |
GALERIA_BACKUP_S3_PATH |
Path under bucket if using GALERIA_BACKUP_S3_BUCKET. |
mariadb |
GALERIA_BACKUP_TMPDIR |
Temporary directory for backups. | /tmp |
GALERIA_BACKUP_RETENTION_DAYS |
Delete backups older than this many days (by S3 LastModified). | — |
GALERIA_BACKUP_RETENTION_CUTOFF_OVERRIDE |
Override retention cutoff date (YYYY-MM-DD). Useful for tests. | — |
GALERIA_CRONTAB |
Additional cron lines to install alongside backups. | — |
AWS_ACCESS_KEY_ID |
AWS access key (optional if using IAM role). | — |
AWS_SECRET_ACCESS_KEY |
AWS secret key. | — |
AWS_REGION / AWS_DEFAULT_REGION |
AWS region for S3. | — |
AWS_ENDPOINT_URL |
Custom S3 endpoint (e.g. MinIO). | — |
Manual backup:
docker exec <container> /usr/local/bin/galera-backup.shBackup logs are written to /var/log/galera-backup.log inside the container.
Restore runs only when /var/lib/mysql is empty on container startup and clone variables are set.
| Variable | Description | Default |
|---|---|---|
GALERIA_CLONE_BACKUP_S3_URI |
Full S3 URI for restore (overrides bucket+path). | — |
GALERIA_CLONE_BACKUP_S3_BUCKET |
S3 bucket name. | — |
GALERIA_CLONE_BACKUP_S3_PATH |
Path under bucket if using GALERIA_CLONE_BACKUP_S3_BUCKET. |
mariadb |
GALERIA_CLONE_FROM |
Object key relative to base path or full s3:// URI. If unset, the latest backup under {hostname}/ is used. |
— |
GALERIA_CLONE_TMPDIR |
Temporary directory for restore files. | /tmp |
CLONE_AWS_ACCESS_KEY_ID |
AWS access key for restore. | — |
CLONE_AWS_SECRET_ACCESS_KEY |
AWS secret key for restore. | — |
CLONE_AWS_REGION / CLONE_AWS_DEFAULT_REGION |
AWS region for restore. | — |
CLONE_AWS_ENDPOINT_URL |
Custom S3 endpoint (e.g. MinIO). | — |
root@%is created on startup and granted full privileges.- If the node is the bootstrap candidate,
safe_to_bootstrapis set to 1 ingrastate.datwhen needed. - If the data directory was created by an older MariaDB version, the container runs
mariadb-upgradeon startup.
When a version upgrade is detected, the entrypoint runs mariadb-upgrade automatically. If S3 backup settings are configured, a hot backup is taken and uploaded before the migration runs. If backup is configured but the pre-upgrade backup fails or the node does not reach Synced within the timeout, the container exits and migration is not performed.
Optional:
| Variable | Description | Default |
|---|---|---|
GALERIA_AUTO_MIGRATE_SYNC_TIMEOUT |
Seconds to wait for Synced + wsrep_ready=ON before taking the pre-upgrade backup. |
120 |
- 3306 - MariaDB clients
- 4567 - Galera replication
- 4568 - IST
- 4444 - SST
- 9200 - HTTP health check
docker build -t galeriadb/12.1:latest -f docker/Dockerfile docker/Single entry point:
make ciRun inside the dev container (no local toolchain required):
make ci-dockermake ci-docker runs make ci from sources baked into the dev image at /workspace and uses Docker socket passthrough (/var/run/docker.sock or path from DOCKER_HOST=unix://...).
Diagnostics from /workspace/artifacts are copied back to local ./artifacts/ after the run.
Targets:
| Command | Description |
|---|---|
make ci |
lint, build, CST, security, smoke, deploy, backup-s3 |
make ci-docker |
same as make ci inside dev container |
make lint |
hadolint, shellcheck, shfmt |
make build |
build image (galeriadb/12.1:local) |
make cst |
Container Structure Tests |
make security |
Trivy rootfs scan (CRITICAL) + Dockle image scan |
make smoke |
required env validation, single-node startup, graceful shutdown, Docker HEALTHCHECK |
make deploy |
3-node Galera + HAProxy scenarios |
make backup-s3 |
S3 backup tests (MinIO) |
make swarm |
Swarm sanity (run after make ci) |
Tests live in tests/00.* through tests/05.*. Each test directory has its own entrypoint.sh. Diagnostics are written to ./artifacts/ on failure.
GitHub Actions runs make ci in a dev container on pull requests to the main branch and on manual runs. The Swarm job runs on the same triggers after CI passes (unless [skip-ci] is set).
Images are built and published via .github/workflows/docker-publish.yml on push to main and on manual runs (skips when [skip-ci] is in the head commit message). Required secrets: DOCKER_USERNAME, DOCKER_PASSWORD.
docker/- Dockerfile, entrypoint, entrypoint stages, backup/clone scripts, templates.tests/- CI and local test suite.examples/docker-compose/- local Compose stack (3 nodes + HAProxy).examples/docker-swarm/- Swarm stack and docs.
This repository is licensed under the MIT License. The image includes third-party software (MariaDB, Galera, socat, etc.) under their own licenses; see NOTICE for details.