Skip to content

Docker Deployment

1.4

When deploying NF using Docker (or other container runtimes), two containers are required: one running the Normal Framework and one running Redis.

Quick Start

The quickest way to get started is by using the docker-compose file provided as part of the SDK.

Images

NF is published as two images, with the same tags (latest, 3.10, 3.10.11-0, ...):

Image Contents Architectures
normalframework/nf-full Every NF service, the SDK (applications and hooks), and the console linux/amd64, linux/arm64, linux/arm/v7
normalframework/nf-slim 3.10.11 BACnet discovery, polling and trending, commands, and Sparkplug B publishing, for gateways with a few hundred MB of RAM linux/amd64, linux/arm64, linux/arm/v7

Both use the same redis image, ports, volumes and environment variables; the tags are multi-architecture, so Docker pulls the right one for the host. 32-bit ARM (linux/arm/v7) images are available from 3.10.10.

nf-slim

nf-slim leaves out Node.js and the applications service (SDK apps and hooks), device health, and the Modbus, OPC-UA, Fox, UDMI, Sparkplug consumer, schedule, template, TimescaleDB, backup and agent services. The console hides the pages for services the image does not have. Its services and the gateway run in a single process.

It also sets these defaults to bound memory use; set any of them on the container (or in the console) to override:

Variable nf-slim default Effect
TIMESERIES_RETENTION 24h Trend history kept per point (new points)
TIMESERIES_ERROR_RETENTION 1h Error history kept per point (new points)
TIMESERIES_ERROR_INTERVAL 15m At most one error history sample per point in this interval
SCAN_JOB_RETENTION 168h Finished scan jobs older than this are deleted
SCAN_JOB_MAX 100 At most this many finished scan jobs are kept
SINGLE_POINT_INDEX 1 Keep one search index (the default layer's) instead of one per layer
INDEXED_LAYERS hpl:bacnet:1,hpl:bacnet:local,model Only these layers are searchable; others are kept but not indexed or polled

SINGLE_POINT_INDEX and INDEXED_LAYERS can also be set on nf-full to reduce Redis memory on small gateways.

Networking

The Normal Framework container requires network_mode: host to properly process BACnet traffic. This limits the ability to use other Docker networking primitives to isolate the container.

After installation, the API Gateway and Management Console are exposed on port tcp/8080.

Filesystem

"Hard state" is stored in Redis, which should be backed up. NF also requires a writable, persistent volume for "soft state," such as data being buffered before being sent out, low-level configuration settings, and other data that should persist across reboots.

This state is stored within /var/nf in the container. It is recommended to volume-mount this directory so that it persists across restarts.

For security, you may mount the container volume as read-only. In this case, you must set S6_READ_ONLY_ROOT=1 and mount /run and /tmp as tmpfs mounts.

Initialization and Configuration

Within the container, NF uses s6-rc to start services and ensure they are restarted on error. You may inspect the s6 configuration by looking in /etc/s6-overlay. Although detailed documentation is beyond the scope of this article, it is possible to alter the environment for individual services by adjusting the contents of this directory. Additionally, environment variables applied to the container (i.e., on the Docker command line) are passed to all services.

Redis

Normal Framework includes a build of Redis Server that has been validated to work correctly. You may also build your own; there are no modifications required. NF requires RediSearch and RedisTimeSeries to be installed on the Redis instance.

Redis stores its data in /data; this directory should be volume-mounted and backed up.

By default NF connects to Redis at localhost:6379. Set REDIS_ADDRESS on the NF container to use another address, or to a path (anything starting with /) to connect over a unix socket 3.10.10. With the NF redis image, set REDIS_LISTEN_SOCKET to the socket path on the Redis container and mount the socket's directory into both containers, e.g. a shared volume at /run/redis-sock and REDIS_ADDRESS=/run/redis-sock/redis.sock. Redis keeps serving TCP 6379 as well.