MakerFLOSS/slides/tappaas/how-to/new-module/index.md
Lars Rossen 834bd406f2
All checks were successful
Build docs site / build (push) Successful in 48s
Build slides / build (push) Successful in 1m6s
slides(tappaas): session details, dev-topology slide, identity login
Date 24 August; the demo environment is lab1 (zone lab1, lab1.makerfloss.eu
outside / lab1.internal inside). Adds the upstream 'developing TAPPaaS modules'
topology from tappaas.org ahead of our own repo picture, which now carries
forgejo.makerfloss.eu and highlights that this site tracks main, not stable.
Drops the manager-verbs slide; the demo slides carry the verbs where they are
actually used, with network/environment/module status commands.

Cockpit now logs in via identity:identity rather than a local PAM password, and
identity hand-out uses 'authentik-manager user-recovery-link' so no password is
ever read aloud. NOTE: podman.json in Community does not yet declare
identity:identity — the module needs that change before the session.
2026-08-22 18:03:06 +02:00

9 KiB

marp theme class paginate title description
true gaia invert true How to implement a TAPPaaS module Live build of a Podman module — OrangeMaker, 24 August

Getting a module onto TAPPaaS

Live build of a Podman container host

OrangeMaker · 24 August


The plan

  1. What TAPPaaS is — a few diagrams, ten minutes, no deeper
  2. What a module actually is — a json contract and three scripts
  3. Build one live — the lab1 environment, then podman into it
  4. Prove it works — tests, then the web console
  5. You get a login — your own identity on this system

You leave with: a mental model, a module you watched get built, and an account.


The shape of a TAPPaaS site

flowchart LR
  sat["satellite VPS<br/>public IP · ingress<br/>off-site backup"]
  subgraph z0["mgmt · zone mgmt"]
    cicd["tappaas-cicd"]
    net["network"]
    clu["cluster"]
    bak["backup"]
    idp["identity"]
  end
  subgraph z1["default · zone srv"]
    nc["nextcloud"]
    ha["home-assistant"]
  end
  subgraph z2["lab1 · zone lab1"]
    pod["podman — today"]
  end
  sat --> net
  cicd --> nc
  cicd --> pod

The words we will use

Word Meaning
Module The smallest deployable unit — its own VM, its own json contract. Foundation and apps are modules.
Environment A tenant. mgmt and one named after the site always exist; add more freely. Today we add lab1.
Zone A VLAN with a firewall policy. Modules land in their environment's zone.
Mothership tappaas-cicd — where the managers run and where you type.
Satellite Optional VPS, for sites with no usable public IP.

Everything is a module. There is one model to learn, not eight.


Developing modules: dev instance, private branch

flowchart RL
  subgraph Development["Development repository"]
    dev_main["main"]
  end
  subgraph Upstream["Upstream repository"]
    up_main["main"]
    up_stable["stable"]
    up_main -->|merge| up_stable
  end
  subgraph InstanceDev["TAPPaaS instance · dev"]
    localDev["clone of Upstream"]
    localDev_dev["clone of Development"]
  end
  subgraph InstanceProd["TAPPaaS instance · prod"]
    localProd["clone of Upstream"]
  end
  localProd -->|pull| up_stable
  localDev -->|pull| up_main
  localDev_dev -->|push| dev_main
  dev_main -->|PR| up_main

Our setup tonight

flowchart RL
  subgraph t["TAPPaaS · codeberg"]
    stable["stable"]
    main["main"]
  end
  subgraph c["Community · codeberg"]
    cm["main"]
  end
  subgraph f["forgejo.makerfloss.eu"]
    fm["main"]
  end
  subgraph inst["Our TAPPaaS · tappaas-cicd"]
    lt["clone of TAPPaaS"]
    lc["clone of Community"]
    lf["clone of MakerFLOSS"]
  end
  lt -->|pull| main
  lc -->|pull| cm
  lf -->|pull| fm
  classDef tracked stroke:#ff8a80,stroke-width:3px
  class main tracked

We track main, not stable — this is a lab, we want the new things.


A module is a contract and three scripts

podman/
├── podman.json     # the contract — what it is, needs, provides
├── install.sh      # put the software in the VM        (once)
├── update.sh       # keep it patched                   (on schedule)
├── test.sh         # prove it still works              (gates updates)
├── README.md       # what it is
└── INSTALL.md      # what automation cannot do for you

That is the whole surface. Everything else is the platform's job.


The contract, for real

{
  "description": "Podman container host — Debian 13 VM with rootless Podman + Cockpit",
  "vmname": "podman", "vmid": 812,
  "dependsOn": ["cluster:vm", "templates:debian", "backup:vm",
                "network:proxy", "identity:identity"],
  "config": {
    "cluster:vm": { "cores": 2, "memory": "2048", "diskSize": "20G",
                    "image": "debian-13-generic-amd64.qcow2" },
    "network:proxy": { "proxyPort": 9090, "proxyUpstreamTls": true,
                       "proxyUpstreamHttp1": true, "proxyAllowedZones": ["mgmt"] }
  }
}

dependsOn is the whole trick: five services, declared — not scripted.


The three scripts, honestly

Script Called Does
install.sh once, at add For podman: exec update.sh — install is update here
update.sh every schedule apt: podman, podman-compose, cockpit, cockpit-podman; enable the rootless socket
test.sh on demand + before every update merge VM reachable · podman present · plugin present · console answers on :9090

If test.sh is honest, unattended updates are safe. That is the entire deal.


What you did not have to write

  • A VM — cluster:vm built it from the Debian 13 cloud image
  • OS prep — templates:debian did apt + guest agent
  • A VLAN, an interface, DHCP, firewall rules — the zone came with the environment
  • https://podman.lab1.makerfloss.eu with a real certificate — network:proxy
  • A login — identity:identity, so it is your TAPPaaS account, not a local one
  • Nightly backup to PBS, scheduled updates, health reporting

A few lines of json bought all of it.


Demo 1 — an environment of our own

network-manager zone add lab1 --from-zone srv
network-manager show lab1              # vlan tag, subnet, access-to
network-manager reconcile              # dry-run: drift on all 4 planes
network-manager reconcile --apply      # converge OPNsense, Proxmox, switch, AP

environment-manager add lab1 --display "MakerFLOSS lab" \
    --zone lab1 --domain lab1.makerfloss.eu
environment-manager list
environment-manager show lab1

A tenant with its own VLAN, firewall posture and DNS names — lab1.makerfloss.eu outside, lab1.internal inside.


Demo 2 — install the module

module-manager module add podman --environment lab1

module-manager module list             # what is deployed
module-manager module show podman      # the resolved config, cascade applied

Watch the order: dependencies resolve first, then the VM, then the network, then install.sh. Install order is computed from every module's dependsOn — nobody maintains a list.


Demo 3 — prove it, then look at it

module-manager module test podman

Then open https://podman.lab1.makerfloss.eu — Cockpit, with the Podman page.

  • Reachable from the mgmt zone only. Not from the internet, by declaration.
  • You log in with your TAPPaaS identity — that is what the identity:identity dependency buys; no per-VM Linux passwords to hand out.

Where this module lives

Community/src/larsrossen/containers/podman/

Three homes for a module, all first-class:

Home For
TAPPaaS repo, by pull request modules the whole project should carry
Community repo yours, shared, no gatekeeping — today's podman
Private repo — e.g. forgejo.makerfloss.eu yours, not shared

Adding a repository is one site-manager repository add.


Your turn — identity on this TAPPaaS

people-manager user add <you> --email <you>@example.org \
    --roles user --groups <group>
people-manager reconcile          # preview
people-manager reconcile --apply  # push to Authentik

authentik-manager user-recovery-link <you>   # one-time URL: set your own password

One login per person, roles via groups. Nobody types a password into a chat window.

TODO: which group do participants land in?


Take it further

  • Develop a module — tappaas.org/generated/develop-a-module
  • Every json field — tappaas.org/generated/schemas
  • Zones and the access model — tappaas.org/generated/zones
  • Repository topology — tappaas.org/generated/design/cicd-git
  • This deck — slides.makerfloss.eu/tappaas/how-to/new-module

Pick an app you want on a sovereign box. Open an issue first — someone may already be packaging it.