sha256:8d45d231adb7f807be984f92e542e83768c29d90e6ce118cf18ffcfb252966af
Last pushed
about 4 hours by peckaales
Type
Compose
Manifest digest
sha256:8d45d231adb7f807be984f92e542e83768c29d90e6ce118cf18ffcfb252966af
# Local test stack: the monolith, SQL Server, and the one-shot service that creates its databases.
# Setup needs three files in this directory: docker-compose.yml, .env (see .env.example) and license/SignedLicense.jws.
# docker compose up -d the server and its database
# docker compose --profile hmi up -d with WebHMI on http://localhost:3000
# docker compose --profile tools up -d with CloudBeaver on http://localhost:8978 and Portainer on https://localhost:9443
# Extras live in optional/: docker compose -f docker-compose.yml -f optional/<name>.yml up -d
# `edge` runs on the host network, as in the published stack; optional/bridge-network.yml puts it on the compose bridge.
name: edge
# The database the server and configure-system both use. `mssql` is the service below; ICOWB_SqlPassword
# also has to reach that service as MSSQL_SA_PASSWORD, so the two stay in step.
x-database: &database
ICOWB_SqlInstance: mssql,1433
ICOWB_SqlUsername: sa
ICOWB_SqlCatalog: IcoUnifiedConfig
ICOWB_SqlSetupCatalog: IcoSetup
ICOWB_SqlPassword: ${ICOWB_SqlPassword:?set ICOWB_SqlPassword in .env}
services:
edge:
image: icodevtest/edge:11.6.25-main
container_name: edge
# The host's network namespace, so BACnet and SNMP broadcasts reach every network the host is on, with no BBMD
# and no field network to configure. The server binds 8080, 8443, 5011, 5013, 47808/udp and 162/udp on the host
# itself; anything else on the host using one of them stops it. No network isolation from the host. The
# container takes the host's name, which is stable enough for the OPC UA certificate in the pki volume.
network_mode: host
# No Docker DNS on the host network. `mssql` is also the server name configure-system stores in IcoSetup,
# so it has to resolve; it reaches SQL Server through its published port.
extra_hosts:
- "mssql:127.0.0.1"
# All three let licensing read /sys/firmware/dmi/tables/DMI for the machine identifiers; without them
# the server runs unlicensed. docs/features/edge/29036-licensing-machine-id.md.
security_opt:
- systempaths=unconfined
- apparmor=unconfined
cap_add:
- DAC_READ_SEARCH
restart: unless-stopped
environment:
<<: *database
# Data connectors
ICO_PM__BACNETSC__ENABLED: true
ICO_PM__IOTPUBLISHER__ENABLED: true
ICO_PM__IOTSUBSCRIBER__ENABLED: true
ICO_PM__MODBUS__ENABLED: true
ICO_PM__OPCUA__ENABLED: true
ICO_PM__SNMP__ENABLED: true
# Assets
ICO_PM__ASSETCATALOG__ENABLED: true
ICO_PM__ASSETCATALOGINPROC__ENABLED: true
# Alarm server
ICO_PM__ALMS__ENABLED: true
# Alarm historian collector
ICO_PM__ALMC__ENABLED: true
# Data historian collector
ICO_PM__DHCOLLECTOR__ENABLED: true
ICO_PM__DHCOLLECTORNOSESSION__ENABLED: true
# # Trace level (all, debug, info, notice, warning, error, fatal)
# ICO_TRACE_OVERRIDE: stdout@debug
# # Ports INSIDE the container; change the `ports:` mapping above too:
# ICO_Communication__Endpoints__Http__Port: 8080
# ICO_Communication__Endpoints__Https__Port: 8443
# # The address clients use from outside, so the PUBLISHED port ("8888:8080" -> 8888):
# ICO_Communication__WebServerPublicOrigin: http://my-host:8080
# # To use your own HTTPS certificate instead of the generated one set the env vars below AND the ./certs mount.
# ICO_Communication__TlsCertificate__Path: /certs/server.pem
# ICO_Communication__TlsCertificate__KeyPath: /certs/server.key
# ICO_Communication__TlsCertificate__Password: <only for a password-protected key or .pfx>
healthcheck:
test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:8080/wb/ || exit 1"]
interval: 5s
start_interval: 1s
start_period: 15s
timeout: 3s
retries: 6
depends_on:
mssql:
condition: service_healthy
configure-system:
condition: service_completed_successfully
volumes:
- pki:/usr/share/ICONICS/11/pki
# Runtime state only, so a new image can change what it ships.
- traces:/usr/share/ICONICS/11/Logs/Traces
- license_log:/usr/share/ICONICS/11/Logs/License
- data:/usr/share/ICONICS/11/Data
# The folder, not the file: a file mount keeps the replaced file, so a new licence would never be seen.
# From the directory compose runs in: run from the OCI artifact, ./ would mean compose's download cache.
- ${PWD}/license:/usr/share/ICONICS/11/License:ro
# - ./certs:/certs:ro
# Creates the configuration databases when they are missing and upgrades what is behind; `edge` waits for it.
configure-system:
image: icodevtest/edge:11.6.25-main
container_name: configure-system
command: configure-system
restart: "no"
depends_on:
mssql:
condition: service_healthy
environment:
<<: *database
# Leaves the new system unsecured. "true" needs ICOWB_SecurityUser and ICOWB_SecurityPassword and
# creates the first login user instead.
ICOWB_SecureSystem: "false"
# ICOWB_Providers: "SEC,FWX"
mssql:
image: mcr.microsoft.com/mssql/server:2025-latest
container_name: mssql
restart: unless-stopped
environment:
ACCEPT_EULA: "Y"
# Read only while the mssql volume is empty, and the image enforces its own policy (>= 8 characters).
MSSQL_SA_PASSWORD: ${ICOWB_SqlPassword:?set ICOWB_SqlPassword in .env}
ports:
- "1433:1433"
healthcheck:
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P \"$$MSSQL_SA_PASSWORD\" -C -Q 'SELECT 1' >/dev/null || exit 1"]
interval: 5s
start_interval: 1s
start_period: 15s
timeout: 3s
retries: 5
volumes:
- mssql:/var/opt/mssql
# Database UI on http://localhost:8978 — register the server as host `mssql`, port 1433.
cloudbeaver:
image: dbeaver/cloudbeaver:latest
container_name: cloudbeaver
profiles: [tools]
restart: unless-stopped
ports:
- "8978:8978"
volumes:
- cloudbeaver_data:/opt/cloudbeaver/workspace
depends_on:
- mssql
# Container UI on https://localhost:9443 (self-signed): logs, restarts, a shell. Create the admin user within
# 5 minutes of the first start, or restart it. The Docker socket gives it full control of the host's Docker.
portainer:
image: portainer/portainer-ce:lts
container_name: portainer
profiles: [tools]
restart: unless-stopped
ports:
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
webhmi:
image: icodevtest/webhmi:latest
container_name: webhmi
profiles: [hmi]
restart: unless-stopped
# On the host network too: from the bridge it would reach the server through the host's firewall, which may
# block it. Port 3000, since the server holds 8080.
network_mode: host
environment:
ASPNETCORE_URLS: http://+:3000
COMPlus_gcServer: 0
ICO_OIDC_PROMPT: Empty
ICO_Client__DefaultConnection__Url: "ws://localhost:8080/fwxserverws/ws_anon/"
ICO_TRACE_OVERRIDE: stdout@info
volumes:
- ./displays:/usr/share/ICONICS/11/PubDisplay/displays
volumes:
pki:
traces:
license_log:
data:
mssql:
cloudbeaver_data:
portainer_data:
docker compose -f oci://icodevtest/edge-stack:latest upUse the above command to pull and run the Compose file. Learn more.
Portainer CE - a lightweight service delivery platform for containerized applications
Pulls
1B+
Stars
2690
Last Updated
10 days