MariaDB on Kubernetes with Kapitan
MariaDB Server as a single instance with one database and its user, designed in kadet-hub on the MariaDB Foundation’s image and rendered by the kadet-hub kubernetes generator 1.14.0.
- Latest version:
1.0.1, published - Source: container image
docker.io/library/mariadb:12.3.3@sha256:d46e102fa8b9b72bfcdeb56f9dd538742092119dc8b11f31fe662605cd234cd9, recipe designed in kadet-hub - Proof level:
deploys, deployed on kind and smoke tested by the kadet-hub/recipes CI renderspassed in the release run of with check 0.18.0, kind v0.33.0- Output capabilities: none
- Inventory backends:
omegaconf - Generators: kubernetes 1.14.0
sha256:787129e1eaed6b9bc868fe4c4aec58d40de6a89fc3cc08424a4cb5822b855080 - Image security: grade F 101 findings, one per advisory and package, in the 1 image of version 1.0.1: CRITICAL 1, HIGH 27, MEDIUM 62, LOW 10, UNKNOWN 1. Scanned 2026-11-07 11:47 UTC. Full report
The grade rates the upstream images the recipe pins, not the recipe:docker.io/library/mariadb.
What it deploys
recipes.mariadb(init.yml)recipes.mariadb.mariadb(mariadb.yml):mariadb
Required parameters
applications.mariadb.password, the password of the user app, and
applications.mariadb.root_password must be set, as refs with the backend
of your choice. Without them the compile stops with
Interpolation key 'applications.mariadb.password' not found.
Include
A target includes the recipe and its options as classes and can override anything the recipe sets:
classes:
- recipes.mariadb
parameters:
namespace: mariadb
kapitan:
vars:
target: mariadb
applications:
mariadb:
password: <ref>
root_password: <ref>
Fetching it
The quickstart goes through these steps on a kind cluster with the uptime-kuma recipe, from installing Kapitan to the running app.
A separate fetch inventory pins the recipe by version and digest. This is fetch/targets/recipes.yml for version 1.0.1:
parameters:
kapitan:
dependencies:
- type: oci
source: ghcr.io/kadet-hub/recipes/mariadb:1.0.1@sha256:0ab0c69a1a1efaeb00354a4e44885cf87cd1084bddb36ea767a77d23151b5662
output_path: inventory/classes/recipes/mariadb
The first command fetches the recipe into inventory/classes/recipes/mariadb, the second the generators and compiles:
kapitan compile --inventory-path fetch --fetch --output-path .
kapitan compile --fetch
The first command exits with status 1 because the fetch target compiles nothing. Kapitan's --fetch checks neither the digest nor the attestation. This verifies the attestation of the recipe:
gh attestation verify \
oci://ghcr.io/kadet-hub/recipes/mariadb@sha256:0ab0c69a1a1efaeb00354a4e44885cf87cd1084bddb36ea767a77d23151b5662 \
--owner kadet-hub \
--cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main
The attested index must also list each digest under its recipe with the pinned version, and not as yanked. Verifying by hand shows how to read it.
Settings
| Setting | Inventory |
|---|---|
| MariaDB version | components.mariadb.image, tag and digest |
database and its user, app |
applications.mariadb.database, applications.mariadb.user |
| volume size, 8Gi | components.mariadb.volume_claims.data.spec.resources.requests.storage |
| resources | components.mariadb.resources |
server options, such as --require-secure-transport=ON |
components.mariadb.args as a mapping, each value one option |
MariaDB reads the database, the user and both passwords only when it initializes an empty data directory. Changing them later changes the Secret, not the database. The root user may log in from any host, the image’s default.
The pod runs as the image’s user mysql, UID 999, and passes Pod Security
restricted. The data lives in the subdirectory mariadb of the volume,
because MariaDB lists a lost+found at the volume’s root as a database.
The readiness probe runs the image’s healthcheck.sh --connect --innodb_initialized every 10 seconds, the check of the
image’s documentation.
There is no liveness probe. MariaDB opens its port only after InnoDB’s
crash recovery, and a liveness probe would restart a recovery that takes
longer than its threshold.
MariaDB serves TLS on port 3306 with a self-signed certificate that it
generates, because no certificate is configured. Clients from 11.4
on verify that certificate by default through the password of a
mysql_native_password or ed25519 account, such as app
(Zero-Configuration SSL).
The server also accepts clients without TLS. --require-secure-transport=ON
refuses them.
Proof
check mariadb --level deploys with tests/target.yml on kind for each
Kubernetes minor CI tests. The image has no Kubernetes objects to compare
with, so the recipe is proven by deploying it (RCP-44). tests/smoke
connects as the user app to its database app through the Service
mariadb on port 3306, with TLS and the server’s certificate verified. It
creates a table, writes a row and reads it back, and requires the server
version of the image’s tag. It checks that the pod passes Pod Security
restricted, deletes the pod mariadb-0 and reads the row again through
the Service once the new pod is ready.
Versions
1.0.1, :sha256:0ab0c69a1a1efaeb00354a4e44885cf87cd1084bddb36ea767a77d23151b56621.0.0, :sha256:36524c95daedcf791c93a58203b109ecc328052bd216e34c657c162fb7b20a48
The recipe's files are in kadet-hub/recipes. All recipes