Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Hints: Running Node-Red in IOTstack

Hints: Running Node-RED in IOTstack

Much of the material that used to be in this gist has been moved to the Node-RED documentation page at SensorsIot/IOTstack.

The nodered_list_installed_nodes script is also part of the IOTstack repository.


The material below is the remainder of the original gist:

Useful script nodered_version_check

#!/usr/bin/env bash

LATEST=$(wget -O - -q https://raw.githubusercontent.com/node-red/node-red-docker/master/package.json | jq -r .version)
INSTALLED=$(docker inspect iotstack_nodered:latest | jq -r .[0].ContainerConfig.Labels[\"org.label-schema.version\"])

if [ "$INSTALLED" = "$LATEST" ] ; then 

   echo "Node-RED is up-to-date (version $INSTALLED)"

else

/bin/cat <<-COLLECT_TEXT

	====================================================================
	Node-RED version number has changed on GitHub:

	    Local Version: $INSTALLED
	   GitHub Version: $LATEST
	
	This means a new version MIGHT be available on DockerHub. Check here:

	   https://hub.docker.com/r/nodered/node-red/tags?page=1&ordering=last_updated

	When an updated version is actually available, proceed like this:

	   $ cd ~/IOTstack
	   $ docker-compose build --no-cache --pull nodered
	   $ docker-compose up -d nodered
	   $ docker system prune
	====================================================================

COLLECT_TEXT

fi

installation

  1. Make sure ~/.local/bin exists (the following command is non-destructive):

    $ mkdir -p ~/.local/bin
    
  2. Logout and login again. A new login causes your .profile to run. That discovers the ~/.local/bin directory and adds it to your search path.

  3. Copy the nodered_version_check script to the clipboard.

  4. Paste the script into your favourite text editor.

    Note:

    • try to avoid using text editors which write line-endings as CR+LF (0x0D 0x0A). You will typically find those on Windows systems but you may also encounter the problem on other platforms if your text editor has a preference which has been set to use CR+LF line-endings. The Raspberry Pi expects LF.
  5. Save the script into ~/.local/bin with the name nodered_version_check.

  6. Make the script executable:

    $ chmod u+x nodered_version_check
    
  7. Test by running the script:

    $ nodered_version_check
    

dependencies

nodered_version_check depends on jq and wget. If those are not available on your Raspberry Pi, you can fix that by:

$ sudo apt install -y jq wget

Script 2: nodered_list_installed_nodes

#!/usr/bin/env bash

INTERNAL="/usr/src/node-red/node_modules"
EXTERNAL="$HOME/IOTstack/volumes/nodered/data/node_modules"

echo -e "\nNodes installed by Dockerfile INSIDE the container at $INTERNAL"

CANDIDATES=$(docker exec nodered bash -c "ls -1d $INTERNAL/node-red-*")

for C in $CANDIDATES; do

   NODE=$(basename "$C")

   # is a node of the same name also present externally
   if [ -d "$EXTERNAL/$NODE" ] ; then

      # yes! the internal node is blocked by the external node
      echo " BLOCKED: $NODE"

   else

      # no! so that means it's active
      echo "  ACTIVE: $NODE"

   fi

done

echo -e "\nNodes installed by Manage Palette OUTSIDE the container at $EXTERNAL"

CANDIDATES=$(ls -1d "$EXTERNAL/node-red-"*)

for C in $CANDIDATES; do

   NODE=$(basename "$C")

   echo " $NODE"

done

echo ""

Customising Node-RED

Reducing the number of layers in the local image

Best practice for producing Docker images is to keep layers to a minimum. Out of the box, IOTstack creates layers unnecessarily. You can fix that by rearranging your Dockerfile:

  1. Instead of three separate commands:

    RUN apk update
    RUN apk upgrade
    RUN apk add --no-cache eudev-dev
    

    you can write it as a one-liner:

    RUN apk update && apk add --no-cache eudev-dev 
    

    Note:

    • apk upgrade should be omitted. The command can have unintended consequences. It will be removed in a future pull request.
  2. Instead of the for loop:

    RUN for addonnodes in \
    node-red-node-pi-gpiod \
    node-red-dashboard \
    node-red-contrib-influxdb \
    node-red-contrib-boolean-logic \
    node-red-node-rbe \
    node-red-configurable-ping \
    node-red-node-email \
    node-red-contrib-generic-ble \
    ; do \
    npm install ${addonnodes} ;\
    done;
    

    you can write it as one logical line:

    RUN npm install \ 
    node-red-node-pi-gpiod \
    node-red-dashboard \
    node-red-contrib-influxdb \
    node-red-contrib-boolean-logic \
    node-red-node-rbe \
    node-red-configurable-ping \
    node-red-node-email \
    node-red-contrib-generic-ble
    

Notes:

  • If you need to install a particular version of a node, you can do it by appending the version number in the Dockerfile. For example, suppose you need version 1.10.1 of node-red-node-email:

     node-red-node-email@1.10.1 \
    
  • If you are installing the SQLite node, it must have an npm install line all to itself.

If you make any changes to your Dockerfile, follow the steps at apply Dockerfile changes.

Build once, deploy many

I have two 4GB Raspberry Pi 4Bs which I think of as "live" and "test". They are kept as close to identical as I can manage. As well as being a good testbed, my "test" Raspberry Pi is also there to guard against my "live" Raspberry Pi emitting magic smoke. If that happens, all I will have to do is:

  1. Restore the latest backup onto the "test" Raspberry Pi (the "live" Raspberry Pi takes two backups per day).
  2. Change my DHCP server to associate the MACs of the "test" Raspberry Pi with the IP addresses being assigned to the "live" Raspberry Pi.
  3. Apply power.

Because I have two Raspberry Pis, I have never seen much sense in rebuilding Node-RED on both the "live" and "test" machines. Generally, I will do the rebuild on the "test" Raspberry Pi first, make sure there are no obvious problems, and then think about the "live" Raspberry Pi.

If you're in a similar situation, here's how to avoid rebuilding Node-RED on more than one machine.

Rebuild on Raspberry Pi "A"

If a new base image has become available on DockerHub:

$ cd ~/IOTstack
$ docker-compose build --no-cache --pull nodered
$ docker-compose up -d nodered
$ docker system prune

If you have changed the Dockerfile, you only need:

$ cd ~/IOTstack
$ docker-compose up --build -d nodered
$ docker system prune

Archive images on Raspberry Pi "A"

  1. If you just rebuilt because a new base image became available on DockerHub, you should archive the new base image:

    $ docker save nodered/node-red >~/nodered_base.tar
    
  2. Archive the new local image:

    $ docker save iotstack_nodered >~/nodered_local.tar
    

Deploy images from "A" to "B"

I use scp but you can use any method that works for you to move the .tar files from "A" to "B":

$ scp ~/nodered_*.tar pi@OTHERPI:.

where "OTHERPI" is the IP address or domain name of another Raspberry Pi.

Load images on Raspberry Pi "B"

On each OTHERPI:

  1. If you archived a new base image, restore that first:

    $ docker load <~/nodered_base.tar
    
  2. Restore the new local image:

    $ docker load <~/nodered_local.tar
    
  3. Apply the changes:

    $ cd ~/IOTstack
    $ docker-compose up -d nodered
    
  4. Clean-up:

    $ docker system prune
    $ rm ~/nodered_*.tar
    

There is no need to take down the old Node-RED container. The "up" will automatically instantiate a new container based on the newer image and perform a new-for-old swap. Barely any downtime!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment