INTERNET
│
┌──────────▼──────────┐
│ anchor EC2 │
│ 13.244.252.132 │
│ WireGuard hub │
│ TLS termination │
│ (Let's Encrypt) │
└──────────┬──────────┘
│ WireGuard 10.100.0.0/24
┌───────────────────┼───────────────────┐
│ │ │
┌─────────▼─────────────────────────────────────────────────────────┐
│ PROXMOX HYPERVISOR (10.0.10.18) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ K3s CLUSTER (4 nodes) │ │
│ │ │ │
│ │ swarm1 10.0.10.41 control-plane │ │
│ │ swarm2 10.0.10.42 worker │ │
│ │ swarm3 10.0.10.43 worker │ │
│ │ swarm4 10.0.10.44 worker │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ NAMESPACE: {package}-dev │ │ │
│ │ │ │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ Caddy │ │ report │ │ webhook │ │ │ │
│ │ │ │ :80/:443 │─▶│ ×5 :9400 │ │ ×10 :9500│ │ │ │
│ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │
│ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ ├───────▶│ web :9000│ │ workflow │ │ │ │
│ │ │ │ │ ×1 │ │ ×10 │ │ │ │
│ │ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ ├───────▶│ go │ │ conversa │ │ │ │
│ │ │ │ │ │ │ ×5 :9550 │ │ │ │
│ │ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ └───────▶│ ai ×2 │ │ sms ×5 │ │ │ │
│ │ │ │ :9700 │ │ │ │ │ │
│ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ mqtt │ │ import │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │scheduler │ │ monitor │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌──── INFRA (in-cluster) ──────────────────────┐ │ │ │
│ │ │ │ ┌────────┐ ┌─────────┐ ┌──────────┐ │ │ │ │
│ │ │ │ │ Redis │ │ MongoDB │ │ RabbitMQ │ │ │ │ │
│ │ │ │ │ cache │ │ 4.4 │ │ │ │ │ │ │
│ │ │ │ └────────┘ └─────────┘ └──────────┘ │ │ │ │
│ │ │ │ ┌────────┐ ┌─────────┐ │ │ │ │
│ │ │ │ │Mosquitto│ │InfluxDB │ │ │ │ │
│ │ │ │ │ MQTT │ │ │ │ │ │ │
│ │ │ │ └────────┘ └─────────┘ │ │ │ │
│ │ │ └──────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌──── VOLUMES ─────────────────────────────────┐ │ │ │
│ │ │ │ config.yaml ◀── ConfigMap (trimmed) │ │ │ │
│ │ │ │ data.config/ ◀── Secret (PEM keys) │ │ │ │
│ │ │ │ local.documents◀── NFS mount from NAS │ │ │ │
│ │ │ │ data.documents ◀── NFS mount from NAS │ │ │ │
│ │ │ └──────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ LXC 136 "registry" — 10.0.10.5 (WG: 10.100.0.5) │ │
│ │ 24 cores, 64GB RAM, 100GB disk │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ Harbor v2.12 (docker-compose) │ │ │
│ │ │ :5000 HTTP (TLS at anchor) │ │ │
│ │ │ │ │ │
│ │ │ registry.technocore.co.za │ │ │
│ │ │ - Project: axion (all service images) │ │ │
│ │ │ - Project: dockerhub-cache (proxy cache) │ │ │
│ │ │ - Trivy auto-scan on push │ │ │
│ │ │ - Tag retention: keep 5 + latest │ │ │
│ │ │ - Weekly GC (Sunday 2am UTC) │ │ │
│ │ │ - CVE allowlist (7 base-image CVEs) │ │ │
│ │ │ - Robot: robot$axion+pipeline (CI/CD) │ │ │
│ │ │ - Webhook proxy: /webhook/* → pipeline LXC │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ Buildx remote-builder │ │ │
│ │ │ ssh://root@10.100.0.5 │ │ │
│ │ │ Platforms: linux/amd64, linux/arm64 │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ LXC 109 "pipeline" — 10.0.10.68 (WG: 10.100.0.68) │ │
│ │ 8 cores, 8GB RAM, 50GB disk, Debian 13 │ │
│ │ │ │
│ │ - Python 3.12.8, Docker, Trivy 0.70 │ │
│ │ - axion-pipeline.service (port 9600) │ │
│ │ - Webhook: POST /webhook/build │ │
│ │ - Bitbucket URL: https://registry.technocore.co.za │ │
│ │ /webhook/build │ │
│ │ - SSH keys to K3s nodes + build host │ │
│ │ - Git repo at /home/axion/axion │ │
│ │ - Auto git-pull on service start │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ LXC 100 │ │ LXC 103 │ │ LXC 104 │ │
│ │ MariaDB │ │ RabbitMQ │ │ InfluxDB │ │
│ │ 10.0.10.20 │ │ 10.0.10.23 │ │ 10.0.10.24 │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ LXC 112 │ │ LXC 135 │ │ LXC 137 │ │
│ │ Keycloak │ │ Ollama │ │ ARM builder │ │
│ │ 10.0.10.3 │ │ 10.0.10.55 │ │ 10.0.10.27 │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────┐ │
│ │ NAS │ NFS exports: │
│ │ │ /documents (local + data + archive) │
│ └────────────────┘ │
└───────────────────────────────────────────────────────────────────┘
Bitbucket merge to develop
│
▼
anchor (TLS) → registry.technocore.co.za/webhook/build
│
▼ proxy
Harbor nginx → 10.0.10.68:9600 (pipeline LXC)
│
▼
axion-pipeline.service
│
├── 1. git pull --ff-only
├── 2. python ObjBuild.py pipeline {package} --notify raci
│ │
│ ├── config Validate config.yaml
│ ├── pem_keys Check encryption keys
│ ├── compile Cython batch compile (ccache)
│ ├── image Build 13 per-service Docker images
│ │ └── buildx → ssh://root@10.100.0.5
│ │ (amd64 + arm64, --push to Harbor)
│ ├── scan Harbor auto-scan results (Trivy)
│ ├── audit Security audit (deps, config, secrets)
│ ├── topology Generate service mesh
│ ├── scaffold Helm charts + Caddyfile + registries.yaml
│ ├── deploy Helm upgrade on K3s cluster
│ └── verify Poll health endpoints
│
└── Email report (RACI) via Brevo SMTP
| Setting |
Value |
| URL |
https://registry.technocore.co.za |
| LXC |
136 "registry" (10.0.10.5, WG 10.100.0.5) |
| Version |
Harbor v2.12 |
| Port |
5000 (HTTP), TLS at anchor |
| Admin |
admin / AsusROG1206 |
| Robot |
robot$axion+pipeline (CI/CD push/pull/scan) |
| Projects |
axion (service images), dockerhub-cache (proxy cache) |
| Auto-scan |
Trivy on every push |
| Prevention |
Block pull of CRITICAL severity |
| Retention |
Keep latest + last 5 tags, weekly cleanup |
| GC |
Weekly Sunday 2am UTC |
| CVE allowlist |
7 base-image CVEs, expires 2027-01-01 |
| Category |
Labels |
| Environment |
production, staging, development, testing |
| Version |
meridian, prism, helix, axion |
| Tier |
tier-minimal, tier-web, tier-report, tier-io, tier-ai, tier-full |
| Architecture |
amd64, arm64, multi-arch |
| Package |
pkg-homechoice, pkg-fullhouse, pkg-technocore, pkg-gekkoridge, pkg-finchoice |
registry.technocore.co.za/axion/{version}-{service}-{package}:latest
Examples:
registry.technocore.co.za/axion/meridian-report-homechoice:latest
registry.technocore.co.za/axion/meridian-web-fullhouse:latest
registry.technocore.co.za/axion/helix-ai-technocore:latest
Version derived from parent branch: develop=meridian, main=axion, helix=helix, other=prism.
┌─────────────────────────────────────────────────────────────────┐
│ AWS af-south-1 (Cape Town) │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ EC2: t3.large (2 vCPU, 8GB) │ │
│ │ K3s CLUSTER │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ NAMESPACE: homechoice-live │ │ │
│ │ │ │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ Caddy │ │ report │ │ webhook │ │ │ │
│ │ │ │ :80/:443 │─▶│ ×5 │ │ ×10 │ │ │ │
│ │ │ │ auto-TLS │ │ :9400 │ │ :9500 │ │ │ │
│ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │
│ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ ├───────▶│ web │ │ workflow │ │ │ │
│ │ │ │ │ ×1 │ │ ×10 │ │ │ │
│ │ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ └───────▶│ go │ │ sms ×5 │ │ │ │
│ │ │ └──────────┘ └──────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌──── INFRA ───────────────────────────────────┐ │ │ │
│ │ │ │ ┌────────┐ ┌─────────┐ │ │ │ │
│ │ │ │ │ Redis │ │ MongoDB │ │ │ │ │
│ │ │ │ │ cache │ │ :27017 │ │ │ │ │
│ │ │ │ │ no PVC │ │ EBS gp3 │ │ │ │ │
│ │ │ │ └────────┘ └─────────┘ │ │ │ │
│ │ │ └──────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌──── VOLUMES ─────────────────────────────────┐ │ │ │
│ │ │ │ config.yaml ◀── ConfigMap │ │ │ │
│ │ │ │ data.config/ ◀── Secret (PEM keys) │ │ │ │
│ │ │ │ local.documents◀── EFS (shared NFS) │ │ │ │
│ │ │ │ data.documents ◀── S3 (via s3fs/boto3) │ │ │ │
│ │ │ │ archive.docs ◀── S3 (via s3fs/boto3) │ │ │ │
│ │ │ └──────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ ECR │ │ RDS MariaDB │ │ S3 │ │
│ │ Container │ │ tc-rds-cpt │ │ Archive + │ │
│ │ Registry │ │ af-south-1 │ │ Backups │ │
│ │ ~$5/month │ │ (existing) │ │ $0.023/GB │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────┐ │
│ │ EFS │ Shared NFS for documents │
│ │ $0.30/GB │ Auto-scaling, multi-AZ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
External:
┌─────────────┐ ┌──────────────┐ ┌────────────┐
│ Cloudflare │ │ Brevo (SMTP) │ │ Infisical │
│ DNS + CDN │ │ │ │ Secrets │
└─────────────┘ └──────────────┘ └────────────┘
| Host |
LAN IP |
WireGuard IP |
Role |
| anchor (EC2) |
13.244.252.132 |
10.100.0.1 |
Hub, TLS termination |
| registry (LXC 136) |
10.0.10.5 |
10.100.0.5 |
Harbor + buildx |
| hypervisor |
10.0.10.18 |
10.100.0.18 |
Proxmox host |
| pipeline (LXC 109) |
10.0.10.68 |
10.100.0.68 |
CI/CD runner |
| Aspect |
Local (Proxmox) |
Cloud (AWS) |
| Compute |
Owned hardware, no recurring cost |
t3.large ~$60-100/month |
| Registry |
Harbor v2.12 (self-hosted, Trivy scanning) |
ECR ~$5/month |
| DB |
MariaDB on LXC 100 (10.0.10.20) |
RDS MariaDB (existing, same region) |
| local.documents |
NFS from NAS |
EFS ($0.30/GB, shared NFS) |
| data.documents |
NFS from NAS |
S3 ($0.023/GB, via s3fs) |
| archive.documents |
NFS from NAS |
S3 ($0.023/GB, via s3fs) |
| MongoDB |
In-cluster (mongo:4.4) + local vol |
In-cluster + EBS |
| Redis |
In-cluster (ephemeral) |
In-cluster (ephemeral) |
| TLS |
Caddy auto-TLS (Let's Encrypt) |
Caddy auto-TLS (Let's Encrypt) |
| CI/CD |
Pipeline LXC + Bitbucket webhook |
Same pipeline, push to ECR |
| Scanning |
Harbor Trivy (auto on push) |
ECR scanning |
| DB latency |
Cross-network to RDS (~5ms) |
Same region to RDS (<1ms) |
| Backup |
NAS snapshots |
EBS snapshots + S3 |
| Scaling |
Manual (add Proxmox nodes) |
EC2 auto-scaling groups |
| Best for |
Dev / staging |
Production |
Developer → git push → Bitbucket
│
▼ webhook
Pipeline LXC (via registry.technocore.co.za/webhook/build)
│
├── Compile (Cython + ccache)
├── Build (13 services × 2 arches)
├── Push to Harbor (auto-scan)
├── Deploy to Proxmox K3s (dev/staging)
│
└── [future] Push to ECR + deploy to AWS K3s (production)
- Dev/staging: Proxmox K3s, Harbor registry, NAS storage
- Production: AWS EC2 K3s, ECR, EFS + S3, same-region RDS
- Same Helm chart for both — only
values.yaml differs
- Same config.yaml structure — package overrides per environment