How to package node-red subflows into a dedicated Node-Red Docker Container?

I have created a subflow for the standard mqtt in and mqtt out nodes which sets the broker address accordingly (docker container names of the MQTT broker) and is made available for the use in the node pallete.

The node pallete looks as follows:
image

The subflow is very simple, it is just a wrapper around the mqtt in and mqtt out nodes but the mqtt properties are configured to the broker address instead of localhost

Internal MQTT In Node

image

Internal MQTT Out Node
image

Documentation for Subflows

Based on the documentation provided by Packaging a Subflow as a module : Node-RED
I did the following steps:

  1. export the subflow as JSON file (example only of Internal MQTT Out Node)

     [{"id":"be86292c6d08f0da","type":"subflow","name":"Internal MQTT Out","info":"","category":"","in":[{"x":340,"y":140,"wires":[{"id":"b122f18e514d14f9"}]}],"out":[],"env":[],"meta":{},"color":"#C0DEED","icon":"node-red/bridge.svg"},{"id":"b122f18e514d14f9","type":"mqtt out","z":"be86292c6d08f0da","name":"Internal MQTT Broker","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"dbd22c0713b05ef6","x":560,"y":140,"wires":[]},{"id":"dbd22c0713b05ef6","type":"mqtt-broker","z":"be86292c6d08f0da","name": "Internal MQTT Broker","broker":"internal-mqtt-broker","port":"1883","clientid":"node-red-mqtt-internal-out","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""}]
    
  2. As the documentation suggests, I packed the dedicate nodes namely, "type": mqtt-out and "type": "mqtt-broker into to "type": "subflow" under an array called flow: []

Altered JSON File after Step 2

[
    {
        "id": "be86292c6d08f0da",
        "type": "subflow",
        "name": "Internal MQTT Out",
        "info": "",
        "category": "",
        "in": [
            {
                "x": 340,
                "y": 140,
                "wires": [
                    {
                        "id": "b122f18e514d14f9"
                    }
                ]
            }
        ],
        "out": [],
        "env": [],
        "meta": {},
        "color": "#C0DEED",
        "icon": "node-red/bridge.svg",
        "flow": [
            {
                "id": "b122f18e514d14f9",
                "type": "mqtt out",
                "z": "be86292c6d08f0da",
                "name": "Internal MQTT Broker",
                "topic": "",
                "qos": "",
                "retain": "",
                "respTopic": "",
                "contentType": "",
                "userProps": "",
                "correl": "",
                "expiry": "",
                "broker": "dbd22c0713b05ef6",
                "x": 560,
                "y": 140,
                "wires": []
            },
            {
                "id": "dbd22c0713b05ef6",
                "type": "mqtt-broker",
                "z": "be86292c6d08f0da",
                "name": "Internal MQTT Broker",
                "broker": "internal-mqtt-broker",
                "port": "1883",
                "clientid": "node-red-mqtt-internal-out",
                "autoConnect": true,
                "usetls": false,
                "protocolVersion": "4",
                "keepalive": "60",
                "cleansession": true,
                "birthTopic": "",
                "birthQos": "0",
                "birthPayload": "",
                "birthMsg": {},
                "closeTopic": "",
                "closeQos": "0",
                "closePayload": "",
                "closeMsg": {},
                "willTopic": "",
                "willQos": "0",
                "willPayload": "",
                "willMsg": {},
                "sessionExpiry": ""
            }
        ]
    }
]

Project file structure

.
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ subflows
    โ””โ”€โ”€ mqtt
        โ”œโ”€โ”€ custom-mqtt-internal-in.js
        โ”œโ”€โ”€ custom-mqtt-internal-in.json
        โ”œโ”€โ”€ custom-mqtt-internal-out.js
        โ””โ”€โ”€ custom-mqtt-internal-out.json

package.json

{
    "name": "node-red-custom-subflow",
    "version": "0.1.0",
    "description": "Node-RED package developed with subflows",
    "dependencies": {
        "node-red": ">=2.2.0"
    },
    "keywords": ["node-red", "mqtt"],
    "node-red": {
        "version": ">=2.2.0",
        "nodes": {
            "custom-mqtt-internal-in": "subflows/mqtt/custom-mqtt-internal-in.js",
            "custom-mqtt-internal-out": "subflows/mqtt/custom-mqtt-internal-out.js",
        }
    },
    "scripts": {
        "start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS --userDir=/data"
    }
}

Question

I wish to create a custom node-red Docker image with these subflows available in the node pallete. I am unable to figure out where should the subflows directory copied in the Container image to make it available for the final image?

Dockerfile

FROM nodered/node-red:2.2.2

WORKDIR /usr/src/node-red

## Maybe already create a directory in `node_modules`?
RUN mkdir -p /usr/src/node-red/node_modules/node-red-custom-subflow/subflows/mqtt

COPY subflows/* /usr/src/node-red/node_modules/node-red-custom-subflows/subflows/mqtt

## Do I need to copy it also in /data?
COPY subflows /data

COPY package.json .

RUN npm install --unsafe-perm \
                --no-update-notifier \
                --no-fund \
                --only=production

CMD [ "npm", "start" ]

I tried building this image using docker build -t custom-node-red-subflow:latest . and docker run -p 1990:1880 custom-node-red-subflow:latest however the nodes are not available in the palette.

Help would be appreciated.

Your subflow JSON is not quite right - you still have the subflow node wrapped in an array.

It should be:

{
    "id": "be86292c6d08f0da",
    "type": "subflow",
    ...
    "flow": [
        { ... },
        { ... },
        { ... }
    ]
}

Ah! That was not clear to me. I will keep you updated on the post. Any chance the docs team might be open for a better Documentation of the development workflow for subflows?

I have been able to figure out now how to provide subflows in Docker, (if you might not know I also posted a tutorial [Tutorial] How to create a custom Node-Red Docker Image and conduct Integration Testing using Docker-Compose previously)

I could do a simple Subflow and provide step by step implementation and maybe it might make things a tad-bit clearer.

As an open source project, we are reliant on contributions from the community to help improve things. There is no dedicated docs team. PRs are always welcome. The page in question is here:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.