view
This commit is contained in:
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Virtual Environment
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
|
||||||
|
# Generated diagram files
|
||||||
|
*.png
|
||||||
|
*.pdf
|
||||||
|
*.svg
|
||||||
|
*.gv
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
*.egg-info/
|
||||||
192
DEPLOYMENT_GUIDE.md
Normal file
192
DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# Deployment Guide - App Pipeline
|
||||||
|
|
||||||
|
Complete guide for deploying applications using the custom deployment pipeline with Gitea, Docker, and Traefik.
|
||||||
|
|
||||||
|
## 1. Create New Application
|
||||||
|
|
||||||
|
### 1.1 Gitea Repository
|
||||||
|
|
||||||
|
1. Log in to Gitea: https://git.appmodel.nl
|
||||||
|
2. Create a new repository:
|
||||||
|
- **Owner**: Tour
|
||||||
|
- **Name**: `viewer` (or your app name)
|
||||||
|
|
||||||
|
### 1.2 Generate Skeleton on Server
|
||||||
|
|
||||||
|
On the server, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apps-create viewer static-fe
|
||||||
|
```
|
||||||
|
|
||||||
|
This command:
|
||||||
|
- Sets up `/opt/apps/viewer` (attempts to clone from `git@git.appmodel.nl:Tour/viewer.git`)
|
||||||
|
- Generates a multi-stage Dockerfile for a Node-based static frontend
|
||||||
|
- Creates `~/infra/viewer/docker-compose.yml` with:
|
||||||
|
- Service `viewer`
|
||||||
|
- Connection to `traefik_net`
|
||||||
|
- Traefik route: `https://viewer.appmodel.nl`
|
||||||
|
|
||||||
|
## 2. Development & Build
|
||||||
|
|
||||||
|
On your development machine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone git@git.appmodel.nl:Tour/viewer.git
|
||||||
|
cd viewer
|
||||||
|
|
||||||
|
# Build your app as usual
|
||||||
|
npm install
|
||||||
|
npm run build # output goes to dist/
|
||||||
|
|
||||||
|
# Commit and push
|
||||||
|
git add .
|
||||||
|
git commit -m "First version"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The Dockerfile expects a `dist/` directory containing static files.
|
||||||
|
|
||||||
|
## 3. Deployment Pipeline
|
||||||
|
|
||||||
|
### 3.1 Manual Deploy with `app-deploy`
|
||||||
|
|
||||||
|
On the server, use the generic deploy command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
app-deploy viewer
|
||||||
|
```
|
||||||
|
|
||||||
|
This command performs:
|
||||||
|
1. `cd /opt/apps/viewer`
|
||||||
|
2. `git pull --ff-only`
|
||||||
|
3. `cd /home/tour/infra/viewer`
|
||||||
|
4. `docker compose up -d --build viewer`
|
||||||
|
|
||||||
|
Logs are saved to: `/var/log/app-deploy-viewer.log`
|
||||||
|
|
||||||
|
### 3.2 Automatic Deployment via Gitea Hook
|
||||||
|
|
||||||
|
Set up automatic deployment on every push:
|
||||||
|
|
||||||
|
1. In Gitea, go to repository `Tour/viewer`
|
||||||
|
2. Navigate to **Settings → Git Hooks**
|
||||||
|
3. Select **post-receive**
|
||||||
|
4. Add the following script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
/usr/local/bin/app-deploy viewer
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result**: Every `git push` to `Tour/viewer` automatically triggers a deployment.
|
||||||
|
|
||||||
|
## 4. Traefik & DNS Configuration
|
||||||
|
|
||||||
|
### Traefik Setup
|
||||||
|
|
||||||
|
Traefik runs in the traefik stack on the same server and manages:
|
||||||
|
- `git.appmodel.nl`
|
||||||
|
- `auction.appmodel.nl`
|
||||||
|
- `aupi.appmodel.nl`
|
||||||
|
- ... (new apps via labels)
|
||||||
|
|
||||||
|
### Auto-Generated Labels
|
||||||
|
|
||||||
|
The `apps-create` command automatically adds the correct Traefik labels:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.viewer.rule=Host(`viewer.appmodel.nl`)"
|
||||||
|
- "traefik.http.routers.viewer.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.viewer.tls=true"
|
||||||
|
- "traefik.http.routers.viewer.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.viewer.loadbalancer.server.port=80"
|
||||||
|
```
|
||||||
|
|
||||||
|
### DNS Configuration
|
||||||
|
|
||||||
|
Add a DNS record pointing to your server's public IP:
|
||||||
|
|
||||||
|
```
|
||||||
|
viewer.appmodel.nl → <server-public-ip>
|
||||||
|
```
|
||||||
|
|
||||||
|
Traefik + Let's Encrypt will automatically handle SSL certificate generation.
|
||||||
|
|
||||||
|
## 5. Future Application Types
|
||||||
|
|
||||||
|
The `apps-create` script currently supports:
|
||||||
|
|
||||||
|
- **`static-fe`** – Node build → Nginx → static frontend
|
||||||
|
|
||||||
|
### Planned Types
|
||||||
|
|
||||||
|
Future app types can be added:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python API
|
||||||
|
apps-create stats api-py
|
||||||
|
|
||||||
|
# Background worker/crawler
|
||||||
|
apps-create crawler worker-py
|
||||||
|
```
|
||||||
|
|
||||||
|
Each type will have:
|
||||||
|
- Custom Dockerfile template
|
||||||
|
- Standard `docker-compose.yml` configuration
|
||||||
|
- Same deployment pipeline: `app-deploy <name>`
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
### Create and Deploy New App
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On server: create skeleton
|
||||||
|
apps-create viewer static-fe
|
||||||
|
|
||||||
|
# On dev machine: develop and push
|
||||||
|
git clone git@git.appmodel.nl:Tour/viewer.git
|
||||||
|
cd viewer
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit"
|
||||||
|
git push
|
||||||
|
|
||||||
|
# On server: deploy (or auto-deploys via hook)
|
||||||
|
app-deploy viewer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Existing Infrastructure
|
||||||
|
|
||||||
|
| Service | URL | Description |
|
||||||
|
|---------|-----|-------------|
|
||||||
|
| Gitea | https://git.appmodel.nl | Git repository hosting |
|
||||||
|
| Auction | https://auction.appmodel.nl | Auction frontend |
|
||||||
|
| Aupi API | https://aupi.appmodel.nl | Auction backend API |
|
||||||
|
| Traefik | - | Reverse proxy & SSL |
|
||||||
|
|
||||||
|
### Log Locations
|
||||||
|
|
||||||
|
- Deployment logs: `/var/log/app-deploy-<app-name>.log`
|
||||||
|
- Docker logs: `docker compose logs -f <service-name>`
|
||||||
|
|
||||||
|
### Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View deployment logs
|
||||||
|
tail -f /var/log/app-deploy-viewer.log
|
||||||
|
|
||||||
|
# View container logs
|
||||||
|
cd ~/infra/viewer
|
||||||
|
docker compose logs -f viewer
|
||||||
|
|
||||||
|
# Restart service
|
||||||
|
docker compose restart viewer
|
||||||
|
|
||||||
|
# Rebuild without cache
|
||||||
|
docker compose up -d --build --no-cache viewer
|
||||||
|
```
|
||||||
82
README.md
Normal file
82
README.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# Network Architecture Diagrams
|
||||||
|
|
||||||
|
Python scripts to generate network architecture diagrams using the [Diagrams](https://diagrams.mingrammer.com/) library.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.8+
|
||||||
|
- Graphviz ([installation guide](https://graphviz.org/download/))
|
||||||
|
|
||||||
|
### Installing Graphviz
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
```bash
|
||||||
|
choco install graphviz
|
||||||
|
# or download from https://graphviz.org/download/
|
||||||
|
```
|
||||||
|
|
||||||
|
**macOS:**
|
||||||
|
```bash
|
||||||
|
brew install graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux:**
|
||||||
|
```bash
|
||||||
|
sudo apt-get install graphviz # Debian/Ubuntu
|
||||||
|
sudo yum install graphviz # RHEL/CentOS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Create a virtual environment:
|
||||||
|
```bash
|
||||||
|
python -m venv .venv
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Activate the virtual environment:
|
||||||
|
```bash
|
||||||
|
# Windows
|
||||||
|
.venv\Scripts\activate
|
||||||
|
|
||||||
|
# macOS/Linux
|
||||||
|
source .venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install dependencies:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the diagram generation scripts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate LAN architecture diagram
|
||||||
|
python lan_architecture.py
|
||||||
|
|
||||||
|
# Generate main diagram
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Output files will be generated in the current directory as PNG images.
|
||||||
|
|
||||||
|
## Available Diagrams
|
||||||
|
|
||||||
|
- `lan_architecture.py` - Home Lab / Auction Stack Architecture diagram
|
||||||
|
- `main.py` - Network architecture diagram
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
To deploy or share this project:
|
||||||
|
|
||||||
|
1. Ensure Graphviz is installed on the target system
|
||||||
|
2. Clone the repository
|
||||||
|
3. Follow the setup instructions above
|
||||||
|
4. Run the desired diagram script
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Generated diagram files (`.png`, `.gv`) are excluded from version control
|
||||||
|
- The diagrams use a left-to-right (`LR`) layout direction
|
||||||
|
- Output files are saved with `show=False` to prevent automatic opening
|
||||||
31
build-pipeline.md
Normal file
31
build-pipeline.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Appmodel Home Lab – Build & Deploy Pipeline
|
||||||
|
|
||||||
|
Dit document beschrijft hoe een nieuwe applicatie in het home lab wordt aangemaakt en hoe de build- & deploy-pipeline werkt.
|
||||||
|
|
||||||
|
## Overzicht
|
||||||
|
|
||||||
|
- **Broncode**: Gitea (`https://git.appmodel.nl`)
|
||||||
|
- **Build & runtime**: Docker containers op netwerk `traefik_net`
|
||||||
|
- **Routing & TLS**: Traefik (`https://traefik.appmodel.nl`)
|
||||||
|
- **Automatische deploy**: Gitea `post-receive` hooks → `app-deploy <app>`
|
||||||
|
|
||||||
|
## Pipeline in één diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Dev[💻 Dev machine\nVS Code / Git] -->|git push| Gitea[📚 Gitea\nTour/<app>]
|
||||||
|
|
||||||
|
subgraph Server[🏠 Home lab server\n192.168.1.159]
|
||||||
|
Gitea --> Hook[🔔 post-receive hook\n/app-deploy <app>]
|
||||||
|
|
||||||
|
Hook --> Deploy[⚙️ app-deploy <app>\n/git pull + docker compose up -d --build <app>]
|
||||||
|
|
||||||
|
subgraph Docker[🐳 Docker / traefik_net]
|
||||||
|
AppC[🧱 App container\n<app>.appmodel.nl]
|
||||||
|
Traefik[🚦 Traefik\nReverse Proxy]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Deploy --> AppC
|
||||||
|
Traefik --> AppC
|
||||||
|
Client[🌐 Browser / API client] -->|https://<app>.appmodel.nl| Traefik
|
||||||
218
lab/dia-kimi.html
Normal file
218
lab/dia-kimi.html
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Home-Lab diagram – Mermaid + Kroki (Graphviz)</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style>
|
||||||
|
:root{--bg:#f7f9fc;--text:#222;--accent:#0d6efd}
|
||||||
|
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial;font-size:14px;background:var(--bg);color:var(--text)}
|
||||||
|
header{background:var(--accent);color:#fff;padding:.6rem 1rem;font-size:1.1rem;font-weight:600}
|
||||||
|
.wrap{display:flex;height:calc(100vh - 40px)}
|
||||||
|
.panel{flex:1;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid #ddd}
|
||||||
|
.panel:last-child{border:none}
|
||||||
|
h3{margin:.4rem .6rem;font-size:1rem}
|
||||||
|
.btn{margin:.2rem .6rem;padding:.3rem .6rem;border:1px solid #ccc;border-radius:4px;background:#fff;cursor:pointer}
|
||||||
|
.btn:hover{background:#eee}
|
||||||
|
#editor{flex:1}
|
||||||
|
.diagram{flex:2;background:#fff;padding:.5rem;overflow:auto}
|
||||||
|
svg{max-width:100%;height:auto}
|
||||||
|
/* mermaid theme tweaks */
|
||||||
|
.mermaid{height:100%;display:flex;align-items:center;justify-content:center}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- ========= 1. LIBRARIES ========= -->
|
||||||
|
<!-- Monaco editor -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/monaco-editor@0.44.0/min/vs/loader.js"></script>
|
||||||
|
<!-- Mermaid -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
|
||||||
|
<!-- Kroki client (tiny wrapper) -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/kroki-client@1/dist/kroki-client.min.js"></script>
|
||||||
|
<!-- html2canvas for PNG export -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>🏠 Home-Lab diagram – editable in browser (localStorage auto-saved)</header>
|
||||||
|
|
||||||
|
<div class="wrap">
|
||||||
|
<!-- ---- LEFT: EDITOR ---- -->
|
||||||
|
<div class="panel">
|
||||||
|
<h3>Source (Mermaid syntax)</h3>
|
||||||
|
<div id="editor"></div>
|
||||||
|
<div style="padding:.4rem .6rem">
|
||||||
|
<button class="btn" onclick="render()">▶ Render both</button>
|
||||||
|
<button class="btn" onclick="savePNG()">💾 Save PNG</button>
|
||||||
|
<button class="btn" onclick="saveSVG()">💾 Save SVG</button>
|
||||||
|
<label class="btn">
|
||||||
|
<input type="checkbox" id="dark"> dark
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ---- MIDDLE: MERMAID ---- -->
|
||||||
|
<div class="panel">
|
||||||
|
<h3>Mermaid render</h3>
|
||||||
|
<div id="mermaid" class="diagram"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ---- RIGHT: KROKI / GRAPHVIZ ---- -->
|
||||||
|
<div class="panel">
|
||||||
|
<h3>Kroki (Graphviz) render</h3>
|
||||||
|
<div id="kroki" class="diagram"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/* ========= 2. DEFAULT SOURCE ========= */
|
||||||
|
const DEFAULT = `flowchart TD
|
||||||
|
%% ---------- colours ----------
|
||||||
|
classDef internet fill:#e1f5ff,stroke:#007bff
|
||||||
|
classDef router fill:#fff3cd,stroke:#ffc107
|
||||||
|
classDef lan fill:#f8f9ff,stroke:#6c757d,stroke-width:2px
|
||||||
|
classDef core fill:#ffe6e6,stroke:#dc3545
|
||||||
|
classDef infra fill:#e6ffe6,stroke:#28a745
|
||||||
|
classDef worker fill:#f0e6ff,stroke:#6f42c1
|
||||||
|
classDef iot fill:#fff9e6,stroke:#fd7e14
|
||||||
|
|
||||||
|
%% ---------- nodes ----------
|
||||||
|
internet(🌐 Internet / Cloud):::internet
|
||||||
|
router{{🛜 Router<br/>hub.lan<br/>192.168.1.1}}:::router
|
||||||
|
|
||||||
|
subgraph LAN["🏠 LAN 192.168.1.0/24"]:::lan
|
||||||
|
subgraph CORE["💻 Core server<br/>192.168.1.159"]:::core
|
||||||
|
traefik[🚦 Traefik]:::core
|
||||||
|
gitea[📚 Gitea]:::core
|
||||||
|
dokku[🐳 Dokku]:::core
|
||||||
|
auction[🧱 Auction stack]:::core
|
||||||
|
mi50[🧠 MI50 / Ollama]:::core
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph INFRA["🧭 Infra & DNS<br/>192.168.1.163"]:::infra
|
||||||
|
adguard[🛡️ AdGuard]:::infra
|
||||||
|
artifactory[📦 Artifactory]:::infra
|
||||||
|
end
|
||||||
|
|
||||||
|
ha[🏡 Home Assistant<br/>192.168.1.193]:::infra
|
||||||
|
atlas[🧱 Atlas<br/>192.168.1.100]:::worker
|
||||||
|
|
||||||
|
iot1[📺 IoT-1]:::iot
|
||||||
|
iot2[📟 IoT-2]:::iot
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph TETHER["📶 Tether 192.168.137.0/24"]:::lan
|
||||||
|
hermes[🛰️ Hermes]:::worker
|
||||||
|
plato[🛰️ Plato]:::worker
|
||||||
|
end
|
||||||
|
|
||||||
|
dev[👨💻 Dev laptop]:::internet
|
||||||
|
|
||||||
|
%% ---------- edges ----------
|
||||||
|
internet ==> router
|
||||||
|
router --> CORE
|
||||||
|
router --> INFRA
|
||||||
|
router --> ha
|
||||||
|
router --> atlas
|
||||||
|
router --> iot1
|
||||||
|
router --> iot2
|
||||||
|
|
||||||
|
dev ==> gitea
|
||||||
|
dev ==> dokku
|
||||||
|
dev ==> mi50
|
||||||
|
|
||||||
|
traefik --> gitea
|
||||||
|
traefik --> auction
|
||||||
|
traefik --> dokku
|
||||||
|
|
||||||
|
CORE -.->|DNS| adguard
|
||||||
|
ha -.->|DNS| adguard
|
||||||
|
atlas-.->|DNS| adguard
|
||||||
|
hermes-.->|DNS| adguard
|
||||||
|
plato-.->|DNS| adguard
|
||||||
|
|
||||||
|
CORE === TETHER
|
||||||
|
`;
|
||||||
|
|
||||||
|
/* ========= 3. EDITOR SETUP ========= */
|
||||||
|
let editor;
|
||||||
|
require.config({paths:{vs:'https://cdn.jsdelivr.net/npm/monaco-editor@0.44.0/min/vs'}});
|
||||||
|
require(['vs/editor/editor.main'], () => {
|
||||||
|
editor = monaco.editor.create(document.getElementById('editor'), {
|
||||||
|
value: localStorage.getItem('diagramSrc') || DEFAULT,
|
||||||
|
language: 'markdown',
|
||||||
|
theme: 'vs-dark',
|
||||||
|
minimap: {enabled: false},
|
||||||
|
wordWrap: 'on'
|
||||||
|
});
|
||||||
|
editor.onDidChangeModelContent(() => {
|
||||||
|
localStorage.setItem('diagramSrc', editor.getValue());
|
||||||
|
});
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ========= 4. RENDERERS ========= */
|
||||||
|
mermaid.initialize({startOnLoad: false, theme: 'default'});
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
const src = editor.getValue();
|
||||||
|
// 4a – mermaid
|
||||||
|
document.getElementById('mermaid').innerHTML = '<div class="mermaid">'+src+'</div>';
|
||||||
|
mermaid.init();
|
||||||
|
// 4b – kroki graphviz
|
||||||
|
Kroki.render('graphviz', dotFromMermaid(src)).then(svg => {
|
||||||
|
document.getElementById('kroki').innerHTML = svg;
|
||||||
|
}).catch(err => {
|
||||||
|
document.getElementById('kroki').innerHTML = '<pre>'+err+'</pre>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* crude converter – good enough for this topology */
|
||||||
|
function dotFromMermaid(m) {
|
||||||
|
let dot = 'digraph G {\nbgcolor=transparent;rankdir=TB;node [shape=rect,style=rounded];\n';
|
||||||
|
const lines = m.split('\n');
|
||||||
|
let inSub = false;
|
||||||
|
lines.forEach(l => {
|
||||||
|
l = l.trim();
|
||||||
|
if (l.startsWith('subgraph')) {
|
||||||
|
const name = (l.match(/subgraph\s+(\w+)/) || [, 'cluster'])[1];
|
||||||
|
dot += 'subgraph '+name+' {\nlabel="'+l.split('"')[1]+'";\nstyle=filled;fillcolor=lightgrey;\n';
|
||||||
|
inSub = true;
|
||||||
|
} else if (l === 'end') {
|
||||||
|
dot += '}\n';
|
||||||
|
inSub = false;
|
||||||
|
} else if (l.includes('[') && l.includes(']')) {
|
||||||
|
const id = l.split('[')[0].trim();
|
||||||
|
const label = (l.match(/\[(.*?)\]/) || [, id])[1];
|
||||||
|
dot += id + ' [label="' + label.replace(/:::.*$/,'') + '"];\n';
|
||||||
|
} else if (l.includes('-->') || l.includes('==>') || l.includes('-.->')) {
|
||||||
|
const arr = l.replace(/[~=>\-.]+/g,'->').split('->').map(x=>x.trim()).filter(Boolean);
|
||||||
|
if (arr.length === 2) dot += arr[0] + ' -> ' + arr[1] + ';\n';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dot += '}';
|
||||||
|
return dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========= 5. EXPORT ========= */
|
||||||
|
function savePNG() {
|
||||||
|
html2canvas(document.querySelector('#mermaid svg')).then(canvas => {
|
||||||
|
download(canvas.toDataURL(), 'home-lab.png');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function saveSVG() {
|
||||||
|
const svg = document.querySelector('#mermaid svg');
|
||||||
|
const url = 'data:image/svg+xml;charset=utf-8,'+encodeURIComponent(svg.outerHTML);
|
||||||
|
download(url, 'home-lab.svg');
|
||||||
|
}
|
||||||
|
function download(href, name) {
|
||||||
|
const a = Object.assign(document.createElement('a'), {href, download: name});
|
||||||
|
document.body.appendChild(a); a.click(); a.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dark toggle */
|
||||||
|
document.getElementById('dark').onchange = e => {
|
||||||
|
document.body.style.background = e.target.checked ? '#121212' : '#f7f9fc';
|
||||||
|
document.body.style.color = e.target.checked ? '#eee' : '#222';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
121
lan_architecture.py
Normal file
121
lan_architecture.py
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
from diagrams import Diagram, Cluster, Edge
|
||||||
|
from diagrams.onprem.network import Internet
|
||||||
|
from diagrams.onprem.compute import Server
|
||||||
|
from diagrams.onprem.iac import Ansible
|
||||||
|
from diagrams.generic.network import Router, Switch
|
||||||
|
from diagrams.generic.device import Mobile, Tablet
|
||||||
|
from diagrams.generic.blank import Blank
|
||||||
|
from diagrams.onprem.client import Users
|
||||||
|
from diagrams.onprem.container import Docker
|
||||||
|
from diagrams.custom import Custom
|
||||||
|
|
||||||
|
# Tip: run this in a venv:
|
||||||
|
# pip install diagrams graphviz
|
||||||
|
|
||||||
|
with Diagram("Home Lab / Auction Stack Architecture", show=False, filename="home_lab_architecture", direction="LR"):
|
||||||
|
internet = Internet("Internet / Cloud")
|
||||||
|
|
||||||
|
dev = Users("Dev laptop(s)\nWindows / WSL")
|
||||||
|
|
||||||
|
# -------------------- LAN 192.168.1.x --------------------
|
||||||
|
with Cluster("LAN 192.168.1.0/24"):
|
||||||
|
router = Router("hub.lan\n192.168.1.1\nRouter / Gateway")
|
||||||
|
|
||||||
|
# -------- Core server / desktop (Tour / hephaestus / dokku / ollama) --------
|
||||||
|
with Cluster("Core server / desktop\nTour / hephaestus / dokku.lan / ollama.lan\n192.168.1.159"):
|
||||||
|
core_os = Server("Ubuntu host")
|
||||||
|
|
||||||
|
traefik = Docker("Traefik\nReverse Proxy")
|
||||||
|
gitea = Docker("Gitea\n git.appmodel.nl")
|
||||||
|
dokku = Docker("Dokku\nPaaS / app hosting")
|
||||||
|
auction_fe = Docker("Auction Frontend\n auction.appmodel.nl")
|
||||||
|
aupi_be = Docker("Aupi API Backend\n aupi.appmodel.nl")
|
||||||
|
mi50 = Server("MI50 GPU / Ollama\nAI workloads")
|
||||||
|
|
||||||
|
# -------- Infra & DNS (odroid / dns.lan) --------
|
||||||
|
with Cluster("Infra & DNS\nodroid / dns.lan\n192.168.1.163"):
|
||||||
|
dns_host = Server("Odroid host")
|
||||||
|
adguard = Docker("AdGuard Home\nDNS / *.lan / *.appmodel.nl")
|
||||||
|
artifactory = Docker("Artifactory (future)")
|
||||||
|
runner = Docker("CI / Build runner (future)")
|
||||||
|
|
||||||
|
# -------- Home Assistant --------
|
||||||
|
with Cluster("Home Automation\nha.lan\n192.168.1.193"):
|
||||||
|
ha_host = Server("HomeAssistant host")
|
||||||
|
hass = Docker("Home Assistant")
|
||||||
|
|
||||||
|
# -------- Extra node / worker --------
|
||||||
|
atlas = Server("atlas.lan\n192.168.1.100\n(extra node / worker)")
|
||||||
|
|
||||||
|
# -------- IoT / devices --------
|
||||||
|
with Cluster("IoT / Clients"):
|
||||||
|
iot_hof = Tablet("hof-E402NA\n192.168.1.214")
|
||||||
|
iot_s380 = Tablet("S380HB\n192.168.1.59")
|
||||||
|
iot_ecb5 = Tablet("ecb5faa56c90\n192.168.1.49")
|
||||||
|
iot_unknown = Tablet("Unknown\n192.168.1.240")
|
||||||
|
|
||||||
|
# -------------------- Tether subnet 192.168.137.x --------------------
|
||||||
|
with Cluster("Tether subnet 192.168.137.0/24"):
|
||||||
|
hermes = Server("hermes.lan\n192.168.137.239\nworker / node")
|
||||||
|
plato = Server("plato.lan\n192.168.137.163\nworker / node")
|
||||||
|
|
||||||
|
# -------------------- Edges / flows --------------------
|
||||||
|
|
||||||
|
# Internet naar router + DNS host
|
||||||
|
internet >> router
|
||||||
|
internet >> dns_host
|
||||||
|
|
||||||
|
# Dev naar Gitea / Traefik / Dokku
|
||||||
|
dev >> Edge(label="git / HTTPS") >> traefik
|
||||||
|
dev >> Edge(label="SSH / HTTPS") >> gitea
|
||||||
|
dev >> Edge(label="Dokku deploys") >> dokku
|
||||||
|
|
||||||
|
# Router naar alle LAN-nodes
|
||||||
|
router >> core_os
|
||||||
|
router >> dns_host
|
||||||
|
router >> ha_host
|
||||||
|
router >> atlas
|
||||||
|
router >> iot_hof
|
||||||
|
router >> iot_s380
|
||||||
|
router >> iot_ecb5
|
||||||
|
router >> iot_unknown
|
||||||
|
|
||||||
|
# Core server services
|
||||||
|
core_os >> traefik
|
||||||
|
core_os >> gitea
|
||||||
|
core_os >> dokku
|
||||||
|
core_os >> auction_fe
|
||||||
|
core_os >> aupi_be
|
||||||
|
core_os >> mi50
|
||||||
|
|
||||||
|
# Infra/DNS services
|
||||||
|
dns_host >> adguard
|
||||||
|
dns_host >> artifactory
|
||||||
|
dns_host >> runner
|
||||||
|
|
||||||
|
# Home Assistant
|
||||||
|
ha_host >> hass
|
||||||
|
|
||||||
|
# DNS-queries
|
||||||
|
core_os >> Edge(label="DNS") >> adguard
|
||||||
|
ha_host >> Edge(label="DNS") >> adguard
|
||||||
|
atlas >> Edge(label="DNS") >> adguard
|
||||||
|
hermes >> Edge(label="DNS") >> adguard
|
||||||
|
plato >> Edge(label="DNS") >> adguard
|
||||||
|
|
||||||
|
# Web traffic / reverse proxy flows
|
||||||
|
internet >> Edge(label="HTTP/HTTPS") >> traefik
|
||||||
|
traefik >> Edge(label="git.appmodel.nl") >> gitea
|
||||||
|
traefik >> Edge(label="auction.appmodel.nl") >> auction_fe
|
||||||
|
traefik >> Edge(label="aupi.appmodel.nl") >> aupi_be
|
||||||
|
traefik >> Edge(label="dokku.lan / apps") >> dokku
|
||||||
|
|
||||||
|
# App-level flow
|
||||||
|
auction_fe >> Edge(label="REST API") >> aupi_be
|
||||||
|
|
||||||
|
# AI workloads
|
||||||
|
dev >> Edge(label="LLM / Tuning / Inference") >> mi50
|
||||||
|
|
||||||
|
# Tether workers verbonden met core (bv. jobs / agents)
|
||||||
|
core_os >> Edge(label="jobs / ssh") >> hermes
|
||||||
|
core_os >> Edge(label="jobs / ssh") >> plato
|
||||||
159
main.py
Normal file
159
main.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
from graphviz import Digraph
|
||||||
|
|
||||||
|
def make_network_diagram(output_name: str = "network-architecture"):
|
||||||
|
g = Digraph(
|
||||||
|
"network",
|
||||||
|
filename=f"{output_name}.gv",
|
||||||
|
format="png",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Globale stijl
|
||||||
|
g.attr(rankdir="LR", fontname="Segoe UI")
|
||||||
|
|
||||||
|
# ---------- WAN / Internet ----------
|
||||||
|
with g.subgraph(name="cluster_wan") as wan:
|
||||||
|
wan.attr(
|
||||||
|
label="🌐 Internet / Cloud",
|
||||||
|
style="rounded",
|
||||||
|
color="lightgrey",
|
||||||
|
fontsize="16",
|
||||||
|
)
|
||||||
|
wan.node("extDNS", "📡 Public DNS", shape="rectangle")
|
||||||
|
wan.node("extGit", "☁️ Externe registries / Git\n(GitHub / Docker Hub)", shape="rectangle")
|
||||||
|
|
||||||
|
# ---------- LAN 192.168.1.0/24 ----------
|
||||||
|
with g.subgraph(name="cluster_lan") as lan:
|
||||||
|
lan.attr(
|
||||||
|
label="🏠 LAN 192.168.1.0/24",
|
||||||
|
style="rounded",
|
||||||
|
color="lightgrey",
|
||||||
|
fontsize="16",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Router / gateway
|
||||||
|
lan.node(
|
||||||
|
"hub",
|
||||||
|
"🛜 Router / Gateway\nhub.lan\n192.168.1.1",
|
||||||
|
shape="rectangle",
|
||||||
|
style="filled",
|
||||||
|
fillcolor="#f0f0ff",
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- Core server / desktop ----
|
||||||
|
with lan.subgraph(name="cluster_core") as core:
|
||||||
|
core.attr(
|
||||||
|
label="💻 Hoofdserver / Desktop\nTour / hephaestus / ollama / dokku.lan\n192.168.1.159",
|
||||||
|
style="rounded",
|
||||||
|
color="#aaccee",
|
||||||
|
)
|
||||||
|
core.node("traefik", "🚦 Traefik\nReverse Proxy", shape="rectangle")
|
||||||
|
core.node("gitea", "📚 Gitea\ngit.appmodel.nl", shape="rectangle")
|
||||||
|
core.node("dokku", "🐳 Dokku\nPaaS / build", shape="rectangle")
|
||||||
|
core.node("auctionFE", "🧱 Auction Frontend\nauction.appmodel.nl", shape="rectangle")
|
||||||
|
core.node("aupiAPI", "🧱 Auction Backend API\naupi.appmodel.nl", shape="rectangle")
|
||||||
|
core.node("mi50", "🧠 MI50 / Ollama\nAI workloads", shape="rectangle")
|
||||||
|
|
||||||
|
# Aanvulling: monitoring / logging
|
||||||
|
core.node("monitoring", "📈 Monitoring / Logging\nPrometheus / Loki / Grafana", shape="rectangle")
|
||||||
|
|
||||||
|
# ---- Infra & DNS ----
|
||||||
|
with lan.subgraph(name="cluster_infra_dns") as infra:
|
||||||
|
infra.attr(
|
||||||
|
label="🧭 Infra & DNS\nodroid / dns.lan\n192.168.1.163",
|
||||||
|
style="rounded",
|
||||||
|
color="#aaddaa",
|
||||||
|
)
|
||||||
|
infra.node("adguard", "🧭 AdGuard Home\nDNS / *.lan / *.appmodel.nl", shape="rectangle")
|
||||||
|
infra.node("artifactory", "📦 Artifactory", shape="rectangle")
|
||||||
|
infra.node("runner", "⚙️ Build runners\nCI/CD", shape="rectangle")
|
||||||
|
|
||||||
|
# ---- Home Automation ----
|
||||||
|
with lan.subgraph(name="cluster_ha") as ha:
|
||||||
|
ha.attr(
|
||||||
|
label="🏡 Home Automation\nha.lan\n192.168.1.193",
|
||||||
|
style="rounded",
|
||||||
|
color="#ffddaa",
|
||||||
|
)
|
||||||
|
ha.node("hass", "🏠 Home Assistant", shape="rectangle")
|
||||||
|
|
||||||
|
# Overige LAN-hosts / IoT
|
||||||
|
lan.node("atlas", "🧱 atlas.lan\n192.168.1.100", shape="rectangle")
|
||||||
|
lan.node("iot1", "📺 hof-E402NA\n192.168.1.214", shape="rectangle")
|
||||||
|
lan.node("iot2", "🎧 S380HB\n192.168.1.59", shape="rectangle")
|
||||||
|
lan.node("iot3", "📟 ecb5faa56c90\n192.168.1.49", shape="rectangle")
|
||||||
|
lan.node("iot4", "❓ Unknown\n192.168.1.240", shape="rectangle")
|
||||||
|
|
||||||
|
# ---------- Tether subnet ----------
|
||||||
|
with g.subgraph(name="cluster_tether") as tether:
|
||||||
|
tether.attr(
|
||||||
|
label="📶 Tether subnet 192.168.137.0/24",
|
||||||
|
style="rounded",
|
||||||
|
color="lightgrey",
|
||||||
|
fontsize="16",
|
||||||
|
)
|
||||||
|
tether.node("hermes", "🛰️ hermes.lan\n192.168.137.239\nworker / node", shape="rectangle")
|
||||||
|
tether.node("plato", "🛰️ plato.lan\n192.168.137.163\nworker / node", shape="rectangle")
|
||||||
|
|
||||||
|
# ---------- Externe gebruikers (aanvulling) ----------
|
||||||
|
g.node(
|
||||||
|
"users",
|
||||||
|
"👨💻 Developers / Users\nlaptops / mobiel",
|
||||||
|
shape="rectangle",
|
||||||
|
style="dashed",
|
||||||
|
)
|
||||||
|
|
||||||
|
# ==================== VERBINDINGEN ====================
|
||||||
|
|
||||||
|
# Basis LAN connecties (ongeveer jouw '---' links)
|
||||||
|
for target in ["core", "infraDNS", "ha", "atlas", "iot1", "iot2", "iot3", "iot4"]:
|
||||||
|
# We linken naar representatieve node binnen subgraph
|
||||||
|
if target == "core":
|
||||||
|
g.edge("hub", "traefik", dir="both", label="LAN")
|
||||||
|
elif target == "infraDNS":
|
||||||
|
g.edge("hub", "adguard", dir="both", label="LAN")
|
||||||
|
elif target == "ha":
|
||||||
|
g.edge("hub", "hass", dir="both", label="LAN")
|
||||||
|
else:
|
||||||
|
g.edge("hub", target, dir="both", label="LAN")
|
||||||
|
|
||||||
|
# WAN koppeling
|
||||||
|
g.edge("hub", "extDNS", label="📶 Internet")
|
||||||
|
g.edge("adguard", "extDNS", label="Upstream DNS")
|
||||||
|
|
||||||
|
# DNS-resolutie (core / ha / atlas / tether -> AdGuard)
|
||||||
|
for client in ["traefik", "hass", "atlas", "hermes", "plato"]:
|
||||||
|
g.edge(client, "adguard", label="DNS", style="dashed")
|
||||||
|
|
||||||
|
# Websites / reverse proxy
|
||||||
|
g.edge("extDNS", "traefik", label="DNS → Traefik")
|
||||||
|
g.edge("traefik", "gitea", label="HTTP(S)")
|
||||||
|
g.edge("traefik", "auctionFE", label="HTTP(S)")
|
||||||
|
g.edge("traefik", "aupiAPI", label="HTTP(S)")
|
||||||
|
g.edge("traefik", "dokku", label="Apps / Deploy")
|
||||||
|
|
||||||
|
# App flow
|
||||||
|
g.edge("auctionFE", "aupiAPI", label="API calls")
|
||||||
|
g.edge("aupiAPI", "adguard", label="DNS lookups", style="dashed")
|
||||||
|
|
||||||
|
# AI workloads
|
||||||
|
g.edge("traefik", "mi50", label="AI / inference", style="dotted")
|
||||||
|
|
||||||
|
# Tether workers
|
||||||
|
g.edge("traefik", "hermes", dir="both", label="Jobs / tasks")
|
||||||
|
g.edge("traefik", "plato", dir="both", label="Jobs / tasks")
|
||||||
|
|
||||||
|
# Monitoring / logging (aanvulling)
|
||||||
|
for observed in ["traefik", "gitea", "dokku", "auctionFE", "aupiAPI", "mi50", "adguard", "atlas", "hass"]:
|
||||||
|
g.edge(observed, "monitoring", style="dotted", label="metrics / logs")
|
||||||
|
|
||||||
|
# Developers / gebruikers
|
||||||
|
g.edge("users", "traefik", label="HTTPS")
|
||||||
|
g.edge("users", "gitea", style="dashed", label="Git / HTTP")
|
||||||
|
|
||||||
|
# Genereer bestanden (PNG + .gv)
|
||||||
|
g.render(cleanup=True)
|
||||||
|
print(f"Diagram gegenereerd als {output_name}.png")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
make_network_diagram()
|
||||||
107
public/dia.html
Normal file
107
public/dia.html
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="nl">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Netwerk architectuur</title>
|
||||||
|
<!-- Mermaid via CDN -->
|
||||||
|
<script type="module">
|
||||||
|
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
||||||
|
mermaid.initialize({ startOnLoad: true, theme: "default" });
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body { font-family: system-ui, sans-serif; margin: 0; padding: 1rem; }
|
||||||
|
.mermaid { max-width: 100%; overflow: auto; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Netwerk architectuur</h1>
|
||||||
|
|
||||||
|
<div class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
|
||||||
|
%% ============ Internet ============
|
||||||
|
subgraph WAN[🌐 Internet / Cloud]
|
||||||
|
extDNS[(📡 Public DNS)]
|
||||||
|
extGit[(☁️ Externe registries / Git)]
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ============ LAN 192.168.1.x ============
|
||||||
|
subgraph LAN[🏠 LAN 192.168.1.0/24]
|
||||||
|
hub[🛜 Router / Gateway\nhub.lan\n192.168.1.1]
|
||||||
|
|
||||||
|
subgraph core[💻 Hoofdserver / Desktop\nTour / hephaestus / ollama / dokku.lan\n192.168.1.159]
|
||||||
|
traefik[🚦 Traefik\nReverse Proxy]
|
||||||
|
gitea[📚 Gitea\n git.appmodel.nl]
|
||||||
|
dokku[🐳 Dokku\nPaaS / build]
|
||||||
|
auctionFE[🧱 Auction Frontend\n auction.appmodel.nl]
|
||||||
|
aupiAPI[🧱 Auction Backend API\n aupi.appmodel.nl]
|
||||||
|
mi50[🧠 MI50 / Ollama\nAI workloads]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph infraDNS[🧭 Infra & DNS\nodroid / dns.lan\n192.168.1.163]
|
||||||
|
adguard[🧭 AdGuard Home\nDNS / *.lan / *.appmodel.nl]
|
||||||
|
artifactory[📦 Artifactory]
|
||||||
|
runner[⚙️ Build runners]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph ha[🏡 Home Automation\nha.lan\n192.168.1.193]
|
||||||
|
hass[🏠 Home Assistant]
|
||||||
|
end
|
||||||
|
|
||||||
|
atlas[🧱 atlas.lan\n192.168.1.100\n]
|
||||||
|
|
||||||
|
iot1[📺 hof-E402NA\n192.168.1.214]
|
||||||
|
iot2[🎧 S380HB\n192.168.1.59]
|
||||||
|
iot3[📟 ecb5faa56c90\n192.168.1.49]
|
||||||
|
iot4[❓ Unknown\n192.168.1.240]
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ============ Tether subnet ============
|
||||||
|
subgraph TETHER[📶 Tether subnet 192.168.137.0/24]
|
||||||
|
hermes[🛰️ hermes.lan\n192.168.137.239\nworker / node]
|
||||||
|
plato[🛰️ plato.lan\n192.168.137.163\nworker / node]
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ============ Verkeer ============
|
||||||
|
|
||||||
|
%% Basis LAN connecties
|
||||||
|
hub --- core
|
||||||
|
hub --- infraDNS
|
||||||
|
hub --- ha
|
||||||
|
hub --- atlas
|
||||||
|
hub --- iot1
|
||||||
|
hub --- iot2
|
||||||
|
hub --- iot3
|
||||||
|
hub --- iot4
|
||||||
|
|
||||||
|
%% WAN koppeling
|
||||||
|
hub --> WAN
|
||||||
|
infraDNS --> WAN
|
||||||
|
|
||||||
|
%% DNS-resolutie
|
||||||
|
core --> adguard
|
||||||
|
ha --> adguard
|
||||||
|
atlas --> adguard
|
||||||
|
TETHER --> adguard
|
||||||
|
|
||||||
|
%% Websites / reverse proxy
|
||||||
|
extDNS --> traefik
|
||||||
|
traefik --> gitea
|
||||||
|
traefik --> auctionFE
|
||||||
|
traefik --> aupiAPI
|
||||||
|
traefik --> dokku
|
||||||
|
|
||||||
|
%% App flow
|
||||||
|
auctionFE --> aupiAPI
|
||||||
|
aupiAPI --> adguard
|
||||||
|
|
||||||
|
%% AI workloads
|
||||||
|
core --> mi50
|
||||||
|
|
||||||
|
%% Tether workers
|
||||||
|
core --- TETHER
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
141
readme-pipe.md
Normal file
141
readme-pipe.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
1. Nieuwe app aanmaken
|
||||||
|
1.1 Gitea repo
|
||||||
|
|
||||||
|
Log in op Gitea: https://git.appmodel.nl
|
||||||
|
|
||||||
|
Maak een nieuwe repo aan, bijvoorbeeld:
|
||||||
|
|
||||||
|
Owner: Tour
|
||||||
|
|
||||||
|
Name: viewer
|
||||||
|
|
||||||
|
1.2 Skeleton genereren op de server
|
||||||
|
|
||||||
|
Op de server:
|
||||||
|
|
||||||
|
apps-create viewer static-fe
|
||||||
|
|
||||||
|
|
||||||
|
Dit doet:
|
||||||
|
|
||||||
|
/opt/apps/viewer klaarzetten (proberen te clonen uit git@git.appmodel.nl:Tour/viewer.git)
|
||||||
|
|
||||||
|
een multi-stage Dockerfile voor een Node-based static frontend aanmaken
|
||||||
|
|
||||||
|
~/infra/viewer/docker-compose.yml aanmaken met:
|
||||||
|
|
||||||
|
service viewer
|
||||||
|
|
||||||
|
koppeling aan traefik_net
|
||||||
|
|
||||||
|
Traefik route: https://viewer.appmodel.nl
|
||||||
|
|
||||||
|
2. Develop & build
|
||||||
|
|
||||||
|
Op je dev machine:
|
||||||
|
|
||||||
|
git clone git@git.appmodel.nl:Tour/viewer.git
|
||||||
|
cd viewer
|
||||||
|
# bouw je app zoals normaal
|
||||||
|
npm install
|
||||||
|
npm run build # output in dist/
|
||||||
|
git add .
|
||||||
|
git commit -m "First version"
|
||||||
|
git push
|
||||||
|
|
||||||
|
|
||||||
|
De Dockerfile verwacht een dist/ map met static files.
|
||||||
|
|
||||||
|
3. Deploy pipeline
|
||||||
|
3.1 app-deploy <app>
|
||||||
|
|
||||||
|
Op de server verzorgt app-deploy de generieke deploy:
|
||||||
|
|
||||||
|
app-deploy viewer
|
||||||
|
|
||||||
|
|
||||||
|
Doet:
|
||||||
|
|
||||||
|
cd /opt/apps/viewer
|
||||||
|
|
||||||
|
git pull --ff-only
|
||||||
|
|
||||||
|
cd /home/tour/infra/viewer
|
||||||
|
|
||||||
|
docker compose up -d --build viewer
|
||||||
|
|
||||||
|
Logs komen in:
|
||||||
|
|
||||||
|
/var/log/app-deploy-viewer.log
|
||||||
|
|
||||||
|
3.2 Automatisch deployen via Gitea hook
|
||||||
|
|
||||||
|
In Gitea (repo Tour/viewer):
|
||||||
|
|
||||||
|
Ga naar Instellingen → Git Hooks
|
||||||
|
|
||||||
|
Kies post-receive
|
||||||
|
|
||||||
|
Gebruik:
|
||||||
|
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
/usr/local/bin/app-deploy viewer
|
||||||
|
|
||||||
|
|
||||||
|
Vanaf nu:
|
||||||
|
|
||||||
|
Elke git push naar Tour/viewer triggert automatisch een deploy.
|
||||||
|
|
||||||
|
4. Traefik & DNS
|
||||||
|
|
||||||
|
Traefik draait in de traefik stack op dezelfde server en beheert:
|
||||||
|
|
||||||
|
git.appmodel.nl
|
||||||
|
|
||||||
|
auction.appmodel.nl
|
||||||
|
|
||||||
|
aupi.appmodel.nl
|
||||||
|
|
||||||
|
… (nieuwe apps via labels)
|
||||||
|
|
||||||
|
Nieuwe app viewer krijgt via apps-create al de juiste labels:
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.viewer.rule=Host(`viewer.appmodel.nl`)"
|
||||||
|
- "traefik.http.routers.viewer.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.viewer.tls=true"
|
||||||
|
- "traefik.http.routers.viewer.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.viewer.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
|
||||||
|
Je moet alleen in DNS nog een record maken:
|
||||||
|
|
||||||
|
viewer.appmodel.nl → publieke IP van de server
|
||||||
|
|
||||||
|
Traefik + Let’s Encrypt regelen het certificaat automatisch.
|
||||||
|
|
||||||
|
5. Nieuwe app types (toekomst)
|
||||||
|
|
||||||
|
Het apps-create script ondersteunt nu:
|
||||||
|
|
||||||
|
static-fe – Node build → Nginx → static frontend
|
||||||
|
|
||||||
|
Later kun je extra types toevoegen, bijvoorbeeld:
|
||||||
|
|
||||||
|
api-py – Python (Flask/FastAPI) API
|
||||||
|
|
||||||
|
worker-py – background worker / crawler
|
||||||
|
|
||||||
|
Door per type een eigen Dockerfile-sjabloon en standaard docker-compose.yml te genereren, wordt een nieuw project neerzetten:
|
||||||
|
|
||||||
|
apps-create stats api-py
|
||||||
|
apps-create crawler worker-py
|
||||||
|
|
||||||
|
|
||||||
|
en blijft de pipeline (app-deploy <naam>) identiek.
|
||||||
|
|
||||||
|
Je kunt nu:
|
||||||
|
|
||||||
|
apps-create viewer static-fe
|
||||||
|
app-deploy viewer
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
diagrams==0.25.1
|
||||||
|
graphviz==0.20.3
|
||||||
40
test.md
Normal file
40
test.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 🌐 Internet / Cloud │
|
||||||
|
└────────────────┬────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 🛜 Router (hub.lan) - 192.168.1.1 │
|
||||||
|
│ Gateway & DHCP │
|
||||||
|
└────────────────┬────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌────────────┴────────────┬──────────────┬──────────────┐
|
||||||
|
▼ ▼ ▼ ▼
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ LAN │ │ LAN │ │ LAN │ │ LAN │
|
||||||
|
│ 192.168.│ │ Infra & │ │ Home │ │ IoT & │
|
||||||
|
│ 1.x │ │ DNS │ │ Assist │ │ Workers │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ ┌────┐ │ │ ┌────┐ │ │ ┌────┐ │ │ ┌────┐ │
|
||||||
|
│ │Core│ │ │ │DNS │ │ │ │ HA │ │ │ │Atlas│ │
|
||||||
|
│ │ Srv│ │ │ │Host│ │ │ │Host│ │ │ │ │ │
|
||||||
|
│ └┬───┘ │ │ └┬───┘ │ │ └┬───┘ │ │ └┬───┘ │
|
||||||
|
│ │ │ │ │ │ │ │ │ │ │ │
|
||||||
|
│ ┌─▼──┐ │ │ ┌─▼──┐ │ │ ┌─▼──┐ │ │ │ │
|
||||||
|
│ │Dock│ │ │ │AdGr│ │ │ │Hass│ │ │ │ │
|
||||||
|
│ │er │ │ │ │d │ │ │ │ │ │ │ │ │
|
||||||
|
│ └────┘ │ │ └────┘ │ │ └────┘ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
||||||
|
│
|
||||||
|
│ ┌─────────────────────────────────────────────────────┐
|
||||||
|
└──►│ Tether Subnet 192.168.137.x │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ Hermes │ │ Plato │ │
|
||||||
|
│ │ Worker │ │ Worker │ │
|
||||||
|
│ └──────────┘ └──────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
Developer Laptops
|
||||||
|
(Windows/WSL)
|
||||||
Reference in New Issue
Block a user