feat(valkey): one Valkey instance per application (1.0.0+up9.1.2.alpine)
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Successful in 4s
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Successful in 11s
Validate Helm Charts / Install-test ${{ fromJSON(needs.detect-changed-charts.outputs.install-charts) }} (pull_request) Successful in 1m22s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 7s
Publish Valkey Helm Chart / Publish Valkey Helm Chart (push) Successful in 7s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Successful in 4s
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Successful in 11s
Validate Helm Charts / Install-test ${{ fromJSON(needs.detect-changed-charts.outputs.install-charts) }} (pull_request) Successful in 1m22s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 7s
Publish Valkey Helm Chart / Publish Valkey Helm Chart (push) Successful in 7s
A new chart for a single Valkey instance per application, replacing the
shared cluster-redis whose separation rests on one ACL file in one
1Password field - a construction in which every change touches six
applications and which cost a month of Paperless standstill.
Shape: StatefulSet with one replica, ClusterIP Service, no cluster mode,
no Ingress and no value to add one.
The password arrives as a finished configuration line ("requirepass
<secret>") in the 1Password field auth-conf, is mounted as a file and
included by the main configuration - never in argv, never in the
environment. The include is rendered last, so nothing in extraConfig can
override it. Because a misspelled or empty field would leave an open
server that looks perfectly healthy, an init container greps the mounted
file for the line and refuses to start the pod without it; it never
prints the file.
maxmemory is derived from the computed memory limit (maxmemoryFactor,
default 0.75) and a configured value above that limit aborts the render:
otherwise the kubelet's OOM kill decides what the eviction policy was
configured to decide. Persistence and eviction are documented as pairs -
queue (PVC + noeviction, the default) and cache (emptyDir +
allkeys-lru) - and the combination "no persistence + noeviction" carries
a warning in values.yaml and in NOTES.txt.
Probes: valkey-cli ping as an exec probe, authenticated through
VALKEYCLI_AUTH read out of the mounted file, with "-e" and an assertion
on the answer PONG. Without -e valkey-cli exits 0 on an error reply
(valkey 9.1.2, src/valkey-cli.c: the config.set_errcode branch in
cliReadReply), which would make the probe unable to fail.
Hardening: uid 999 / gid 1000 - the image's own valkey user - with
fsGroup matching, runAsNonRoot, readOnlyRootFilesystem, all capabilities
dropped and seccompProfile RuntimeDefault in the pod context so the init
container is covered too. /data is the only writable path.
NetworkPolicy on by default (first chart in this repo with one), with a
switch and a list of additional namespaces; values.yaml names that it is
only a boundary where the CNI enforces policies.
Wiring: publish-valkey.yml, the chart-name choice list, ci/valkey
fixtures for the persistent variant, a plain docker-versioning Renovate
block, README chart row.
This commit was merged in pull request #53.
This commit is contained in:
19 files changed
+1687
No files matched your search
@@ -109,6 +109,19 @@ misconfigurations:
|
||||
paths: ["**/homeassistant.yaml"]
|
||||
statement: "NET_RAW is the capability in question and is added on purpose for device discovery; see AVD-KSV-0022."
|
||||
|
||||
# --- valkey: the two keyword findings on its ConfigMap ---------------------
|
||||
# Both are keyword matches on the COMMENTS and the shell script in the
|
||||
# ConfigMap, not on data. Worth suppressing with a reason rather than leaving
|
||||
# standing, because "ConfigMap stores secrets" on this chart of all charts
|
||||
# says the opposite of what it does: the whole design exists to keep the
|
||||
# password out of everything Helm renders.
|
||||
- id: AVD-KSV-0109
|
||||
paths: ["**/valkey.yaml"]
|
||||
statement: "False positive on the rendered ConfigMap. The matched strings are the comment '# Nothing here prints the password' and the line pass=\"$(sed -n 's/^requirepass...' \"$AUTH_FILE\")\" of the probe script - i.e. the code that READS the password out of the mounted Secret file at probe time. The ConfigMap contains no credential: the password lives only in the 1Password item, is materialized into a Secret by the operator, mounted as a file and 'include'd by the configuration, which is precisely why no requirepass line is rendered here. Verify by rendering the chart - no value from the vault appears in it."
|
||||
- id: AVD-KSV-01010
|
||||
paths: ["**/valkey.yaml"]
|
||||
statement: "Same class as AVD-KSV-0109 above: the matched keys are 'valkey.conf' and an 'echo \"valkey...' line of the validation script. Both are chart-authored configuration and diagnostics text; nothing user- or credential-derived is stored in this ConfigMap."
|
||||
|
||||
# --- rss-bridge: port 80 is fixed by the image ----------------------------
|
||||
- id: AVD-KSV-0117
|
||||
paths: ["**/rss-bridge.yaml"]
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Fixtures for the valkey install-test: the one Secret the 1Password operator
|
||||
# would otherwise materialize from the OnePasswordItem the chart renders
|
||||
# (release name: ci, stub CRD in ci/common/).
|
||||
#
|
||||
# The field name matters as much as the value. The chart mounts exactly the key
|
||||
# "auth-conf" and its content has to be a COMPLETE Valkey configuration line,
|
||||
# because the configuration "include"s the file - so this fixture is also what
|
||||
# keeps the init container's check honest: give it anything that is not a
|
||||
# "requirepass <password>" line and the pod refuses to start, which is the
|
||||
# failure this chart exists to make loud.
|
||||
#
|
||||
# No throwaway infrastructure here: Valkey depends on nothing. What this
|
||||
# install-test does exercise, and why it is the persistent variant, is the risky
|
||||
# path - a provisioned PVC, the pod's fsGroup against it, and an append-only
|
||||
# file being created and replayed on a volume the container did not create.
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ci-valkey-secret
|
||||
stringData:
|
||||
# A throwaway password. Nothing here survives the run - but it is a real
|
||||
# password rather than an empty string on purpose: an empty one would produce
|
||||
# exactly the open server the chart refuses to start, and the run would fail
|
||||
# for the right reason at the wrong place.
|
||||
auth-conf: requirepass ci-valkey-throwaway-password
|
||||
@@ -0,0 +1,37 @@
|
||||
# CI values for the valkey install-test. The PERSISTENT variant on purpose: it is
|
||||
# the chart's default and the only risky path there is (a provisioned PVC, the
|
||||
# pod's fsGroup against it, an append-only file created on a volume the container
|
||||
# did not create). The machinery can run one variant per chart, so the
|
||||
# non-persistent path is covered by a local render only - named as a known gap in
|
||||
# the PR that introduced this chart.
|
||||
secrets:
|
||||
authSecretRef: op://ci/valkey
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
appendonly: true
|
||||
# k3d's dynamic provisioner. The chart's default, longhorn-encrypted-ns, does
|
||||
# not exist on the runner, and a pre-bound hostPath PV would be worse than this
|
||||
# one: the kubelet does not apply fsGroup to a hostPath volume at all, so the
|
||||
# test would silently stop exercising the ownership path it is here for.
|
||||
storageClass: local-path
|
||||
size: 128Mi
|
||||
|
||||
valkey:
|
||||
# Small, so the whole thing stays inside the runner's budget. It still
|
||||
# exercises the derivation: 64Mi x limitFactor 3 = 192Mi limit, maxmemory =
|
||||
# 0.75 x that = 144Mi - and the render aborts if a configured maxmemory ever
|
||||
# ends up above the limit.
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
ephemeral-storage: 32Mi
|
||||
|
||||
# Left ON, although nothing in the test connects from another namespace: the
|
||||
# point here is that the object is accepted and does not keep the pod's own
|
||||
# traffic (the exec probes are local to the pod and unaffected) from working.
|
||||
# Whether the policy actually FILTERS is a property of the cluster's CNI and is
|
||||
# not claimed by this test.
|
||||
networkPolicy:
|
||||
enabled: true
|
||||
Reference in new issue
Block a user