How-to guide Package task guides
Deploy Valkey / Redis
Deploy a persistent Redis-compatible Valkey service with the Kix package catalogue.
Use the valkey package to deploy a Redis-compatible data store on the
official Valkey image: a StatefulSet with a volume per pod, a Service for
clients, password authentication, and, on clusters that span several nodes,
Sentinel failover.
Add the Valkey instance and its password
Section titled “Add the Valkey instance and its password”Add the package, and a secret holding its password, in the namespace where the applications that use it run:
instances.cache = { valkey = { package = packages.valkey; config.storage.size = "2Gi"; };
# Outside local development, give the secret a SOPS `source` with # keys = [ "password" ], or use a secret-ref to an existing Secret. valkey-password = { package = packages.secret; aliases = [ "valkeyPassword" ]; config.stringData.password = "development-only-password"; }; };The valkeyPassword dependency is required and auth is always on. It
resolves to a secret or secret-ref instance in Valkey’s namespace that
declares the key password. The inline password in the example is for local
development. For a deployed environment, give the secret a SOPS source with
keys = [ "password" ], or point a secret-ref instance at a Secret managed
outside Kix. When the password of a secret-ref changes, the pods do not
restart on their own; use reloader’s withReloadOn to roll them. The password
is used byte for byte, so a trailing newline in the Secret is part of it, and
clients must send it too. An empty password stops the pod from starting.
Each pod gets a claim of storage.size (8 GiB unless set). The claim’s class
is storage.storageClassName when set, else the class of the cluster’s
storageClasses provider, else the cluster default.
Choose the topology
Section titled “Choose the topology”The availability level decides the topology. Below node, Valkey runs one
standalone pod. From node up, sentinel.enabled defaults on and the
instance runs three pods: one primary, two replicas, and a Sentinel sidecar
in each pod that promotes a replica when the primary is lost. Set
sentinel.enabled and replicas on the instance to choose explicitly.
Evaluation refuses more than one pod without Sentinel, fewer than three with
it, and a sentinel.quorum that the remaining Sentinels could not reach once
the primary’s pod is gone.
Change Valkey’s configuration through settings, which renders valkey.conf
directives, and Sentinel’s through sentinel.primarySettings:
instances.cache.valkey.config = { settings.maxmemory-policy = "allkeys-lru"; sentinel.primarySettings.down-after-milliseconds = 5000;};maxmemory defaults to 70% of resources.limits.memory, leaving room for
replication buffers and the copy-on-write pages of an AOF rewrite. With the
default noeviction policy, writes fail once the dataset is full. Directives
the package sets itself or relies on, such as port, bind, the password,
replication, and rename-command, are refused, and so is a value with a line
break.
When the cluster has a prometheus provider, each pod also runs a
redis_exporter sidecar, and the instance gets a ServiceMonitor and alerts.
The sidecar is part of the pod template, so adding the first provider, or
setting metrics.enabled = false, restarts every pod.
Connect an application
Section titled “Connect an application”Applications read the connection from the instance’s out:
| Key | Value |
|---|---|
out.fqdn, out.port | The Service that selects every Valkey pod, port 6379 |
out.authSecret, out.authPasswordKey | The password secret and its key: valkey.out.authSecret.out.keyRef valkey.out.authPasswordKey |
out.sentinelPort, out.primarySet | With Sentinel only: port 26379 on the same Service, and the name Sentinel monitors the primary under |
A consumer must run in Valkey’s namespace, because Kubernetes resolves a
secretKeyRef only in the pod’s own namespace. Dependency injection does not
offer a Valkey instance to a consumer in another namespace, and an explicit
ref to one fails evaluation.
With Sentinel on, the Service also routes to replicas, which refuse writes. A
client that writes asks Sentinel at out.fqdn and out.sentinelPort for the
primary of out.primarySet. It sends Sentinel no password: Sentinel’s default
user takes none, and an AUTH with a password is an error. That user may read
Sentinel’s state, which covers the discovery calls of common clients
(SENTINEL GET-PRIMARY-ADDR-BY-NAME, SENTINEL MASTERS, SENTINEL REPLICAS, SENTINEL SENTINELS), and may not change it. Only the
sentinel-admin user, with the instance password, can reconfigure Sentinel.
A package whose client cannot use Sentinel asks for a standalone Valkey and refuses one that runs Sentinel anyway, such as an import:
deps.valkey = { config.sentinel.enabled = false; assertions = dep: lib.optional (dep.out ? sentinelPort) { assertion = false; message = "this package has no Sentinel client; set sentinel.enabled = false on the valkey instance."; };};Check the generated resources
Section titled “Check the generated resources”Evaluate the cluster:
❱ kix check how-to-package-valkey
TOOL RESULT DETAILS
eval pass 14 manifests evaluated
scorecard pass 0 errors, 1 warnings, 0 info Inspect the StatefulSet and client Service:
❱ kix build how-to-package-valkey --output json
[
{
"apiVersion": "apps/v1",
"kind": "StatefulSet",
"metadata": {
"name": "valkey",
"namespace": "cache"
},
"spec": {
"replicas": 1,
"serviceName": "valkey-headless",
"containers": [
{
"name": "valkey",
"image": "docker.io/valkey/valkey:8.1.10@sha256:640c5e62cea04b6d6f2084232651d0cc70362d31f4f805e7be94dbed6855e8f2",
"ports": [
{
"containerPort": 6379,
"name": "valkey",
"protocol": "TCP"
}
]
}
],
"volumeClaimTemplates": [
{
"metadata": {
"name": "data"
},
"spec": {
"accessModes": [
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "2Gi"
}
},
"storageClassName": "standard"
}
}
]
}
},
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "valkey",
"namespace": "cache"
},
"spec": {
"ports": [
{
"name": "valkey",
"port": 6379,
"protocol": "TCP",
"targetPort": 6379
}
]
}
}
] The StatefulSet requests the configured 2 GiB volume and uses the headless
Service for stable pod names. Applications connect to the valkey Service on
port 6379.
Deploy and connect
Section titled “Deploy and connect”Deploy the cluster and check the instance:
❱ kix deploy how-to-package-valkey❱ kix status how-to-package-valkey To test it locally, forward the service port:
❱ kix pf how-to-package-valkey valkey 6379:6379 While the forward is running, use a Redis-compatible client from another terminal:
❱ REDISCLI_AUTH=development-only-password valkey-cli ping A successful connection returns PONG. Stop the port-forward with Ctrl-C.
If the pod remains pending, inspect its PVC and confirm that the requested
StorageClass exists and can provision ReadWriteOnce volumes in the target
cluster.