kadet-hub logokadet-hub

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.

What it deploys

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:

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

The recipe's files are in kadet-hub/recipes. All recipes