|
All checks were successful
Build and Test MariaDB Backup Images / Load Configuration (push) Successful in 3s
Build and Test MariaDB Distroless Images / Load Configuration (push) Successful in 3s
Build and Test MariaDB Backup Images / Build Backup (MariaDB 12) (push) Successful in 1m37s
Build and Test MariaDB Backup Images / Build Backup (MariaDB 11) (push) Successful in 1m39s
Build and Test MariaDB Distroless Images / Build (MariaDB 11) (push) Successful in 56s
Build and Test MariaDB Distroless Images / Build (MariaDB 12) (push) Successful in 57s
Build and Test MariaDB Backup Images / Backup Tests (MariaDB 11) (push) Successful in 44s
Build and Test MariaDB Backup Images / Backup Tests (MariaDB 12) (push) Successful in 45s
Build and Test MariaDB Distroless Images / Functional Tests (MariaDB 11) (push) Successful in 1m14s
Build and Test MariaDB Distroless Images / Functional Tests (MariaDB 12) (push) Successful in 1m14s
Build and Test MariaDB Backup Images / Security Scan (MariaDB 11) (push) Successful in 48s
Build and Test MariaDB Backup Images / Security Scan (MariaDB 12) (push) Successful in 46s
Build and Test MariaDB Backup Images / Compliance Scan (MariaDB 11) (push) Successful in 12s
Build and Test MariaDB Backup Images / Compliance Scan (MariaDB 12) (push) Successful in 10s
Build and Test MariaDB Distroless Images / Security Scan (MariaDB 11) (push) Successful in 47s
Build and Test MariaDB Distroless Images / Security Scan (MariaDB 12) (push) Successful in 47s
Build and Test MariaDB Distroless Images / Compliance Scan (MariaDB 11) (push) Successful in 12s
Build and Test MariaDB Distroless Images / Compliance Scan (MariaDB 12) (push) Successful in 11s
Build and Test MariaDB Backup Images / Push Backup (MariaDB 11) (push) Successful in 7s
Build and Test MariaDB Backup Images / Push Backup (MariaDB 12) (push) Successful in 6s
Build and Test MariaDB Distroless Images / Push (MariaDB 11) (push) Successful in 7s
Build and Test MariaDB Distroless Images / Push (MariaDB 12) (push) Successful in 7s
Build and Test MariaDB Backup Images / Tag Backup Latest (push) Successful in 7s
Build and Test MariaDB Distroless Images / Tag Latest (push) Successful in 7s
Build and Test MariaDB Distroless Images / Cleanup (push) Successful in 1s
- show retention policy and backup count at start - log each backup with KEEP/DELETE and reason - show which retention rule matched (keep_last, hourly, daily, etc.) - display count progress (e.g., "keep_last (3/10)") |
||
|---|---|---|
| .github/workflows | ||
| backup-sidecar | ||
| examples | ||
| mariadb | ||
| mariadb-backup | ||
| mariadb-entrypoint | ||
| .gitignore | ||
| .metadata.json | ||
| LICENSE | ||
| README.md | ||
| SECURITY.md | ||
| test-backup.sh | ||
MariaDB Distroless
Minimal, secure MariaDB container images based on Google's distroless base.
Features
- Minimal footprint: ~80MB per image (vs ~400MB for official mariadb)
- Multi-architecture: linux/amd64 and linux/arm64
- Distroless base: No shell, no package manager, reduced attack surface
- Multiple versions: MariaDB 11 and 12
- Security-first: Runs as non-root (UID 65532), binaries owned by root
- TLS support: Auto-detection of SSL certificates
- Docker secrets: Support for
_FILEsuffix environment variables
Quick Start
# Basic usage
docker run -d \
-e MARIADB_ROOT_PASSWORD=mysecretpassword \
-p 3306:3306 \
git.breis.ch/images/mariadb:12
# With persistent data
docker run -d \
-e MARIADB_ROOT_PASSWORD=mysecretpassword \
-v mariadb-data:/var/lib/mysql \
-p 3306:3306 \
git.breis.ch/images/mariadb:12
Available Tags
| Tag | MariaDB Version | Notes |
|---|---|---|
12, latest |
12.1.x | Latest stable |
11 |
11.8.x | LTS (until 2028) |
Environment Variables
| Variable | Default | Description |
|---|---|---|
MARIADB_ROOT_PASSWORD |
(required*) | Root password |
MARIADB_DATABASE |
- | Create database on init |
MARIADB_USER |
- | Create user on init |
MARIADB_PASSWORD |
- | Password for MARIADB_USER |
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD |
- | Set to yes to allow empty root password |
MARIADB_RANDOM_ROOT_PASSWORD |
- | Set to yes to generate random password |
MARIADB_AUTO_UPGRADE |
- | Set to yes to auto-upgrade on version change |
DATADIR |
/var/lib/mysql/{version}/data |
Data directory |
*One of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD, or MARIADB_RANDOM_ROOT_PASSWORD is required.
Performance & Limits
| Variable | Default | Description |
|---|---|---|
MARIADB_MAX_CONNECTIONS |
151 |
Maximum concurrent connections |
MARIADB_STATEMENT_TIMEOUT |
- | Query timeout (e.g., 30, 300) |
MARIADB_INNODB_BUFFER_POOL_SIZE |
128M |
InnoDB buffer pool size |
Logging
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
info |
Log level for entrypoint and MariaDB: error, warn, info, debug |
The log level controls both entrypoint verbosity and MariaDB's log_warnings setting.
Security & Audit
| Variable | Default | Description |
|---|---|---|
MARIADB_LOG_CONNECTIONS |
on |
Log connection attempts |
MARIADB_LOG_DISCONNECTIONS |
on |
Log disconnections |
Docker Secrets
All MARIADB_* variables support the _FILE suffix for Docker secrets:
docker run -d \
-e MARIADB_ROOT_PASSWORD_FILE=/run/secrets/db_password \
-v /path/to/secrets:/run/secrets:ro \
git.breis.ch/images/mariadb:12
TLS/SSL Configuration
SSL certificates are read from /var/lib/mysql/ssl/. You can provide them via environment variables or volume mounts.
Option 1: Environment Variables / Docker Secrets
Pass certificates directly via environment variables or use _FILE suffix for secrets:
# Direct environment variables
docker run -d \
-e MARIADB_ROOT_PASSWORD=mysecretpassword \
-e MARIADB_SSL_CERT="$(cat server-cert.pem)" \
-e MARIADB_SSL_KEY="$(cat server-key.pem)" \
-e MARIADB_SSL_CA="$(cat ca.pem)" \
-p 3306:3306 \
git.breis.ch/images/mariadb:12
# Docker secrets (with _FILE suffix)
docker run -d \
-e MARIADB_ROOT_PASSWORD_FILE=/run/secrets/db_password \
-e MARIADB_SSL_CERT_FILE=/run/secrets/ssl_cert \
-e MARIADB_SSL_KEY_FILE=/run/secrets/ssl_key \
-v /path/to/secrets:/run/secrets:ro \
-p 3306:3306 \
git.breis.ch/images/mariadb:12
Option 2: Volume Mounts
Mount certificates to /var/lib/mysql/ssl/:
docker run -d \
-e MARIADB_ROOT_PASSWORD=mysecretpassword \
-v $(pwd)/ca.pem:/var/lib/mysql/ssl/ca.pem:ro \
-v $(pwd)/server-cert.pem:/var/lib/mysql/ssl/server-cert.pem:ro \
-v $(pwd)/server-key.pem:/var/lib/mysql/ssl/server-key.pem:ro \
-p 3306:3306 \
git.breis.ch/images/mariadb:12
SSL Environment Variables
| Variable | Default | Description |
|---|---|---|
MARIADB_SSL_CERT |
- | Server certificate (PEM content) |
MARIADB_SSL_KEY |
- | Server private key (PEM content) |
MARIADB_SSL_CA |
- | CA certificate (PEM content, optional) |
MARIADB_SSL |
off |
Set to on to warn if certs not found |
MARIADB_SSL_REQUIRE |
off |
Set to on to require SSL for all connections |
All variables support the _FILE suffix for Docker secrets.
When MARIADB_SSL_REQUIRE=on, all connections must use SSL (require_secure_transport=ON).
Generate Test Certificates
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 365 -key ca-key.pem -out ca.pem -subj "/CN=MariaDB-CA"
openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-req.pem -subj "/CN=mariadb"
openssl x509 -req -in server-req.pem -days 365 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
TLS Hardening
When SSL is enabled, the following hardening is applied automatically:
tls_version = TLSv1.2,TLSv1.3ssl_cipher = HIGH:!aNULL:!MD5:!3DES:!RC4
Security
File Ownership
| Path | Owner | Permissions |
|---|---|---|
/usr/bin/mariadb* |
root | Execute only |
/usr/lib/mariadb/* |
root | Read only |
/var/lib/mysql/* |
65532 (nonroot) | Read/Write |
/var/run/mysqld/ |
65532 (nonroot) | Read/Write |
The MariaDB process cannot modify its own binaries.
Default Hardening
The image applies these security settings by default:
[mysqld]
local_infile=0
symbolic-links=0
skip-name-resolve
log_warnings=2
Runtime Hardening (Recommended)
For maximum security, run with these Docker flags:
docker run -d \
--read-only \
--tmpfs /tmp:uid=65532,gid=65532 \
--tmpfs /var/run/mysqld:uid=65532,gid=65532 \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
-e MARIADB_ROOT_PASSWORD=mysecretpassword \
-v mariadb-data:/var/lib/mysql/12/data \
-p 3306:3306 \
git.breis.ch/images/mariadb:12
Note
: The tmpfs mounts require
uid=65532,gid=65532to match the nonroot user. The volume must be mounted directly to/var/lib/mysql/{version}/datato avoid directory creation issues with--read-only.
| Flag | Purpose |
|---|---|
--read-only |
Immutable root filesystem |
--tmpfs /tmp:uid=65532,gid=65532 |
Writable temp directory (nonroot user) |
--tmpfs /var/run/mysqld:uid=65532,gid=65532 |
Writable socket directory (nonroot user) |
--cap-drop=ALL |
Drop all Linux capabilities |
--security-opt=no-new-privileges |
Prevent privilege escalation |
For Kubernetes, use equivalent securityContext:
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
runAsNonRoot: true
runAsUser: 65532
Volumes
| Path | Description |
|---|---|
/var/lib/mysql |
Data directory (mount for persistence) |
/var/run/mysqld |
Unix socket directory |
Ports
| Port | Description |
|---|---|
| 3306 | MariaDB |
Healthcheck
The image includes a built-in healthcheck using mariadb-admin ping. Since this is a distroless image without a shell, the healthcheck uses the entrypoint with the --health-check flag:
HEALTHCHECK CMD ["/entrypoint", "--health-check"]
The healthcheck uses MARIADB_USER and MARIADB_PASSWORD environment variables for authentication. Make sure these are set for the healthcheck to work properly.
To check the health status:
docker inspect --format='{{.State.Health.Status}}' container_name
You can also run the healthcheck manually:
docker exec container_name /entrypoint --health-check && echo "Healthy" || echo "Unhealthy"
Upgrading
When upgrading between major versions (e.g., 11 to 12), set MARIADB_AUTO_UPGRADE=yes to automatically run mariadb-upgrade:
docker run -d \
-e MARIADB_ROOT_PASSWORD=mysecretpassword \
-e MARIADB_AUTO_UPGRADE=yes \
-v mariadb-data:/var/lib/mysql \
git.breis.ch/images/mariadb:12
Backup Sidecar
A companion mariadb-backup image is available for scheduled backups with:
- Cron-based scheduling
- Multiple compression algorithms (gzip, zstd, xz, lzma)
- Proxmox-style retention policies
- Age encryption support
- Webhook notifications
- Built-in restore utility
See mariadb-backup/README.md for full documentation.
Quick example:
services:
mariadb:
image: git.breis.ch/images/mariadb:12
environment:
MARIADB_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mariadb-data:/var/lib/mysql
backup:
image: git.breis.ch/images/mariadb-backup:12
environment:
MARIADB_HOST: mariadb
MARIADB_PASSWORD: ${DB_PASSWORD}
BACKUP_SCHEDULE: "0 2 * * *"
BACKUP_KEEP_DAILY: "7"
volumes:
- backup-data:/backups
depends_on:
- mariadb
License
MIT License (image build scripts) / GPL v2 (MariaDB)