kadet-hub logokadet-hub

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.

What it deploys

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

The recipe's files are in kadet-hub/recipes. All recipes