Sixteen slides built around the live demo: two orientation diagrams (site shape with environments/zones/satellite, and the pull-based GitOps repo topology), a condensed module anatomy anchored on the real podman.json from Community/src/larsrossen/containers/podman, the three demo beats (test environment, module add, prove it), and the identity hand-out. Mermaid subgraph titles collide with the node row under flowchart TB, so both diagrams use LR; _class directives repeat 'invert' because a local _class replaces the deck-level one rather than adding to it.
8.2 KiB
| marp | theme | class | paginate | title | description |
|---|---|---|---|---|---|
| true | gaia | invert | true | How to implement a TAPPaaS module | Live build of a Podman module — OrangeMaker session |
Getting a module onto TAPPaaS
Live build of a Podman container host
OrangeMaker · TODO: date
The plan
- What TAPPaaS is — two diagrams, ten minutes, no deeper
- What a module actually is — a json contract and three scripts
- Build one live — a test environment, then
podmaninto it - Prove it works — tests, then the web console
- 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["test · zone hacklab"]
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. |
| 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.
How code gets in: pull-based GitOps
flowchart RL
subgraph t["TAPPaaS repository"]
stable["stable"]
main["main"]
end
subgraph c["Community repository"]
cm["main"]
end
subgraph inst["Your TAPPaaS · tappaas-cicd"]
lt["clone of TAPPaaS"]
lc["clone of Community"]
end
lt -->|pull| stable
lc -->|pull| cm
Nothing pushes into your site. It pulls, on a schedule, and reconciles.
Managers: the verbs you will watch me type
module-manager module add|test|reconcile|modify|delete
environment-manager add|modify|reconcile
network-manager zone add|merge|reconcile
people-manager user add|modify · reconcile --apply
Admins drive verbs, never hand-edited JSON. Each manager owns one slice of desired state; controllers push it into OPNsense, Proxmox, the switch, Authentik.
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"],
"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: four 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:vmbuilt it from the Debian 13 cloud image - OS prep —
templates:debiandid apt + guest agent - A VLAN, an interface, DHCP, firewall rules — the zone came with the environment
https://podman.<domain>with a real certificate —network:proxy, one dependency- Nightly backup to PBS —
backup:vm - Scheduled updates and health reporting — the mothership
Six lines of json bought all of it.
Demo 1 — an environment of our own
# srvTest ships in the zone template; a fresh one keeps the demo self-contained
network-manager zone add hacklab --from-zone srv
environment-manager add test \
--display "Hackerspace test" \
--zone hacklab \
--domain test.<our-domain>
A tenant with its own VLAN, its own firewall posture, its own DNS names — and nothing in it can touch production.
TODO: our domain — and do we build the zone live or pre-bake it?
Demo 2 — install the module
module-manager module add podman --environment test
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.<domain> — Cockpit, with the Podman page.
- Reachable from the
mgmtzone only. Not from the internet, by declaration. - Cockpit authenticates against Linux accounts on the VM — the cloud-init
tappaasuser has no password until someone sets one.
TODO: pre-create the demo login, or set the password live?
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 | 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 orangemaker__users
people-manager reconcile # preview
people-manager reconcile --apply # push to Authentik
One login per person, roles via groups. TODO: which groups/roles do participants get?
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.