Issue commands from a docker container on the host where it run

Communication between NR dockerized and the host where it run

I worked a lot on NR in docker and I want to share my research and implementation.
Indeed how to pass orders between these 2 environments (Host & Guest docker) which are supposed to be watertight one towards the other apart from the directory sharing.

Concrete use case :

How to restart the Pi or NR container in a planned or unplanned way from a NR flow ?
Where it used to be enough to use an EXEC node with the sudo reboot command or node-red-restart on standard installation, in a container this does not work anymore.
You have to pass the reboot order to the host or the docker command to restart a container
So you have to tell the host to run the right commands.

1) Get the IP address of the host.
The main thing is to get the IP address of the host at startup and to pass it to the container via a shared host/container file. This will be read by NR docker when it starts.

Example:
This script get-ip4.sh retrieves the IP address of the P

#!/bin/bash
(/sbin/ip -o -4 addr list wlan0 | awk '{print $4}' | cut -d/ -f1) > global-variables/ip4.txt

Put the script at the boot of the Pi !

crontab -e
@reboot sleep 08 && /home/pi/get-ip4.sh

image

2) Webhook: The solution I used to place orders

Next, I opted for the Webhook solution.
See here: GitHub - adnanh/webhook: webhook is a lightweight incoming webhook server to run shell commands

sudo apt-get install webhook

In short, on the host, a daemon listens on a specific URL for an order to be given to it and then executes a script that for example restarts the Pi or checks if the OLED screen is on or off or restart a container.

Example of the hooks.json file

[
  {
    "id": "oled-status",
    "execute-command": "/home/pi/oled-status.sh",
    "command-working-directory": "/home/pi/tmp"
  },
  {
    "id": "reboot",
    "execute-command": "/home/pi/reboot.sh",
    "command-working-directory": "/home/pi/tmp"
  }
]

2.1 - Create a service that will listen on a defined port (ex:8999) the given order

sudo nano /etc/systemd/system/webhook.service

[Unit] 
Description=System Starting Webhook for NodeRed 

[Service] 
ExecStart=webhook -hooks /home/pi/hooks.json -verbose -port 8999 

[Install] 
WantedBy=multi-user.target

3) From the NR container or elsewhere

Now that this URL is launched on the host via the webhook service
It is easy to invoke this URL via the HTTP Request node or a CURL command.
This will cause a reaction on the host and execute the corresponding script.

example (code inside function node)

var ip4 = global.get("ip4");
msg.payload = "http://" + ip4;
msg.payload = msg.payload.replace(/[\r\n]/g, "");
msg.payload = msg.payload + ":8999/hooks/reboot"
return msg;

And the flow:

[{"id":"e936fd79.34d98","type":"comment","z":"77573501.0a8d4c","name":"** DANGER! Reboots the Raspberry ou OrangePi","info":"","x":200,"y":200,"wires":[]},{"id":"2bd9af2a.39e75","type":"ui_button","z":"77573501.0a8d4c","name":"","group":"aaa165da.25ec6","order":4,"width":5,"height":1,"passthru":false,"label":"Reboot Pi","tooltip":"","color":"","bgcolor":"#FF0000","icon":"fa-power-off","payload":"","payloadType":"str","topic":"","topicType":"str","x":160,"y":260,"wires":[["c3350502.fa723"]]},{"id":"404571c0.030c1","type":"inject","z":"77573501.0a8d4c","name":"Reboot Pi à 04h00 du matin","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"00 04 * * *","once":false,"onceDelay":"","topic":"","payload":"","payloadType":"str","x":180,"y":320,"wires":[["c3350502.fa723"]]},{"id":"c3350502.fa723","type":"function","z":"77573501.0a8d4c","name":"create http request","func":"var ip4 = global.get(\"ip4\");\nmsg.payload = \"http://\" + ip4;\nmsg.payload = msg.payload.replace(/[\\r\\n]/g, \"\");\nmsg.payload = msg.payload + \":8999/hooks/reboot\"\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":260,"wires":[["a59aab7e.a407d8"]]},{"id":"a59aab7e.a407d8","type":"http request","z":"77573501.0a8d4c","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"{{{payload}}}","tls":"","persist":false,"proxy":"","authType":"","x":630,"y":260,"wires":[[]]},{"id":"aaa165da.25ec6","type":"ui_group","name":"Onduleur + Raspberry","tab":"8fc69317.2b6ca","order":8,"disp":true,"width":5,"collapse":true},{"id":"8fc69317.2b6ca","type":"ui_tab","name":"Maintenance","icon":"settings_applications","order":6,"disabled":false,"hidden":false}]

I hope that these explanations will help other people

Super, I just finished this challenge to have a host node red (locally installed) and let the container NR talk to the local node Node Red instances. Your solution looks more lightweigt.
For me the local node reds are also serving as a heartbeat service to provision one of my nodes with an virtual ip.

But I like the Webhook solution. Going to dive into that one.

There is also an elegant solution for the host to talk to the NR container.
This is with the HTTP IN into NR node and CURL with parameters from the host.
So we can have a bi-directional connection with this hook solution

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