No description
Find a file
Clément BREISCH f50d160474
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
add retention cleanup debug logging
- 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)")
2026-01-05 13:02:18 +00:00
.github/workflows add --health-check flag to entrypoint for distroless compatibility 2025-12-29 20:15:22 +00:00
backup-sidecar add retention cleanup debug logging 2026-01-05 13:02:18 +00:00
examples add backups 2025-12-26 20:00:29 +00:00
mariadb add --health-check flag to entrypoint for distroless compatibility 2025-12-29 20:15:22 +00:00
mariadb-backup add ssl/tls connection support for backup and restore 2026-01-05 11:20:14 +00:00
mariadb-entrypoint add utc timestamps to all log messages 2026-01-05 12:59:43 +00:00
.gitignore Initial MariaDB distroless image implementation 2025-12-21 23:39:18 +00:00
.metadata.json fix paths 2025-12-26 20:04:30 +00:00
LICENSE Initial commit 2025-12-21 23:15:32 +00:00
README.md healthcheck: use MARIADB_USER/MARIADB_PASSWORD for authentication 2026-01-05 12:35:42 +00:00
SECURITY.md docs: fix runtime hardening tmpfs uid/gid and volume mount path 2025-12-29 18:34:40 +00:00
test-backup.sh add backups 2025-12-26 20:00:29 +00:00

MariaDB Distroless

Build

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 _FILE suffix 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.3
  • ssl_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

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=65532 to match the nonroot user. The volume must be mounted directly to /var/lib/mysql/{version}/data to 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)