Files
computer-playbook/roles/svc-db-redis/README.md
kevinveenbirkenbachandClaude Opus 5.5 45d956e5ea fix(sidecars): cap an engine's sidecar at its provider's size
A Redis sidecar whose consumer declares no services.redis.mem_limit
runs in a container that inherits the consumer's primary entity limit.
Since the lookup replaced the old filter, maxmemory followed that limit
and rose from 204 MiB to between 819 and 3276 MiB in 17 roles.

lookup('service_memory_mb', ..., provider=<role>) caps the result at
the same share of the provider's own limit when the application does
not declare one for that service. A declared limit is not capped, and a
container smaller than the provider keeps its own share. The Redis
sidecar passes provider='svc-db-redis': those 17 roles get 409 MiB, the
seven with a 256 MiB container stay at 204.

The lookup now rejects unknown options and a provider that is no role
or declares no limit for the service, so a misspelled option fails
instead of silently lifting the cap.

The memcached sidecar's literal -m 64 takes the same lookup and keeps
its value.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 01:30:01 +02:00

6.3 KiB

Redis

Description

This Ansible role provides Redis in two interchangeable shapes, selected per consumer with the shared flag (mirroring svc-db-postgres):

  • Central (enabled: true, shared: true): a standalone, manager-pinned Redis stack that many roles share. Each consumer gets its own ACL user restricted to the key-prefix {entity}:*.
  • Embedded (enabled: true, shared: false): a Redis sidecar rendered into the consumer's own compose stack via templates/service.yml.j2.

Overview

The central stack (templates/compose.yml.j2) runs redis:alpine with:

  • requirepass for the default (admin) user, sourced from the REDIS_PASSWORD credential.
  • AOF persistence for cached data.
  • A maxmemory ceiling derived from the service mem_limit with an allkeys-lru policy.
  • A bind on 127.0.0.1:6379 plus the shared cross-stack overlay network for consumers.

Per-consumer provisioning (tasks/01_init.yml) runs with application_id=svc-db-redis and database_consumer_id=<consumer>; it resolves the consumer's username, password and key-prefix via lookup('engine', 'redis', <consumer>, ...) and reconciles an idempotent ACL SETUSER restricted to ~{entity}:*. The ACL users are recreated by the consumer's 01_init on every deploy, so a container restart that drops the in-memory ACL set is healed on the next run.

The embedded snippet (templates/service.yml.j2) keeps the previous single-host behaviour: an unauthenticated in-memory Redis attached to the consumer stack's default network. Its maxmemory is 80 % of the consumer's services.redis.mem_limit; a consumer that declares none gets 80 % of the limit its container inherits, at most 80 % of this role's own mem_limit.

Cosmos

The diagram places Redis in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).

flowchart LR
    subgraph deps [Dependencies]
        dep_svc_bkp_volume_2_local["svc-bkp-volume-2-local 💻"]
        dep_svc_net_tor["svc-net-tor 🐳🐝"]
    end
    subgraph role [svc-db-redis 🐳🐝]
        svc_redis["redis"]
        svc_tor["tor"]
        svc_container_backup["container_backup"]
    end
    subgraph dependents [Dependents]
        dpt_web_app_akaunting["web-app-akaunting 🐳🐝"]
        dpt_web_app_baserow["web-app-baserow 🐳🐝"]
        dpt_web_app_bookwyrm["web-app-bookwyrm 🐳🐝"]
        dpt_web_app_decidim["web-app-decidim 🐳🐝"]
        dpt_web_app_discourse["web-app-discourse 🐳🐝"]
        dpt_web_app_erpnext["web-app-erpnext 🐳🐝"]
        dpt_web_app_fider["web-app-fider 🐳🐝"]
        dpt_web_app_flowise["web-app-flowise 🐳🐝"]
        dpt_web_app_funkwhale["web-app-funkwhale 🐳🐝"]
        dpt_web_app_gitea["web-app-gitea 🐳🐝"]
        dpt_web_app_gitlab["web-app-gitlab 🐳🐝"]
        dpt_web_app_magento["web-app-magento 🐳🐝"]
        dpt_more["..."]
    end
    dep_svc_bkp_volume_2_local -- "1:1" --> svc_container_backup
    dep_svc_net_tor -. "0..1" .-> svc_tor
    svc_redis -- "1:1" --> dpt_more
    svc_redis -. "0..1" .-> dpt_web_app_akaunting
    svc_redis -. "0..1" .-> dpt_web_app_baserow
    svc_redis -. "0..1" .-> dpt_web_app_bookwyrm
    svc_redis -. "0..1" .-> dpt_web_app_decidim
    svc_redis -. "0..1" .-> dpt_web_app_discourse
    svc_redis -. "0..1" .-> dpt_web_app_erpnext
    svc_redis -. "0..1" .-> dpt_web_app_fider
    svc_redis -. "0..1" .-> dpt_web_app_flowise
    svc_redis -. "0..1" .-> dpt_web_app_funkwhale
    svc_redis -. "0..1" .-> dpt_web_app_gitea
    svc_redis -. "0..1" .-> dpt_web_app_gitlab
    svc_redis -. "0..1" .-> dpt_web_app_magento

Solid 1:1 edges are fixed relationships; dashed 0..1 edges are conditional (enabled only in matching deployments); red 0..0 edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in meta/main.yml.

Features

  • Central or embedded selected per consumer via services.redis.shared.
  • ACL isolation one Redis user per consumer, scoped to {entity}:* keys.
  • Idempotent provisioning ACL users reconciled on every deploy via ACL SETUSER.
  • Manager-pinned central on-disk state stays node-local (never on NFS) in swarm.
  • Built-in healthcheck authenticated redis-cli ping.

Quick Setup

Development

Clone, set up the workstation, and deploy Redis onto the local stack:

git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=svc-db-redis full_cycle=false

Production

Run the published image to provision the inventory and deploy Redis to a managed server (the mounted volume persists the inventory):

APP=svc-db-redis
HOST=<your-server>
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"

docker run --rm -it \
  -v "$PWD/inventories:/etc/infinito.nexus/inventories" \
  -e APP="$APP" -e HOST="$HOST" -e DOMAIN="$DOMAIN" -e TLS_MODE="$TLS_MODE" -e SSH_PUBLIC_KEY="$SSH_PUBLIC_KEY" \
  ghcr.io/infinito-nexus/core/debian bash -c '
    INVENTORY=/etc/infinito.nexus/inventories/production
    infinito administration inventory provision "$INVENTORY" \
      --inventory-file "$INVENTORY/devices.yml" \
      --host "$HOST" \
      --include "$APP" \
      --vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}" &&
    infinito administration deploy dedicated "$INVENTORY/devices.yml" \
      --password-file "$INVENTORY/.password" \
      --diff -vv'

Further Resources

Credits

Implemented by Kevin Veen-Birkenbach. Part of the Infinito.Nexus Project and maintained by Kevin Veen-Birkenbach. Licensed under the Infinito.Nexus Community License (Non-Commercial).