--- marp: true theme: gaia class: invert paginate: true title: How to implement a TAPPaaS module description: 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 1. **What TAPPaaS is** — two diagrams, ten minutes, no deeper 2. **What a module actually is** — a json contract and three scripts 3. **Build one live** — a test 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 ```mermaid flowchart LR sat["satellite VPS
public IP · ingress
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 ```mermaid 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 ```bash 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 ```text 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 ```json { "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: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.` 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 ```bash # 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. ``` 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 ```bash 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 ```bash module-manager module test podman ``` Then open **`https://podman.`** — Cockpit, with the Podman page. - Reachable from the `mgmt` zone only. Not from the internet, by declaration. - Cockpit authenticates against **Linux accounts on the VM** — the cloud-init `tappaas` user has no password until someone sets one. `TODO: pre-create the demo login, or set the password live?` --- ## Where this module lives ```text 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 ```bash people-manager user add --email @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.