Sign inSign up

icodevtest/edge-stack:latest

Manifest digest

sha256:8d45d231adb7f807be984f92e542e83768c29d90e6ce118cf18ffcfb252966af

Last pushed

about 10 hours by peckaales

Type

Compose

Manifest digest

sha256:8d45d231adb7f807be984f92e542e83768c29d90e6ce118cf18ffcfb252966af

Compose file content

# 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 commands

docker compose -f oci://icodevtest/edge-stack:latest up

Use the above command to pull and run the Compose file. Learn more⁠.

Images used

Image

Portainer CE - a lightweight service delivery platform for containerized applications


Pulls

1B+

Stars

2690

Last Updated

10 days

Image

CloudBeaver Community


Pulls

10M+

Stars

134

Last Updated

about 16 hours