Netgrimoire/Keystone-Grimoire/Docker/Swarm-Template.md
2026-04-12 09:53:51 -05:00

3.7 KiB

title description published date tags editor dateCreated
Docker Swarm Template Standard Canonical YAML template and label rules for all Netgrimoire swarm services true 2026-04-12T00:00:00.000Z keystone, docker, swarm markdown 2026-04-12T00:00:00.000Z

Docker Swarm Template Standard

All Swarm YAML files in services/swarm/ and services/swarm/stack/ must follow this standard. The Gremlin audit workflow checks compliance weekly.


Canonical Template

# Deploy: docker stack deploy -c <service>.yaml <service>
services:
  <servicename>:
    image: <image>:latest
    environment:
      TZ: America/Chicago
    volumes:
      - /DockerVol/<servicename>:/config
      # - /data/nfs/znas/Docker/<servicename>:/data
    networks:
      - netgrimoire
    deploy:
      restart_policy:
        condition: any
        delay: 5s
        max_attempts: 3
        window: 120s
      placement:
        constraints:
          - node.hostname == znas
          - node.platform.arch != aarch64
          - node.platform.arch != arm
      labels:
        # Caddy
        caddy: <servicename>.netgrimoire.com
        caddy.reverse_proxy: <servicename>:<PORT>
        caddy.import: crowdsec
        caddy.import_1: authentik

        # Uptime Kuma
        kuma.<servicename>.http.name: <Service Name>
        kuma.<servicename>.http.url: https://<servicename>.netgrimoire.com

        # Homepage
        homepage.group: <Group>
        homepage.name: <Service Name>
        homepage.icon: <service>.png
        homepage.href: https://<servicename>.netgrimoire.com
        homepage.description: <Description>

        # DIUN
        diun.enable: "true"

networks:
  netgrimoire:
    external: true

Forbidden Fields

Never use these at the service level:

Field Reason
version: Deprecated in Compose v2+
container_name: Incompatible with Swarm replicas
restart: Use deploy.restart_policy instead
depends_on: Not supported in Swarm mode
endpoint_mode: dnsrr Breaks internal DNS — always use VIP

Volume Path Rules

Path When to Use
/DockerVol/<service> Config, SQLite DBs, small app state. Only valid with a node.hostname placement constraint.
/data/nfs/znas/Docker/<service> Bulk data, media, or any service without a hostname constraint

Placement Constraints

Default (all services):

constraints:
  - node.hostname == znas
  - node.platform.arch != aarch64
  - node.platform.arch != arm

ARM exclusion prevents accidental scheduling on Pi vault/worker nodes. Override only if the service is ARM-specific.

For services pinned to docker4 (Gremlin stack):

constraints:
  - node.hostname == docker4
  - node.platform.arch != aarch64
  - node.platform.arch != arm

Caddy Label Rules

caddy: servicename.netgrimoire.com        # no https:// prefix
caddy.reverse_proxy: servicename:PORT     # container name:port, NOT {{upstreams PORT}}
caddy.import: crowdsec                    # always both
caddy.import_1: authentik                 # always both, no exceptions

Never use {{upstreams PORT}} — it breaks during docker stack config preprocessing.

Wasted-bandwidth services use wasted-bandwidth.net domain and caddy.import_1: authelia instead of authentik.


Deploy Workflow

# From services repo root
git add . && git commit -m "Add/update <service>" && git push

# On znas (or docker4 for Gremlin services)
cd ~/services && git pull
cd swarm/stack/<StackName>
set -a && source .env && set +a
docker stack config --compose-file <service>.yaml > resolved.yml
docker stack deploy --compose-file resolved.yml <service>
rm resolved.yml
docker stack services <service>