feat(infra): add Traefik load balancer with active node health check for central cluster failover
Add ActiveNodeHealthCheck that returns 200 only on the Akka.NET cluster leader, enabling Traefik to route traffic to the active central node and automatically fail over when the leader changes. Also fixes AkkaClusterHealthCheck to resolve ActorSystem from AkkaHostedService (was always null via DI).
This commit is contained in:
@@ -5,7 +5,12 @@ Local Docker deployment of the full ScadaLink cluster topology: a 2-node central
|
||||
## Cluster Topology
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
┌───────────────────┐
|
||||
│ Traefik LB :9000 │ ◄── CLI / Browser
|
||||
│ Dashboard :8180 │
|
||||
└────────┬──────────┘
|
||||
│ routes to active node
|
||||
┌──────────────────────┼──────────────────────────────┐
|
||||
│ Central Cluster │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
@@ -48,6 +53,7 @@ Each site cluster runs Site Runtime, Data Connection Layer, Store-and-Forward, a
|
||||
|
||||
| Node | Container Name | Host Web Port | Host Akka Port | Internal Ports |
|
||||
|------|---------------|---------------|----------------|----------------|
|
||||
| Traefik LB | `scadalink-traefik` | 9000 | — | 80 (proxy), 8080 (dashboard) |
|
||||
| Central A | `scadalink-central-a` | 9001 | 9011 | 5000 (web), 8081 (Akka) |
|
||||
| Central B | `scadalink-central-b` | 9002 | 9012 | 5000 (web), 8081 (Akka) |
|
||||
| Site-A A | `scadalink-site-a-a` | — | 9021 | 8082 (Akka) |
|
||||
@@ -185,22 +191,24 @@ curl -s http://localhost:9002/health/ready | python3 -m json.tool
|
||||
|
||||
### CLI Access
|
||||
|
||||
The CLI connects to the Central Host's HTTP management API. With the Docker setup, the Central UI (and management API) is available at `http://localhost:9001`:
|
||||
The CLI connects to the Central Host's HTTP management API via the Traefik load balancer at `http://localhost:9000`, which routes to the active central node:
|
||||
|
||||
```bash
|
||||
dotnet run --project src/ScadaLink.CLI -- \
|
||||
--url http://localhost:9001 \
|
||||
--url http://localhost:9000 \
|
||||
--username multi-role --password password \
|
||||
template list
|
||||
```
|
||||
|
||||
Direct access to individual nodes is also available at `http://localhost:9001` (central-a) and `http://localhost:9002` (central-b).
|
||||
|
||||
> **Note:** The `multi-role` test user has Admin, Design, and Deployment roles. The `admin` user only has the Admin role and cannot perform design or deployment operations. See `infra/glauth/config.toml` for all test users and their group memberships.
|
||||
|
||||
A recommended `~/.scadalink/config.json` for the Docker test environment:
|
||||
|
||||
```json
|
||||
{
|
||||
"managementUrl": "http://localhost:9001"
|
||||
"managementUrl": "http://localhost:9000"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -18,10 +18,12 @@ docker compose -f "$SCRIPT_DIR/docker-compose.yml" ps
|
||||
|
||||
echo ""
|
||||
echo "Access points:"
|
||||
echo " Central UI (node A): http://localhost:9001"
|
||||
echo " Central UI (node B): http://localhost:9002"
|
||||
echo " Health check: http://localhost:9001/health/ready"
|
||||
echo " CLI contact points: akka.tcp://scadalink@localhost:9011"
|
||||
echo " akka.tcp://scadalink@localhost:9012"
|
||||
echo " Central (Traefik LB): http://localhost:9000"
|
||||
echo " Central UI (node A): http://localhost:9001"
|
||||
echo " Central UI (node B): http://localhost:9002"
|
||||
echo " Health check: http://localhost:9001/health/ready"
|
||||
echo " Active node check: http://localhost:9001/health/active"
|
||||
echo " Traefik dashboard: http://localhost:8180"
|
||||
echo " Management API: http://localhost:9000/management"
|
||||
echo ""
|
||||
echo "Logs: docker compose -f $SCRIPT_DIR/docker-compose.yml logs -f"
|
||||
|
||||
@@ -123,6 +123,19 @@ services:
|
||||
- scadalink-net
|
||||
restart: unless-stopped
|
||||
|
||||
traefik:
|
||||
image: traefik:v3.4
|
||||
container_name: scadalink-traefik
|
||||
ports:
|
||||
- "9000:80" # Central load-balanced entrypoint
|
||||
- "8180:8080" # Traefik dashboard
|
||||
volumes:
|
||||
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
|
||||
- ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
|
||||
networks:
|
||||
- scadalink-net
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
scadalink-net:
|
||||
external: true
|
||||
|
||||
18
docker/traefik/dynamic.yml
Normal file
18
docker/traefik/dynamic.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
http:
|
||||
routers:
|
||||
central:
|
||||
rule: "PathPrefix(`/`)"
|
||||
service: central
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
services:
|
||||
central:
|
||||
loadBalancer:
|
||||
healthCheck:
|
||||
path: /health/active
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
servers:
|
||||
- url: "http://scadalink-central-a:5000"
|
||||
- url: "http://scadalink-central-b:5000"
|
||||
11
docker/traefik/traefik.yml
Normal file
11
docker/traefik/traefik.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
|
||||
providers:
|
||||
file:
|
||||
filename: /etc/traefik/dynamic.yml
|
||||
Reference in New Issue
Block a user