[PATCH v2 08/13] recipes-containers/images: add app-container-valkey

Tim Orling <[email protected]> Mon, 6 Jul 2026 10:12:43 -0700
Newsgroups org.yoctoproject.lists.meta-virtualization
Message-ID <db9e87eaeb31711afb8f4dbe5b7631cada5848f0.1783356922.git.tim.orling@konsulko.com>
From: Tim Orling <[email protected]>

Add OCI container image recipe for the Valkey in-memory key-value
datastore. The image uses multi-layer mode with separate base and
valkey layers, exposes the standard Valkey port (6379), and launches
valkey-server with its default config file as the entrypoint.

The stock valkey.conf shipped by meta-oe is tuned for a host install
(daemonize yes, syslog-enabled yes, bind 127.0.0.1). In most use cases
the user will want to provide their own valkey.conf. In that vein,
provide container-entrypoint.sh which will use /path/to/valkey.conf
passed in on the command line. If no .conf is passed in, we default
to the same behavior as upstream containers (no config).

Add container-entrypoint.sh script based on upstream [1]

Add OCI_IMAGE_WORKINGDIR = "/data" to avoid issues writing .rdb on save
since 'valkey' will default to '/' for the working dir.

Add NONROOT_OWNED_DIRS = "/data /var/lib/valkey /var/log/valkey /run/valkey"
as the 'nonroot' user needs permissions on these directories.

Inherit container-nonroot-user to run as 'nonroot' with UID 65532 by
default. Can optionally set PACKAGECONFIG:pn-app-container-valkey = "dev"
in local.conf or a distro/image config to run as 'root'.

Inherit container-volatile-fixup to fix 'log' and 'tmp' in
/var/volatile.

Inherit container-dev-mode to optionally run as UID '0' root user.
Since we use 'container-entrypoint.sh' which has #!/bin/sh we
provide a shell for both '-dev' and 'production' container flavors,
which matches upstream Docker Hardened Images behavior.

Relies on image-oci to auto-derive IMAGE_INSTALL from OCI_LAYERS
:packages: layers.

[1] https://github.com/valkey-io/valkey-container/blob/mainline/9.1/debian/docker-entrypoint.sh

Signed-off-by: Tim Orling <[email protected]>
---
 .../images/app-container-valkey.bb            | 71 +++++++++++++++++++
 .../container-entrypoint.sh                   | 18 +++++
 2 files changed, 89 insertions(+)
 create mode 100644 recipes-containers/images/app-container-valkey.bb
 create mode 100644 recipes-containers/images/app-container-valkey/container-entrypoint.sh

diff --git a/recipes-containers/images/app-container-valkey.bb b/recipes-containers/images/app-container-valkey.bb
new file mode 100644
index 00000000..10c239e2
--- /dev/null
+++ b/recipes-containers/images/app-container-valkey.bb
@@ -0,0 +1,71 @@
+SUMMARY = "Valkey key-value store container image"
+DESCRIPTION = "OCI container running the Valkey in-memory key-value \
+datastore, a flexible distributed datastore that supports both caching \
+and beyond caching workloads."
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+
+# Multi-layer mode: create explicit layers instead of single rootfs layer
+OCI_LAYER_MODE = "multi"
+
+# Optional 'dev' mode:
+#   - runs the container as root (UID 0)
+# Enable with: PACKAGECONFIG:pn-app-container-valkey = "dev"
+PACKAGECONFIG ??= ""
+PACKAGECONFIG[dev] = ""
+inherit container-dev-mode
+
+# Unlike the other app-container-* recipes, valkey always ships a real shell,
+# in 'dev' and production alike. container-entrypoint.sh is a #!/bin/sh
+# script (upstream-compatible arg handling + umask hardening; see the file
+# for details) and requires an interpreter to boot at all — 'no shell in
+# production' isn't available here without dropping that script and its
+# behavior. Matches DHI's own 'hardened' valkey image (debian-13/9.1.yaml),
+# which ships bash for the exact same reason rather than go shell-less.
+CONTAINER_SHELL = "busybox"
+
+#  image.bbclass intentionally sets do_fetch, do_unpack and do_install to noexec.
+#  We do not want to abuse that isolation, so instead get the file from local
+#  tree and install in rootfs postprocess.
+ROOTFS_POSTPROCESS_COMMAND:append = " rootfs_install_entrypoint_sh ; "
+rootfs_install_entrypoint_sh () {
+    install -m 0755 ${THISDIR}/${BPN}/container-entrypoint.sh ${IMAGE_ROOTFS}/${bindir}/
+}
+
+# Define layers: each layer contains specific packages
+# Format: "name:type:content" where content uses + as delimiter for multiple items
+OCI_LAYERS = "\
+    base:packages:base-files+base-passwd+netbase \
+    shell:packages:${CONTAINER_SHELL} \
+    valkey:packages:valkey+tini \
+    entrypoint:files:${bindir}/container-entrypoint.sh \
+"
+
+# In 'dev' mode, override the nonroot UID inherited from container-nonroot-user
+OCI_IMAGE_RUNTIME_UID = "${@bb.utils.contains('PACKAGECONFIG', 'dev', '0', '${NONROOT_UID}', d)}"
+
+# The 'nonroot' user needs permissions on the following directories
+NONROOT_OWNED_DIRS = "/data /var/lib/valkey /var/log/valkey /run/valkey"
+
+IMAGE_FSTYPES = "container oci"
+inherit image
+inherit image-oci
+inherit container-nonroot-user
+inherit container-volatile-fixup
+
+IMAGE_FEATURES = ""
+IMAGE_LINGUAS = ""
+NO_RECOMMENDATIONS = "1"
+
+# Allow build with or without a specific kernel
+IMAGE_CONTAINER_NO_DUMMY = "1"
+
+# The stock valkey.conf shipped by meta-oe is tuned for a host install
+# (daemonize yes, syslog-enabled yes, bind 127.0.0.1). Most users will
+# want to create their own valkey.conf and pass it in to the
+# container-entrypoint.sh script
+OCI_IMAGE_ENTRYPOINT = "${bindir}/docker-init -- ${bindir}/container-entrypoint.sh"
+OCI_IMAGE_CMD = "${bindir}/valkey-server"
+OCI_IMAGE_PORTS = "6379/tcp"
+OCI_IMAGE_TAG = "latest"
+OCI_IMAGE_WORKINGDIR = "/data"
diff --git a/recipes-containers/images/app-container-valkey/container-entrypoint.sh b/recipes-containers/images/app-container-valkey/container-entrypoint.sh
new file mode 100644
index 00000000..36cdf93a
--- /dev/null
+++ b/recipes-containers/images/app-container-valkey/container-entrypoint.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Based on https://github.com/valkey-io/valkey-container/blob/mainline/docker-entrypoint.sh
+# SPDX-License-Identifier: BSD-3-Clause
+set -e
+
+# first arg is `-f` or `--some-option`
+# or first arg is `something.conf`
+if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then
+    set -- valkey-server "$@"
+fi
+
+# set an appropriate umask (if one isn't set already)
+um="$(umask)"
+if [ "$um" = '0022' ]; then
+    umask 0077
+fi
+
+exec "$@"
-- 
2.54.0