{{- $replicas := include "valkey.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.valkey.replicas) -}} {{- $limitBytes := include "valkey.memoryLimitBytes" .Values.valkey.resources -}} {{- $maxmemory := include "valkey.maxmemoryBytes" (dict "resources" .Values.valkey.resources "maxmemory" .Values.valkey.maxmemory "maxmemoryFactor" .Values.valkey.maxmemoryFactor) -}} Valkey {{ .Chart.AppVersion }} — release {{ .Release.Name }} in namespace {{ .Release.Namespace }}. ACCESS — IN-CLUSTER ONLY {{ .Release.Name }}-{{ .Chart.Name }}-service.{{ .Release.Namespace }}.svc.cluster.local:6379 There is no Ingress and no value to add one: this is one application's cache or queue backend, and its only authentication is the password. Applications address it with a redis:// URL (Valkey speaks the same protocol, and every client library still calls the scheme redis://): redis://:@{{ .Release.Name }}-{{ .Chart.Name }}-service.{{ .Release.Namespace }}.svc.cluster.local:6379/0 The password belongs in the CONSUMING application's own vault item, where its connection URL lives. Nothing here writes it there. Check by hand from inside the namespace, with the password out of the pod's own mounted file so it never reaches your shell history: kubectl -n {{ .Release.Namespace }} exec {{ .Release.Name }}-{{ .Chart.Name }}-sfs-0 -- /bin/sh /etc/valkey/ping.sh && echo OK THE 1PASSWORD ITEM MUST CARRY ONE FIELD, AND ITS NAME IS PART OF THE CHART secrets.authSecretRef points at {{ .Values.secrets.authSecretRef }} The 1Password operator materializes that item as the Kubernetes Secret {{ .Release.Name }}-{{ .Chart.Name }}-secret, with one Secret key per field of the item. This chart reads exactly one field: auth-conf a COMPLETE Valkey configuration line, not the bare password: requirepass A differently named field produces no such key, and the pod then stays in ContainerCreating with "couldn't find key auth-conf" in its events. Why a whole configuration line instead of the password: the file is mounted and "include"d by the configuration, so the password never appears in the process list, in an environment variable, or in anything Helm renders. The cost is that a typo in that line would be a Valkey WITHOUT a password — running, healthy, and reachable from the whole pod network, because the official image compiles protected-mode off. An init container therefore checks the mounted file for a "requirepass " line before the server starts and refuses to let the pod run otherwise. If the pod is stuck in Init:Error or Init:CrashLoopBackOff, read it: kubectl -n {{ .Release.Namespace }} logs {{ .Release.Name }}-{{ .Chart.Name }}-sfs-0 -c {{ .Release.Name }}-{{ .Chart.Name }}-check-auth It never prints the field's contents. Watch the materialization with kubectl -n {{ .Release.Namespace }} get onepassworditem {{ .Release.Name }}-{{ .Chart.Name }}-secret kubectl -n {{ .Release.Namespace }} get secret {{ .Release.Name }}-{{ .Chart.Name }}-secret THIS RELEASE IS CONFIGURED AS A {{ if .Values.persistence.enabled }}{{ if eq .Values.valkey.maxmemoryPolicy "noeviction" }}QUEUE{{ else }}PERSISTENT CACHE{{ end }}{{ else }}{{ if eq .Values.valkey.maxmemoryPolicy "noeviction" }}VOLATILE STORE — PROBABLY BY MISTAKE{{ else }}CACHE{{ end }}{{ end }} persistence.enabled: {{ .Values.persistence.enabled }} valkey.maxmemoryPolicy: {{ .Values.valkey.maxmemoryPolicy }} memory limit (computed): {{ include "valkey.humanBytes" $limitBytes }} ({{ $limitBytes }} bytes) maxmemory: {{ include "valkey.humanBytes" $maxmemory }} ({{ $maxmemory }} bytes){{ if kindIs "invalid" .Values.valkey.maxmemory }}, derived as maxmemoryFactor {{ .Values.valkey.maxmemoryFactor | default 0.75 }} x the limit{{ else }}, set explicitly in values and checked against the limit{{ end }} {{ if .Values.persistence.enabled }} {{- if eq .Values.valkey.maxmemoryPolicy "noeviction" }} The combination this chart is built for. When memory runs out Valkey REFUSES WRITES instead of discarding keys, so a full queue is an error in the application rather than jobs that quietly disappeared. {{- else }} Persistence with an evicting policy: the data survives a restart but not memory pressure. Fine for a cache that is expensive to rebuild — wrong for a Sidekiq or Celery queue, which would lose jobs while staying green. {{- end }} {{- else }} {{- if eq .Values.valkey.maxmemoryPolicy "noeviction" }} READ THIS: no persistence AND noeviction is almost never intended. The data is gone on every pod restart, so nothing is being protected — but once memory is full, writes start FAILING instead of cold keys being dropped. For a cache set valkey.maxmemoryPolicy: allkeys-lru; for a queue set persistence.enabled: true. {{- else }} Cache shape: the dataset lives in the pod only. Both AOF and the RDB save points are switched off, so a restart starts from empty and nothing is written to ephemeral storage. {{- end }} {{- end }} {{- if .Values.persistence.enabled }} STORAGE {{ .Release.Name }}-{{ .Chart.Name }}-pvc, {{ .Values.persistence.size }}, {{ if .Values.persistence.storageClass }}storage class "{{ .Values.persistence.storageClass }}"{{ else }}on the cluster's default storage class (persistence.storageClass is unset — the default class is not encrypted){{ end }}. Persistence mode: {{ if .Values.persistence.appendonly }}append-only file (every write appended; a crash loses at most the last fsync interval){{ else }}RDB snapshots only (a crash loses every write since the last snapshot, silently — the instance comes back healthy, only shorter){{ end }}. helm uninstall does NOT delete this PVC, which is deliberate — the data survives a reinstall of the same release name. It also means a release removed and recreated under a DIFFERENT name starts on an empty volume while the old one keeps occupying space. On encrypted Longhorn volumes that space is never returned to the pool. {{- end }} {{ if eq $replicas "0" }} SCALED TO ZERO {{ if .Values.scaleDown }}scaleDown: true{{ else }}valkey.replicas: 0{{ end }} — the StatefulSet runs with replicas: 0, so nothing answers on the address above and every application configured against it will fail its own checks. Nothing else is removed: Service and Secret stay{{ if .Values.persistence.enabled }}, the PVC keeps the data{{ end }}{{ if .Values.networkPolicy.enabled }}, and the NetworkPolicy stays in force{{ end }}. {{ end }} CHANGING THE PASSWORD IS NOT COVERED BY A CHECKSUM The pod template carries checksum/config over the configuration ConfigMap and checksum/secret-ref over the rendered OnePasswordItem. So a changed maxmemory/policy rolls the pod, and so does repointing secrets.authSecretRef at a DIFFERENT vault item. What cannot be covered is a new password inside the same item: Helm never sees the content of a Secret the 1Password operator fills in. After changing it there: kubectl -n {{ .Release.Namespace }} rollout restart statefulset {{ .Release.Name }}-{{ .Chart.Name }}-sfs (operator.1password.io/auto-restart is not set on purpose — the operator restarts Deployments only, so on a StatefulSet it would be a silent no-op.) Unverified, and named so rather than promised: because the probes read the password out of the same mounted file, the kubelet's refresh of that file (roughly a minute) should make the liveness probe fail against the still-old server and restart the container by itself. Do the rollout restart instead of waiting for it. {{ if .Values.networkPolicy.enabled }} NETWORK POLICY IS ACTIVE Ingress to port 6379 is allowed from namespace {{ .Release.Namespace }}{{ if .Values.networkPolicy.allowedNamespaces }} and from {{ join ", " .Values.networkPolicy.allowedNamespaces }}{{ end }}. Egress is unrestricted (this instance opens no outbound connection of its own). It is only a boundary where the CNI enforces NetworkPolicies. Where it does not, the object is accepted and nothing is filtered — so verify it instead of reading it off the manifest: kubectl -n run t --rm -it --image=docker.io/valkey/valkey:{{ .Chart.AppVersion }} \ -- valkey-cli -h {{ .Release.Name }}-{{ .Chart.Name }}-service.{{ .Release.Namespace }} ping That must hang or be refused. "NOAUTH Authentication required." means the policy is not being enforced and the password is your only boundary. {{- else }} NO NETWORK POLICY networkPolicy.enabled is false, so the password is the only thing between this instance and every pod in the cluster. The official image compiles protected-mode off, so there is no second line of defence behind it. {{- end }} WHAT A GREEN POD PROVES All three probes run "valkey-cli -e ping" AUTHENTICATED with the password from the mounted file and require the answer PONG. So Ready means: the server accepted a connection, accepted that password, and answered. Two things it does not mean. It does not say anything about the dataset — a restarted instance whose AOF was lost answers PONG on an empty database. And it does not say your application's keys are reachable: that depends on the connection URL in the application's own vault item, which this chart neither writes nor reads. The probe asserts the answer (PONG), not just that the command returned, and it passes "-e" so that valkey-cli reports an error reply through its exit code at all — without it a bare "valkey-cli ping" exits 0 while printing "NOAUTH Authentication required.", which would be a probe that cannot fail.