0 Design: Runnable Project
Dave Conway-Jones edited this page 2018-04-13 11:47:52 +01:00

Note: Added a branch runnable-project to experiment - https://github.com/node-red/node-red/tree/runnable-project. Currently works as described below... but maybe not final design choices.

One of the goals of the Projects feature is to treat a project as a deployable artefact.

It should be possible to deploy a project without using the editor. For example:

1. git clone https://example.com/my-node-red-project.git
2. cd my-node-red-project
3. npm install
4. npm start -- --credentialSecret="my-secret-key"

Missing pieces

We can't quite do this today. Here are the missing pieces:

  1. the project's package.json needs to list node-red as a dependency. On balance, I think this is the right approach, rather than treat node-red as an assumed prerequisite. I don't think we should do this be default; maybe add a checkbox in the project settings' dependencies page to include node-red.

DCJ: Yes - agree it should be a dependency. Currently not hard to add manually, but could be even easier. It would be a prerequisite dependency for inside a Docker container.

DCJ: Added a button to dependencies panel to add node-red core - As it's not "known" it shows as greyed in the list- but I actually think this is good, as it indicates it may not be required also.

NOL: Not sure a standalone button passes the "why is it there?" test.

  1. it must be possible to point node-red at a project on start-up, without using the editor to do so. Currently we overload the flowFile argument to set the active project - but that only works if the project is 'known'. It would be better to point at a projectDir wherever it may exist.

DCJ: Are we pointing Node-RED or npm start ? Which are we calling to run it ? If npm start then don't we already have to be in the correct project directory ? (or use npm start --prefix projectDir)

DCJ: Having played with it a while - I think npm start from within the relevant directory is the way to go to start with.

  1. it must be possible to provide the credentialSecret for the project without it being part of any of the version controlled files. Options for this include:
    • env var - NODE_RED_CREDENTIAL_SECRET
      • [DCJ] easy to add to settings.js - credentialSecret: process.env.NODE_RED_CREDENTIAL_SECRET and would suit Docker style deploy.
    • command-line flag - --credentialSecret="..."
      • [DCJ] added as new command line option to runnable-project dev branch

DCJ/NOL: a) If environment variable works do we need command line option ? When would you use it? b) should using env var be baked into core or just via settings file so can be removed if required.

  1. Must handle running in a read-only environment. If the package is installed globally (in order to insert a command link into /usr/bin) then the flow file and settings.js will be in root space - which ought not to be writable by the user. Currently even starting Node-RED with -u option pointing somewhere protected will fail. Options include
    • just handling the error - i.e. log something (useful) - but fail to start.
    • on detecting this condition, marking the settings.readOnly as true thus stopping the library failing - but run.
    • setting disableEditor to true also.

The package would provide an npm start script that runs node-red with the appropriate command-line args.

DCJ: currently just using node-red -u . flow.json - i.e. start Node-RED using the current directory as the base and the current flow file.

NOL: instead should it use (say) a -p option to specify a package.json file to use instead to read the extra settings from (like flow file etc)

It could also provide a bin section that could allow starting via command line if installed globally - but that requires a command to be run (that doesn't take parameters) so in order to do that we would also need to create that script/.js file or provide a template.

DCJ: Actually by pre-req node-red it automatically adds the node-red command to the node_modules/.bin so the package.json start script can just call node-red and all is good.

Runtime settings

When deploying the project, there will also be a need to have the runtime settings provided. These are not normally part of a project generated by Node-RED. The question is whether we have some tooling support to generate, or we just document how to do it. For example, the user would manually add a settings.js file to their project repo.

DCJ: If we have the "add node-red as a dependency" button - could it not also have a ... "copy default settings.js into project" button or create a minimal settings.js (i.e. without defaults and comments) ? (but ensuring flowFile doesn't clash) e.g.

module.exports = {
    uiPort: process.env.PORT || 1880,
    credentialSecret: process.env.NODE_RED_CREDENTIAL_SECRET
}

Dockerfile

We should also have an example Dockerfile that can be used to build and run a project.

DCJ: Here is an example Dockerfile.template that works with various flavours of Docker - note that the flow file is set using the start command in package.json, and it needs node red as a dependency)

"scripts": {"start": "node-red -u . flow.json"},
# Expects -e NODE_RED_CREDENTIAL_SECRET="my_secret_key" to be part of the docker run command at start time
# and settings.js to exist as per above
# 
# Note the node:slim image doesn't have node-gyp

## Uncomment one of the following FROM lines to suit your environment
# For generic servers
#FROM node:8-slim
# For Pi...
FROM arm32v7/node:8-slim
# For Resin.io
#FROM resin/%%RESIN_MACHINE_NAME%%-node:8-slim

# Uncomment the next three lines if you want GPIO for Pi
#RUN apt-get update && apt-get install -yq \
#    rpi.gpio && \
#    apt-get clean && rm -rf /var/lib/apt/lists/*

WORKDIR /usr/src/app

COPY package.json package.json

RUN JOBS=MAX npm install --production --unsafe-perm --no-optional && npm cache clean --force && rm -rf /tmp/*

COPY . ./

# required for Resin.io
ENV INITSYSTEM on
# useful for pigpiod node to be able to talk to daemon on host.
ENV HOST_IP=172.17.0.1
ENV NODE_PATH=/usr/src/app/node_modules

EXPOSE 1880

CMD ["npm", "start"] 

A really minimal Dockerfile to build an image (but not run) could be as simple as

FROM node:8-onbuild
VOLUME /root/.node-red
EXPOSE 1880