MakerFLOSS/slides/tappaas/how-to/new-module/index.md

290 lines
8.2 KiB
Markdown
Raw Normal View History

---
marp: true
theme: gaia
class: invert
paginate: true
title: How to implement a TAPPaaS module
description: Live build of a Podman module — OrangeMaker session
---
<style>
section { font-size: 26px; }
h1 { font-size: 1.5em; }
h2 { font-size: 1.15em; }
pre { font-size: 0.7em; line-height: 1.35; }
table { font-size: 0.78em; }
th, td { padding: 0.2em 0.55em; }
/* Unfinished content, loud on purpose: an unfinished deck should never be
presented by accident. Written in the markdown as `TODO: ...`. */
code.todo { color: #ff8a80; font-weight: 600; }
/* Mermaid renders at its natural size, which is far too small on a projector. */
div.mermaid { display: flex; justify-content: center; width: 100%; }
div.mermaid svg { width: 100% !important; height: auto !important; max-height: 500px; }
section.diagram h2 { margin-bottom: 0.1em; }
</style>
<!-- _paginate: false -->
# Getting a module onto TAPPaaS
Live build of a **Podman** container host
OrangeMaker · `TODO: date`
<!--
Slides are the map; the terminal is the territory. Everything here has a live
counterpart — keep the deck moving and spend the time in the shell.
-->
---
## 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.
---
<!-- _class: invert diagram -->
## The shape of a TAPPaaS site
```mermaid
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.
---
<!-- _class: invert diagram -->
## 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.<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
```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.<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?`
<!-- Show zones.json before/after, and the OPNsense interface appearing. -->
---
## 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.
<!-- Expect a few minutes. Good moment for questions. -->
---
## Demo 3 — prove it, then look at it
```bash
module-manager module test podman
```
Then open **`https://podman.<domain>`** — 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 <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?`
<!-- Do these live, one per participant, while the podman VM builds. -->
---
## 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.