This is docker-compose:
services:
node-red:
container_name: node-red-edge
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: 3
build:
context: ./
args:
NODE_VERSION: 22.13.0
NODE_RED_VERSION: ${NODE_RED_VERSION}
OS: alpine
BUILD_DATE: now
ARCH: ${NODE_RED_ARCH}
ENVIRONMENT: ${ENVIRONMENT}
environment:
- TZ=UTC
network_mode: host
volumes:
- type: bind
source: ./
target: /data
restart: always
We need to see all the files in the directory that has the compose file (since that is the build context)
Specifically the Dockerfile to start with, but probably more.
But you probably should NOT be mixing the volume mounted on /data with the environment used to build the Docker container (build context is the same as volume source, this feels like a really bad idea)
1 Like
As it is a custom docker build, you should also drop to the containers console and check that D2 is not installed in the container globally or anywhere where node-red will pick it up.
Thanks all for taking time to involve in this puzzle 
This is the Dockerfile:
ARG ARCH=amd64
ARG NODE_VERSION=22.13.0
ARG OS=alpine
#### Stage BASE ########################################################################################################
FROM ${ARCH}/node:${NODE_VERSION}-${OS} AS base
# get latest npm version
RUN npm install -g "npm@11.0.0"
RUN echo $NODE_VERSION
# Copy scripts
COPY scripts/*.sh /tmp/
# Install tools, create Node-RED app and data dir, add user and set rights
RUN set -ex && \
apk add --no-cache \
bash \
tzdata \
iputils \
curl \
nano \
git \
openssl \
openssh-client \
ca-certificates \
openssh-keygen && \
mkdir -p /usr/src/node-red /data /usr/local/bacnet-stack/programs && \
deluser --remove-home node && \
adduser -h /usr/src/node-red -D -H node-red -u 1000 && \
chown -R node-red:root /data && chmod -R g+rwX /data && \
chown -R node-red:root /usr/src/node-red && chmod -R g+rwX /usr/src/node-red
# chown -R node-red:node-red /data && \
# chown -R node-red:node-red /usr/src/node-red
# Set work directory
WORKDIR /usr/src/node-red
# Setup SSH known_hosts file
RUN /tmp/known_hosts.sh /etc/ssh/ssh_known_hosts && rm /tmp/known_hosts.sh
RUN echo "PubkeyAcceptedKeyTypes +ssh-rsa" >> /etc/ssh/ssh_config
COPY scripts/entrypoint.sh .
# copy package.json (contains Node-RED NPM module and node dependencies), settings.js, projects and env files
COPY package.json .
#### Stage BUILD #######################################################################################################
FROM base AS build
# Install Build tools
RUN apk add --no-cache --virtual buildtools build-base cmake linux-headers udev python3 && \
npm install --unsafe-perm --no-update-notifier --no-fund --omit=dev && \
/tmp/remove_native_gpio.sh && \
cp -R node_modules prod_node_modules
# BACnet Stack build process
WORKDIR /usr/local
RUN rm -rf /usr/local/bacnet-stack && \
git clone https://github.com/bacnet-stack/bacnet-stack.git --depth 1 && \
cd bacnet-stack && \
mkdir -p build/programs && cd build && \
cmake .. && \
make && \
cp /usr/local/bacnet-stack/build/whois /usr/local/bacnet-stack/build/programs/bacnet-whois && \
cp /usr/local/bacnet-stack/build/readprop /usr/local/bacnet-stack/build/programs/bacnet-read && \
cp /usr/local/bacnet-stack/build/readpropm /usr/local/bacnet-stack/build/programs/bacnet-read-multiple && \
cp /usr/local/bacnet-stack/build/writeprop /usr/local/bacnet-stack/build/programs/bacnet-write && \
cp /usr/local/bacnet-stack/build/bacdiscover /usr/local/bacnet-stack/build/programs/bacnet-discover && \
cp /usr/local/bacnet-stack/build/ack-alarm /usr/local/bacnet-stack/build/programs/bacnet-acknowledge-alarm
#### Stage RELEASE #####################################################################################################
FROM base AS release
ARG BUILD_DATE
ARG BUILD_VERSION
ARG BUILD_REF
ARG NODE_RED_VERSION
ARG ARCH
ARG TAG_SUFFIX=default
ARG ENVIRONMENT=dev
LABEL org.label-schema.build-date=${BUILD_DATE} \
org.label-schema.docker.dockerfile=".docker/Dockerfile.alpine" \
org.label-schema.license="Apache-2.0" \
org.label-schema.name="Node-RED" \
org.label-schema.version=${BUILD_VERSION} \
org.label-schema.description="Low-code programming for event-driven applications." \
org.label-schema.url="https://nodered.org" \
org.label-schema.vcs-ref=${BUILD_REF} \
org.label-schema.vcs-type="Git" \
org.label-schema.vcs-url="https://github.com/node-red/node-red-docker" \
org.label-schema.arch=${ARCH} \
authors="Dave Conway-Jones, Nick O'Leary, James Thomas, Raymond Mouthaan"
COPY --from=build /usr/src/node-red/prod_node_modules ./node_modules
# Copy BACnet Stack tools from build stage
COPY --from=build /usr/local/bacnet-stack/build /usr/local/bacnet-stack/
# Chown, install devtools & Clean up
RUN chown -R node-red:root /usr/src/node-red && \
chown -R node-red:root /usr/local/bacnet-stack && \
/tmp/install_devtools.sh && \
rm -r /tmp/*
RUN npm config set cache /data/.npm --global
USER node-red
# Env variables
ENV NODE_RED_VERSION=${NODE_RED_VERSION} \
NODE_PATH=/usr/src/node-red/node_modules:/data/node_modules \
PATH=/usr/src/node-red/node_modules/.bin:${PATH} \
PATH=${PATH}:/usr/local/bacnet-stack/programs \
FLOWS=flows.json \
ENVIRONMENT=${ENVIRONMENT}
ENV TZ="UTC"
# ENV NODE_RED_ENABLE_SAFE_MODE=true # Uncomment to enable safe start mode (flows not running)
# ENV NODE_RED_ENABLE_PROJECTS=true # Uncomment to enable projects option
# Expose the listening port of node-red
EXPOSE 1880
EXPOSE 47808
# Add a healthcheck (default every 30 secs)
# HEALTHCHECK CMD curl http://localhost:1880/ || exit 1
# ENTRYPOINT ["npm", "start", "--cache", "/data/.npm", "--", "--userDir", "/data"]
ENTRYPOINT ["./entrypoint.sh"]
As I mentioned sharing the same directory for the root container build and the /data means that they will have clashing package.json file. These should NOT be the same file, they should contain different things (one is for installing Node-RED into the container, the other (in /data) is for keeping track of installed nodes.
If you have rebuilt the container after installing the dashbaord it will have installed the dashbaord nodes (and any other nodes previously installed) under /usr/src/nodered when the container was built and you can not remove those nodes as they are baked into the container.
This would show the symptoms you have described.
I suggest you start again and ensure that you use use a separate directory mounted as /data
1 Like
This is really intriguing. So I could create a separate ./docker folder to put my docker files in. Keep the docker config files there as well as an image package.json. However, the current root level package.json is where the runtime package changes are applied to? And as seems common in NR, we make these changes live in production. So let's say we add or update a package needed for integrating a system (for example modbus node in NR), we do that in palette manager and it is added to /data/package.json (runtime). However, would we then need to synchronize this to also add to image build stage package.json? Or perhaps keep the image context package.json minimal and limited to core dependencies like node red only.
I did a quick test to see the contents of /usr/src/node-red inside the container, and while it has the node_modules folder, it doesn't currently have a package.json. But this is of course post build stage, so perhaps irrelevant.
While I wasn't initially aware of this fumble I made, my thinking was whatever changes is done to runtime /data/package.json needs to be shared, synced and applied to future images/containers.