Memcached on Kubernetes with Kapitan
memcached as a single in-memory cache without authentication, designed in kadet-hub on the Docker Official Image memcached and rendered by the kadet-hub kubernetes generator 1.14.0.
- Latest version:
1.0.1, published - Source: container image
docker.io/library/memcached:1.6.45@sha256:aea0d81d101a9b64fe30cf2cf2f96144e284f8e9552bb084a03f4e12e9043bab, recipe designed in kadet-hub - Proof level:
deploys, deployed on kind and smoke tested by the kadet-hub/recipes CI renderspassed in the release run of with check 0.18.0, kind v0.33.0- Output capabilities: none
- Inventory backends:
omegaconf - Generators: kubernetes 1.14.0
sha256:787129e1eaed6b9bc868fe4c4aec58d40de6a89fc3cc08424a4cb5822b855080 - Image security: grade D 189 findings, one per advisory and package, in the 1 image of version 1.0.1: CRITICAL 0, HIGH 50, MEDIUM 78, LOW 61, UNKNOWN 0. Scanned 2026-11-07 11:47 UTC. Full report
The grade rates the upstream images the recipe pins, not the recipe:docker.io/library/memcached.
What it deploys
recipes.memcached(init.yml)recipes.memcached.memcached(memcached.yml):memcached
Required parameters
No parameter has to be set.
Include
A target includes the recipe and its options as classes and can override anything the recipe sets:
classes:
- recipes.memcached
parameters:
namespace: memcached
kapitan:
vars:
target: memcached
Fetching it
The quickstart goes through these steps on a kind cluster with the uptime-kuma recipe, from installing Kapitan to the running app.
A separate fetch inventory pins the recipe by version and digest. This is fetch/targets/recipes.yml for version 1.0.1:
parameters:
kapitan:
dependencies:
- type: oci
source: ghcr.io/kadet-hub/recipes/memcached:1.0.1@sha256:eeea246db03e3e6a06232d58e019b2ba44d21550396c8d8aeab0d3137b63a7b4
output_path: inventory/classes/recipes/memcached
The first command fetches the recipe into inventory/classes/recipes/memcached, the second the generators and compiles:
kapitan compile --inventory-path fetch --fetch --output-path .
kapitan compile --fetch
The first command exits with status 1 because the fetch target compiles nothing. Kapitan's --fetch checks neither the digest nor the attestation. This verifies the attestation of the recipe:
gh attestation verify \
oci://ghcr.io/kadet-hub/recipes/memcached@sha256:eeea246db03e3e6a06232d58e019b2ba44d21550396c8d8aeab0d3137b63a7b4 \
--owner kadet-hub \
--cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main
The attested index must also list each digest under its recipe with the pinned version, and not as yanked. Verifying by hand shows how to read it.
Settings
| Setting | Inventory |
|---|---|
| memcached version | components.memcached.image, tag and digest |
| cache size, 64 megabytes | components.memcached.args as a mapping, such as memory-limit: --memory-limit=1024, with components.memcached.resources.limits.memory raised above it |
other server options, such as --conn-limit=4096 |
components.memcached.args as a mapping, each value one option |
| resources | components.memcached.resources |
Service type, ClusterIP |
components.memcached.service.type |
nodeSelector, tolerations, affinity |
components.memcached.node_selector, components.memcached.tolerations, components.memcached.affinity |
memcached accepts every client that reaches the Service, without authentication and without TLS, as Bitnami’s chart does by default (DEC-153). It listens on TCP port 11211 only. UDP is off, memcached’s default. The cache lives in the pod’s memory and is empty after every restart.
With its cache of 64 megabytes full, memcached used 70 MiB of the memory
limit of 192Mi on kind. Raise the limit together with --memory-limit.
The pod runs as the image’s user memcache, UID 11211, with a read-only
root filesystem, and passes Pod Security restricted. A readiness probe
connects to port 11211. There is no liveness probe (DEC-152).
Left out
Bitnami’s chart 8.8.7 renders these with its defaults as well:
NetworkPolicy/memcached. It admits port 11211 from every source and all egress, and memcached listens on no other port.PodDisruptionBudget/memcached.maxUnavailable: 1of one replica allows every eviction.ServiceAccount/memcached. No role binds it. The recipe’s pod runs asdefaultwithout a token, as the chart’s pod runs without one.- On the Deployment, the liveness probe
pgrep memcached, which the pinned image cannot run, the preferred pod anti-affinity, which does nothing for one replica, the CPU limit of 150m, the ephemeral-storage request and limit, and the environment variables andemptyDirmounts of Bitnami’s image. - On the Service,
publishNotReadyAddresses: true.
Proof
check memcached --level deploys with tests/target.yml on kind for each
Kubernetes minor CI tests. The image has no Kubernetes objects to compare
with, so the recipe is proven by deploying it (RCP-44). tests/smoke
connects with bash’s /dev/tcp from the memcached pod to the Service
memcached on port 11211. It stores a value, reads it back on a second
connection, and requires stats to report the version of the image tag.
It checks that the pod passes Pod Security restricted.
Versions
1.0.1, :sha256:eeea246db03e3e6a06232d58e019b2ba44d21550396c8d8aeab0d3137b63a7b41.0.0, :sha256:dd2adc4f4e32fef333c9a7a6b4c7b3df8e7afec789904aa5c9a799d49983a1ae
The recipe's files are in kadet-hub/recipes. All recipes