Redis on Kubernetes without Bitnami: Valkey with Kapitan
Valkey, in place of Bitnami's redis chart (standalone architecture): one StatefulSet with append-only persistence and a password. Valkey is the BSD-3-Clause fork of Redis 7.2 and speaks the same protocol. The password is a Kapitan ref, generated on the first compile into refs/valkey/password; compile again with --reveal, or apply through Tesoro, to get the value into the Secret. The base64 backend keeps the recipe self-contained and encrypts nothing: in a real project use gpg or a KMS backend. No operator needed.
- Replaces the Bitnami charts:
redis - Generators: kubernetes
- Operators: none
Inventory class
inventory/classes/recipes/valkey.yml, as on the main branch of kadet-hub/examples. A target includes it next to the pins below.
# Valkey, in place of Bitnami's redis chart (standalone architecture): one
# StatefulSet with append-only persistence and a password. Valkey is the
# BSD-3-Clause fork of Redis 7.2 and speaks the same protocol. The password
# is a Kapitan ref, generated on the first compile into refs/valkey/password;
# compile again with --reveal, or apply through Tesoro, to get the value into
# the Secret. The base64 backend keeps the recipe self-contained and encrypts
# nothing: in a real project use gpg or a KMS backend. No operator needed.
classes:
- recipes.lib.kubernetes
parameters:
generators:
kubernetes:
namespaces:
valkey: {}
components:
valkey:
namespace: valkey
type: statefulset
image: docker.io/valkey/valkey:9.1.2
security_profile: restricted
workload_security_context:
runAsUser: 999
runAsGroup: 999
fsGroup: 999
args: [valkey-server, --requirepass, $(VALKEY_PASSWORD), --appendonly, "yes", --dir, /data]
env:
VALKEY_PASSWORD:
secretKeyRef:
key: password
secrets:
auth:
string_data:
password:
value: ?{base64:valkey/password||random:str:32}
ports:
valkey:
container_port: 6379
service_port: 6379
healthcheck:
readiness:
type: tcp
port: valkey
liveness:
type: tcp
port: valkey
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {memory: 512Mi}
volume_mounts:
data:
mount_path: /data
volume_claims:
data:
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 8Gi
service:
type: ClusterIP
Compile classes
The class includes one per generator; each compiles its generator once, so a target can combine several recipes.
inventory/classes/recipes/lib/kubernetes.yml
# Compiles the kubernetes generator; recipes include this class, so a target that
# combines several recipes compiles it once.
parameters:
kapitan:
compile:
- {input_type: kadet, output_type: yml, input_paths: [lib/kubernetes], output_path: kubernetes/}
Generator pins
The entries of inventory/classes/generators.yml for these generators, pinned by version and digest.
parameters:
kapitan:
dependencies:
- output_path: lib/kubernetes
source: ghcr.io/kadet-hub/kubernetes:1.2.0@sha256:52017626e77dd5bf7293ce465ff0c3dc7a61dae1ae8353a56a53ffebe1bfb67c
type: oci
How it is checked
The examples CI verifies the signed index and the attestation of every pinned generator, compiles the target, validates the output against the generators' schemas, deploys it to a new kind cluster with the operators above and fails unless the StatefulSet is ready and valkey-cli ping answers PONG. The Chainsaw test holds the assertions.