Compare commits

..

No commits in common. "fd0b589c104e2f1f28f4464922443006ad31a59f" and "8149f1bbbf9bab87006ed5a9180851d12281c187" have entirely different histories.

3 changed files with 12 additions and 106 deletions

View file

@ -26,12 +26,6 @@ spec:
envFrom:
- configMapRef:
name: pangolin-controller-config
env:
- name: CONFIG_AUTH_HEADER
valueFrom:
secretKeyRef:
name: pangolin-controller-api-key
key: auth-header
ports:
- name: metrics
containerPort: 9090

View file

@ -74,54 +74,10 @@ The API access via /jmap seems to be too complex for the agent and the configrua
Refer to [manual configuration steps](manual_config_steps.md)
## Network Architecture
### Load Balancing Setup
Stalwart uses a two-tier load balancing architecture:
1. **Hetzner Cloud Load Balancer** (External Layer)
- Provides the public-facing IP for mail services
- Configured with k3s-cp-1 and all worker nodes as targets
- Forwards traffic to Kubernetes NodePorts on the cluster nodes
2. **Kubernetes LoadBalancer Services** (Internal Layer)
- Service type: LoadBalancer (managed by k3s ServiceLB)
- Automatically configured by Hetzner CCM (Cloud Controller Manager)
- Creates NodePorts that the Hetzner LB targets
### Traffic Flow
```
External Mail Client
Hetzner Load Balancer (public IP)
k3s Node NodePort (automatically assigned)
Kubernetes LoadBalancer Service (stalwart-smtp / stalwart-imap)
Stalwart Pod
```
### Why LoadBalancer Service Type is Required
The Kubernetes services MUST remain type `LoadBalancer` because:
- The Hetzner CCM automatically manages the Hetzner Load Balancer configuration
- When a service is type LoadBalancer, the CCM creates/updates the Hetzner LB targets
- Changing to NodePort would break this automatic management
- Manual Hetzner LB configuration would be required and error-prone
### Services
- `stalwart-smtp` (LoadBalancer): Ports 25, 587
- `stalwart-imap` (LoadBalancer): Port 993
- `stalwart-http` (ClusterIP): Port 8080 (web UI via Traefik Ingress)
## Ports
- SMTP: 25, 587
- IMAPS: 993 (secure only, port 143 disabled per DEV-359)
- SMTP: 25, 587, 465
- IMAP: 143, 993
- HTTP: 8080 (web UI)
## Storage

View file

@ -198,60 +198,27 @@ Ports:
### Stalwart Mail Server
Stalwart uses a **two-tier load balancing architecture** combining Hetzner Cloud Load Balancer with Kubernetes LoadBalancer services.
#### Architecture
```
External Mail Client
Hetzner Cloud Load Balancer (Managed)
- Targets: k3s-cp-1, k3s-worker-1 through k3s-worker-5
- Health checks enabled
k3s Node NodePorts (auto-assigned by k3s ServiceLB)
Kubernetes LoadBalancer Services (stalwart-smtp / stalwart-imap)
Stalwart Pod (fsn1 datacenter, PV affinity)
```
#### Why This Architecture?
The Kubernetes services **MUST** be type `LoadBalancer` (not NodePort) because:
- **Hetzner CCM Integration**: The Hetzner Cloud Controller Manager automatically configures the Hetzner Load Balancer when it detects a Kubernetes LoadBalancer service
- **Automatic Target Management**: CCM keeps the Hetzner LB targets synchronized with cluster node changes
- **Health Check Automation**: CCM configures health checks based on the service configuration
- **No Manual Intervention**: Changing to NodePort would require manual Hetzner LB management
See DEV-439 for detailed investigation.
#### SMTP Service
```yaml
Service: stalwart/stalwart-smtp
Type: LoadBalancer # Required for Hetzner CCM integration
Type: LoadBalancer
External-IPs: 10.42.1.2, 10.42.1.3, 10.42.1.5, 178.105.17.239
Ports:
- 25/TCP (SMTP)
- 587/TCP (Submission)
- 465/TCP (SMTPS)
```
#### IMAP Service
```yaml
Service: stalwart/stalwart-imap
Type: LoadBalancer # Required for Hetzner CCM integration
Type: LoadBalancer
External-IPs: 10.42.1.2, 10.42.1.3, 10.42.1.5, 178.105.17.239
Ports:
- 993/TCP (IMAPS) # Port 143 disabled per DEV-359
- 143/TCP (IMAP)
- 993/TCP (IMAPS)
```
#### Historical Context
- **Initial Setup**: Used k3s ServiceLB with hostPort bindings (DEV-359)
- **Migration**: Migrated to Hetzner Load Balancer for stability (DEV-357)
- **Current State**: Hetzner LB + Kubernetes LoadBalancer services (managed by Hetzner CCM)
- **Key Fix**: Resolved CNI-HOSTPORT orphaned rules issue by adding external LB layer
## DNS Configuration
### Domain: basicstack.de
@ -431,26 +398,16 @@ Internet → DNS → Hetzner Firewall (fw-k3s)
→ Application Pods
```
### Mail Traffic (SMTP/IMAP) - Stalwart
**Two-Tier Architecture** (Hetzner Load Balancer + Kubernetes LoadBalancer):
### Direct LoadBalancer Traffic (SMTP/IMAP)
```
Internet → DNS (mail.basicstack.de)
→ Hetzner Cloud Load Balancer (managed by Hetzner CCM)
→ k3s Node (any target: k3s-cp-1 or k3s-worker-1 through k3s-worker-5)
→ NodePort (auto-assigned by k3s ServiceLB)
→ Kubernetes LoadBalancer Service (stalwart-smtp / stalwart-imap)
Internet → DNS → Hetzner Firewall (fw-k3s)
→ LoadBalancer IP (any worker or control-plane node)
→ Service DaemonSet Pod (svclb-stalwart-*)
→ Stalwart Pod (in fsn1 datacenter due to PV affinity)
→ Backend Service (ClusterIP)
→ Stalwart Pods
```
**Key Points:**
- Hetzner CCM automatically manages the Hetzner Load Balancer configuration
- Service type MUST be LoadBalancer (not NodePort) for CCM integration
- k3s ServiceLB creates the NodePorts that the Hetzner LB targets
- Traffic flows through two load balancing layers for reliability
### Internal Service-to-Service
```
@ -712,5 +669,4 @@ kubectl get certificate -n <namespace> <cert-name> -w
| Date | Change | Author |
|------|--------|--------|
| 2026-08-02 | Document Hetzner Load Balancer architecture for Stalwart mail services | CTO (DEV-439) |
| 2026-07-06 | Initial comprehensive network architecture documentation | CTO (DEV-225) |