Sign inSign up

icodevtest/edge-stack:11.6.14-main

Manifest digest

sha256:2bf1c16e677e87954c40f05d2d48fddae17fc068bc51475c3f9b67a758310913

Last pushed

11 days by peckaales

Type

Compose

Manifest digest

sha256:2bf1c16e677e87954c40f05d2d48fddae17fc068bc51475c3f9b67a758310913

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 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
# Extras live in optional/: docker compose -f docker-compose.yml -f optional/<name>.yml up -d
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: ${EDGE_IMAGE:-icodevtest/edge:latest}
    container_name: edge
    # Fixed, because the OPC UA certificate in the pki volume is stamped with the hostname. A random one
    # on each recreate invalidates it and `ua:` stops resolving.
    hostname: edge
    # 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
    ports:
      - "8080:8080"
      - "8443:8443"
      # OPC UA server interface, opc.tcp and https.
      - "5011:5011"
      - "5013:5013"
      # Inbound from devices on the host's LAN: BACnet/IP (I-Am replies, COV, foreign device via a BBMD) and
      # SNMP traps. Host and container port must match. docs/edge-container.md, "Devices on the host's LAN".
      - "47808:47808/udp"
      - "162:162/udp"
    environment:
      <<: *database
      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
      # 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
      # HTTPS needs both of these AND the ./certs mount; without a certificate Kestrel skips port 8443.
      # ICO_FWX_TLS_CERT_PATH: /certs/server.pem
      # ICO_FWX_TLS_CERT_KEY_PATH: /certs/server.key
      # ICO_FWX_TLS_CERT_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
      - ./SignedLicense.jws:/usr/share/ICONICS/11/License/SignedLicense.jws:ro
      # - ./certs:/certs:ro

  # Creates the configuration databases when they are missing and upgrades what is behind; `edge` waits for it.
  configure-system:
    image: ${EDGE_IMAGE:-icodevtest/edge:latest}
    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

  webhmi:
    image: icodevtest/webhmi:latest
    container_name: webhmi
    profiles: [hmi]
    restart: unless-stopped
    ports:
      - 3000:8080
    environment:
      ASPNETCORE_URLS: http://+:8080
      COMPlus_gcServer: 0
      ICO_OIDC_PROMPT: Empty
      ICO_Client__DefaultConnection__Url: "ws://edge: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:
# Runs `edge` in the host's network namespace instead of on the compose bridge, so BACnet and SNMP broadcasts
# reach every network the host is on, with no BBMD and no field network to configure:
#   docker compose -f docker-compose.yml -f optional/host-network.yml up -d
# 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. It has no network isolation from the host.
services:
  edge:
    network_mode: host
    # The container takes the host's name, which is just as stable for the OPC UA certificate.
    hostname: !reset null
    ports: !reset []
    # 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"
    volumes:
      # From the directory compose runs in: run from the OCI artifact, ./ would mean compose's download cache.
      - ${PWD}/SignedLicense.jws:/usr/share/ICONICS/11/License/SignedLicense.jws:ro

  # On the host network too: from the bridge it would reach the server through the host's firewall, which may
  # block it. It keeps port 3000, since the server holds 8080.
  webhmi:
    network_mode: host
    ports: !reset []
    environment:
      ASPNETCORE_URLS: http://+:3000
      ICO_Client__DefaultConnection__Url: "ws://localhost:8080/fwxserverws/ws_anon/"

Docker commands

docker compose -f oci://icodevtest/edge-stack:11.6.14-main up

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

Images used

Image

CloudBeaver Community


Pulls

10M+

Stars

134

Last Updated

about 22 hours