- scripts/install/traefik.yml + traefik-dynamic.yml: Traefik static + dynamic
config. One :80 entry point, one router on HostRegexp(otopcua.*), one
service load-balancing admin-a:9000 + admin-b:9000 with /health/active health
check (interval 5s, timeout 2s, expected 200). Followers return 503 from
/health/active so Traefik drops them within the next interval after a
leadership change.
- scripts/install/Install-Traefik.ps1: downloads Traefik for Windows, drops the
yml configs, registers the OtOpcUaTraefik Windows service via sc.exe with
restart-on-failure. Companion to Install-Services.ps1.
- docker-dev/{Dockerfile,docker-compose.yml,traefik-dynamic.yml,README.md}:
Mac-friendly four-node fleet (admin-a + admin-b + driver-a + driver-b) plus
SQL Server 2022 + OpenLDAP + Traefik. Single OtOpcUa.Host image built once;
Compose drives OTOPCUA_ROLES + Cluster:* per container to differentiate the
four hosts. README walks through bring-up + failover smoke + the dev LDAP
users.
Note: untested on macOS (no local Docker — see docs/v2/dev-environment.md).
3.2 KiB
docker-dev
Mac-friendly four-node OtOpcUa fleet for manual UI exercise + integration smoke tests. Spins up an Akka cluster + SQL Server + OpenLDAP + Traefik in front of two admin nodes.
Stack
| Service | Role | Ports |
|---|---|---|
sql |
SQL Server 2022 (ConfigDb backing store) |
host 14330 → container 1433 |
ldap |
OpenLDAP with dev users alice / bob |
host 3893 → container 1389 |
admin-a |
OtOpcUa.Host, OTOPCUA_ROLES=admin, cluster seed |
internal 9000 |
admin-b |
OtOpcUa.Host, OTOPCUA_ROLES=admin, joins admin-a |
internal 9000 |
driver-a |
OtOpcUa.Host, OTOPCUA_ROLES=driver |
host 4840 → container 4840 |
driver-b |
OtOpcUa.Host, OTOPCUA_ROLES=driver |
host 4841 → container 4840 |
traefik |
Routes :80 to whichever admin-* currently passes /health/active |
host 80, dashboard 8080 |
All six containers share an Akka cluster bound to port 4053 inside the Compose network. The Akka PublicHostname of each container matches its Compose service name; the seed-node list points at admin-a so the other three join via that.
Bring up
# from the repo root
docker compose -f docker-dev/docker-compose.yml up -d --build
# wait ~15 seconds for SQL to come up + the cluster to form
open http://localhost # Blazor admin UI via Traefik
open http://localhost:8080 # Traefik dashboard
The first build takes a few minutes (.NET SDK image + restore + publish). Subsequent rebuilds are faster with Docker's layer cache.
Auth (dev only)
Use one of the LDAP dev users from LDAP_USERS in docker-compose.yml:
| Username | Password |
|---|---|
alice |
alice123 |
bob |
bob123 |
The compose mounts everyone into ou=FleetAdmin so the dev role mapping resolves to FleetAdmin.
Tear down
docker compose -f docker-dev/docker-compose.yml down -v
The -v drops the SQL + LDAP volumes; remove it to keep ConfigDb state across restarts.
Failover smoke
- Watch the Traefik dashboard at
http://localhost:8080. Bothadmin-aandadmin-bshould be listed as healthy in theotopcua-adminservice. docker compose -f docker-dev/docker-compose.yml stop admin-a—admin-bshould pick up the admin role-leader within ~15 s (Akka split-brain stable-after). Traefik will route traffic toadmin-bonce its/health/activereturns 200.docker compose -f docker-dev/docker-compose.yml start admin-a—admin-arejoins as a follower;admin-bkeeps the leader role until something disturbs it.
Notes
- This compose is for the local Mac/Linux developer rig. The team's CI + soak runs go to the remote docker host at
10.100.0.35(seedocs/v2/dev-environment.md); the file there mirrors this one with adjusted port bindings. - The OPC UA driver endpoints (
opc.tcp://localhost:4840,opc.tcp://localhost:4841) are reachable directly from the host — Traefik is only in front of the admin HTTP surface. - Galaxy + Wonderware drivers can't run in Linux containers (they need the Windows-only mxaccessgw + Historian SDK). On non-Windows,
DriverInstanceActor.ShouldStub(driverType, roles)returnstruefor those types and the actor goes straight to aStubbedstate that returns deterministic success.