Warning
Pre-alpha. OpenEverest v2 and this provider are under active development. CRD schemas, chart values and defaults change frequently, including in breaking ways, and there is no supported upgrade path between versions yet. Not for production use.
Run MariaDB on Kubernetes through OpenEverest,
backed by the mariadb-operator.
OpenEverest providers translate a single, technology-agnostic Instance custom
resource into the native custom resources of an upstream Kubernetes operator —
for databases, but equally for caches, message queues, object storage, or
model-serving runtimes. This repository is the provider for MariaDB: it owns
the technology-specific knowledge — topologies, versions, parameters, backup
wiring — so that users, the API server, and the UI stay technology-agnostic.
Important
This provider is not standalone. It requires an OpenEverest installation (core CRDs and controller) in the cluster. Installing this chart on its own does nothing. See Install OpenEverest.
flowchart LR
U([User / API / UI]) -->|creates| I["Instance<br/>core.openeverest.io"]
I --> P["provider-mariadb<br/>(this repository)"]
P -->|reconciles into| O["MariaDB CR<br/>k8s.mariadb.com/v1alpha1"]
O --> W["mariadb-operator"]
W --> R[("Workloads, Services,<br/>Secrets, PVCs")]
P -->|status, endpoints,<br/>credentials| I
The provider watches Instance resources whose spec.providerRef.name is
mariadb, and reports workload health back onto Instance.status. It never
manages pods directly — all lifecycle work is delegated to the operator.
| provider-mariadb | OpenEverest | mariadb-operator | Kubernetes |
|---|---|---|---|
0.1.x |
>= 2.0.0 |
26.6.x |
1.30 – 1.34 |
What you can do to a running instance through the Instance API. Upgrading the
provider itself is covered under Installation.
| Capability | Status | Notes |
|---|---|---|
| Provisioning | ✅ | |
| Horizontal scaling | ✅ | spec.components.engine.replicas |
| Vertical scaling (CPU / memory) | ✅ | spec.components.engine.resources |
| Version upgrades | ✅ | of the deployed MariaDB version — change spec.version; see Versions |
| High availability (Galera) | ✅ | spec.topology.type: galera — multi-master cluster; odd node count (default 3) |
| High availability (replication) | ✅ | spec.topology.type: replication — async primary/replica cluster; at least 2 nodes (default 3) |
| Proxy / load balancing (MaxScale) | ✅ | opt-in via the proxy component on galera and replication; see MaxScale proxy |
| Custom configuration | ✅ | my.cnf via the engine component's configuration parameter |
| Monitoring | ✅ | opt-in via the monitoring component; deploys mysqld-exporter and a Prometheus ServiceMonitor — requires the ServiceMonitor CRD (monitoring.coreos.com) |
| Pod scheduling | ✅ | spec.components.{engine,proxy}.schedulingPolicy — affinity (nodeAffinity and podAntiAffinity; podAffinity is rejected), nodeSelector, tolerations and topologySpreadConstraints; schedulerName is not supported. A set affinity replaces the HA default soft anti-affinity, {} sets none |
| TLS | ✅ | enabled by default with operator-managed certificates; CA is published in the connection Secret |
Stateful workloads additionally report:
| Capability | Status | Notes |
|---|---|---|
| Persistent storage | ✅ | spec.components.engine.storage.size |
| Storage expansion | ✅ | when the StorageClass allows volume expansion |
| Backups (on demand) | ✅ | logical (mariadb-dump) or physical (mariadb-backup) to S3-compatible storage; strategy selected via the backup type parameter |
| Backups (scheduled) | ✅ | cron schedules per storage via spec.backup |
| Restore | ✅ | logical backups are restored in place; physical backups are restored by seeding a new Instance from spec.dataSource |
| Point-in-time recovery | ✅ | binary log archival on the replication topology; one storage may enable pitr; recover a new Instance to a target time via spec.dataSource (PointInTime) |
The provider chart is published as an OCI artifact:
helm install provider-mariadb \
oci://ghcr.io/openeverest/charts/provider-mariadb \
--version 0.1.8 \
--namespace everest-system- The
mariadb-operator(and its CRDs) is bundled as a chart dependency and is installed automatically.
Upgrade and uninstall:
helm upgrade provider-mariadb oci://ghcr.io/openeverest/charts/provider-mariadb --version 0.1.8
helm uninstall provider-mariadb --namespace everest-systemUninstalling the chart does not delete running Instance resources or their data.
Verify that the provider registered itself:
kubectl get providers.core.openeverest.io mariadbCreate an instance:
apiVersion: core.openeverest.io/v1alpha1
kind: Instance
metadata:
name: my-instance
spec:
providerRef:
name: mariadb
components:
engine:
type: mariadb
replicas: 1
resources:
requests:
cpu: 500m
memory: 2G
storage:
size: 10GiComponent names are defined by this provider — see
definition/provider.yaml. spec.version and
spec.topology are optional; the provider defaults apply. More examples live in
examples/.
Watch it come up and read the connection details:
kubectl get instance my-instance -w
kubectl get instance my-instance -o jsonpath='{.status.connectionSecretRef.name}'The credentials (host, port, username, password, uri) live in the connection
Secret named by .status.connectionSecretRef.name.
TLS is enabled by default. The same connection Secret contains tls: "true"
and the operator-generated CA bundle under ca.crt, allowing clients to verify
the MariaDB server certificate. Unencrypted connections remain accepted by
default for migration compatibility. To reject them, set:
spec:
components:
engine:
parameters:
tls:
required: trueTLS can be explicitly disabled with tls.enabled: false. Galera deployments
also encrypt state snapshot transfers by default; this can be changed with
tls.galeraSSTEnabled. See examples/instance-tls.yaml.
The galera and replication topologies can be fronted by
MariaDB MaxScale,
which routes writes to the primary and balances reads across nodes. Enable it
through the proxy component:
spec:
topology:
type: replication
components:
proxy:
replicas: 2 # default
parameters:
enabled: true
service:
serviceType: LoadBalancerWhile the proxy is enabled, the connection Secret points at the MaxScale
Service (<name>-maxscale) with the same credentials. MaxScale terminates TLS
only when the engine requires it (tls.required: true); the connection Secret
then carries the MaxScale CA. Setting enabled: false removes MaxScale. See
examples/instance-maxscale.yaml.
Primary failover, rejoin and read_only stay with the operator: MaxScale only
routes traffic and follows the topology. With replication, the provider turns
off MaxScale's own auto_failover, auto_rejoin and
switchover_on_low_disk_space, because running failover in both MaxScale and
the operator races and can leave no writable primary
(#37).
Important
MaxScale is licensed under the Business Source License. Make sure you understand the implications before enabling it.
Backups are driven natively by the operator to an S3-compatible object store —
the provider never runs side-car Jobs. Two strategies are available, selected
per backup via the type parameter:
logical— amariadb-dumpSQL dump, restored in place.physical— amariadb-backupdata-directory snapshot, restored by seeding a new Instance fromspec.dataSource(in-place restore is not supported by the engine for physical backups).
Point-in-time recovery builds on physical backups plus binary log archival; see Point-in-time recovery below.
Enable backups on the Instance by registering a BackupStorage (a reference to
your object store) under spec.backup, using the provider's mariadb
BackupClass. Cron schedules are configured per storage:
spec:
backup:
enabled: true
classRef:
name: mariadb
storages:
- storageRef:
name: my-s3-storage
schedules:
- name: daily
enabled: true
cron: "0 0 * * *"
retention:
type: count # or `type: time` with `duration: 30d` (d/w/m)
count: 7
parameters:
type: physical
compression: gzipOn-demand backups are taken by creating a Backup resource that targets the
same storage and class. Restore a new Instance from an existing backup with
spec.dataSource:
spec:
dataSource:
type: Backup
backup:
backupRef:
name: my-backupspec.dataSource is immutable once set and requires spec.backup.enabled: true
with at least one storage so the provider can read the source backup.
Point-in-time recovery (PITR) continuously archives the primary's binary logs to
object storage on top of a full physical base backup, so an Instance can be
recovered to any moment within the retained window. Binary log archival is only
supported on the replication topology (Galera and standalone are not
supported by the engine yet).
Enable it by setting pitr.enabled on exactly one storage that also declares a
physical backup schedule (which drives the base backup); the provider reconciles
a PointInTimeRecovery object and turns on archival:
spec:
topology:
type: replication
backup:
enabled: true
classRef:
name: mariadb
storages:
- storageRef:
name: my-s3-storage
pitr:
enabled: true
schedules:
- name: base
enabled: true
cron: "0 * * * *"
parameters:
type: physicalThe recovery window is published on status.backup.storages[].pitr. Recover a
new Instance to a target time (or the latest archived point) via
spec.dataSource:
spec:
dataSource:
type: PointInTime
pointInTime:
source:
instanceRef:
name: my-source-instance
storageRef:
name: my-s3-storage
recoveryTarget: date # or "latest"
date: 2026-02-20T18:00:04Z| Topology | Default | Description |
|---|---|---|
standalone |
✅ | Single MariaDB instance (no replication or Galera) |
galera |
Multi-master Galera cluster for high availability (odd number of nodes, default 3) | |
replication |
Async primary/replica cluster for high availability (at least 2 nodes, default 3) |
| Version bundle | Default | mariadb |
|---|---|---|
10.11 |
10.11 |
|
11.4 |
11.4 |
|
11.8 |
11.8 |
|
12.3 |
✅ | 12.3 |
Source of truth: definition/versions.yaml.
- Chart values: charts/provider-mariadb/values.yaml
- Instance parameters: per-component and per-topology
parametersschemas, defined under definition/ and published on theProviderresource (kubectl get provider mariadb -o yaml). The API server and the UI validate user input against these schemas.
The main technology-specific knob is the engine's configuration parameter,
which is passed through to the MariaDB server as my.cnf.
Requires Go (see go.mod), Docker, Helm, kubectl, and a Kubernetes
cluster you can reach. For local development we recommend k3d —
make dev-up creates the cluster for you.
make dev-up # local k3d cluster + Tilt dev environment
make generate # RBAC, provider spec, Helm chart sync
make run # run the provider locally against the cluster
make test-unit
make test-integration # chainsaw suites under test/integration/
make dev-downTo work against a cluster you already have — kind, GKE, a shared dev cluster —
skip make dev-up and point Tilt at it:
cp dev/.env.example dev/.env # set K8S_CONTEXT, and DOCKER_REGISTRY_URL for a remote registry
tilt up -f dev/Tiltfilemake help lists every target. make verify fails when generated files are
stale — run make generate and commit the result.
The provider contract (Validate / Sync / Status / Cleanup), RBAC
markers, watches, code generation, and the backup/restore interfaces are
documented once for all providers in PROVIDER_DEVELOPMENT.md.
| Path | Purpose |
|---|---|
cmd/provider/ |
Entry point |
internal/provider/ |
ProviderInterface implementation, RBAC markers |
internal/common/ |
Component name constants |
definition/ |
Provider identity, component types, versions, topologies |
charts/provider-mariadb/ |
Helm chart (generated/ is produced by make generate) |
config/rbac/role.yaml |
Generated ClusterRole — do not edit |
test/integration/ |
Chainsaw suites |
test/vars.sh |
Pinned operator and workload versions used by tests |
examples/ |
Example Instance resources |
dev/ |
Tilt dev environment, .env configuration, k3d cluster config |
.github/workflows/ |
CI: lint, build, unit and integration tests, release |
- Unit tests —
make test-unit. - Integration tests — chainsaw suites under test/integration/.
The
core/suite provisions an instance and verifies connectivity end to end. - CI — .github/workflows/ci.yaml runs lint, build, unit tests, generated-file verification, Helm lint, and each integration suite on every pull request.
kubectl logs -n everest-system deploy/provider-mariadb -f| Symptom | Where to look |
|---|---|
Instance stuck in Creating |
kubectl describe instance <name> conditions, then the provider logs |
No Provider resource in the cluster |
Is the chart installed? Check the provider deployment logs |
Instance ignored entirely |
spec.providerRef.name must be mariadb |
| MariaDB resource created but no pods | Inspect the MariaDB custom resource status — the failure is upstream in the operator |
Issues and pull requests are welcome. See PROVIDER_DEVELOPMENT.md and the OpenEverest Code of Conduct.
Report vulnerabilities per the OpenEverest security policy. Please do not open public issues for security reports.
Apache License 2.0 — see LICENSE for details.