Kubernetes
The Helm chart
deploys exav as one Deployment behind one ClusterIP Service. The chart is
oci://ghcr.io/sylvinus/exav-chart. It applies a hardened Pod Security
Standard by default, and it ships with no signature source: you must set one
before the daemon serves scans. Each resource takes the release name when
the release name contains exav, otherwise it takes <release>-exav.
This page covers the concepts. For the full list of chart values, read the chart README on GitHub.
Install
Section titled “Install”helm install exav oci://ghcr.io/sylvinus/exav-chart --version <X.Y.Z> \ --set 'signatures.sources={https://mirror.example/db/}'The chart version, the app version, and the image tag all match the exav
git tag, without the leading v.
Test the install with a port-forward. In one terminal:
kubectl port-forward svc/exav 3310:3310In another terminal, run a PING and a scan:
exav --ping --connect clamd://127.0.0.1:3310exav --connect clamd://127.0.0.1:3310 --send-as contents file.binSignatures
Section titled “Signatures”Set signatures.sources to one or more CVD mirror URLs, or set
signatures.dbUrl to a prebuilt .exavdb. See
Signatures for the source formats, and
Prebuilt database for how to build a
.exavdb and why it starts faster.
Both values can carry credentials. The chart stores them in a Secret, and
signatures.existingSecret lets you supply your own. Do not set
signatures.sources or signatures.dbUrl together with
signatures.existingSecret. The chart render fails.
Startup and probes
Section titled “Startup and probes”The chart’s only probe is /exav --ping, an exec probe. Nothing answers on
the clamd or ICAP port until signatures finish loading. The startup probe
allows about 40 minutes by default, which covers the fetch and the first
load, and the Deployment progress deadline follows the same window.
signatures.startupWaitSecs applies only when no source is set and a
sidecar fills the volume. A signature hot reload keeps the listener open, so
it does not fail a readiness probe. The daemon replaces the workers at once,
so a scan in flight loses its connection.
Storage
Section titled “Storage”By default, the chart mounts an emptyDir: each pod refetches signatures
on every restart. Turn on signatures.persistence.enabled for a
PersistentVolumeClaim instead. With more than one replica, the PVC needs a
ReadWriteMany access mode, or chart rendering fails.
Memory and workers
Section titled “Memory and workers”exav sizes each worker from the pod’s cgroup memory limit. Without a memory
limit, the Kubernetes OOM killer can kill the pod. exav then gives no
verdict at all. With a limit, exav reports LIMITS-EXCEEDED instead.
Always set resources.limits.memory. Use about 6Gi for raw sources. Use
about 3Gi for a prebuilt database. Add headroom for scans in flight.
Workers default to the number of available CPUs, and this count honors a
cpu limit but not a cpu request. Set resources.limits.cpu, or set
workers yourself, on a large node.
Security
Section titled “Security”The chart runs the pod under the Pod Security Standard restricted
profile: non-root uid/gid/fsGroup 65532, all capabilities dropped,
readOnlyRootFilesystem: true, and no auto-mounted ServiceAccount token.
Neither the clamd port nor the ICAP port has authentication or TLS, so
network reachability is the whole security boundary. Use a NetworkPolicy to
restrict which namespaces can reach the Service.
Set icap.enabled: true to add an ICAP listener on port 1344, next to the
clamd listener, over the same loaded signature database. See the
ICAP guide for the service names and the verdict mapping.
Upgrades
Section titled “Upgrades”To upgrade, run helm upgrade with the new chart version:
helm upgrade exav oci://ghcr.io/sylvinus/exav-chart --version <X.Y.Z> \ -f my-values.yamlA helm upgrade that passes -f or --set replaces every value from the
previous release, unless you add --reuse-values. Pass the full values file
each time. A RollingUpdate starts a second pod before it stops the first
one, so the node needs memory for two signature loads at once. When
persistence is on without ReadWriteMany, the chart uses the Recreate
strategy instead.