Node-RED is another service that I run in my K3s cluster for experimenting with event-driven automation. Node-RED is described as:

Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways.

It provides a browser-based editor that makes it easy to wire together flows using the wide range of nodes in the palette that can be deployed to its runtime in a single-click.

I originally used Node-RED with a few Raspberry Pis, but found the tool interesting and useful enough to run a permanent instance in my cluster. There are tons of plugins that can extend the value of Node-RED well beyond its out-of-the-box functionality.

Configuring the Deployment

I run K3s in my home lab and leverage most of the built in utilities that come with it, such as Traefik ingress. I also have Longhorn installed for block storage provisioning.

I put all files created in this example in their own folder to separate this deployment from other deployments on my cluster.

Authorization

Node-RED is not a multi-user platform. Its UI is exposed unless you take action to secure it through other ingress, like your reverse proxy. In my case, I configured Basic Auth in the out-of-the-box Traefik ingress in K3s. We’ll use the htpasswd utility to create the password string and then base64 to encode it for k8s.

The full command is the following replacing user and password with the username and password that you want to use:

htpasswd -nb user password | openssl base64

And then we will create a secrets.yml file to store the output of that command.

Note: The example below contains a dummy output from the command above. You could use an environment variable and envsubst to remove any secrets from the file.

---
apiVersion: v1
kind: Secret
metadata:
  name: auth-secret
  namespace: node-red
data:
  users: |2
    dXNlcjokYXByMSRHaFZaT3VJLiRjMWRydDU5Nmo2SzhQSUV4Z21WWnoxCgo=

Headers

Now that the authorization secret is prepared, we can go about configuring the rest of the deployment resources.

First, we will create a headers.yml file that will create a Traefik middleware to manage the basic auth authorization.

---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: auth
  namespace: node-red
spec:
  basicAuth:
    secret: auth-secret

Storage

Next, create the file pvc.yml to request a persistent volume claim so that Node-RED can store its data. In my example below, I use the Longhorn storage provisioner, but it can be local storage or any other storage provisioner that you have in your cluster.

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: node-red-pvc
  namespace: node-red
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: longhorn
  resources:
    requests:
      storage: 1Gi

Service

Next create a service.yml file to expose the Node-RED service. The container exposes port 1880 by default. We’ll use our ingress to terminate TLS traffic later.

---
apiVersion: v1
kind: Service
metadata:
  name: node-red-service
  namespace: node-red

spec:
  ports:
    - name: web
      port: 1880
      targetPort: 1880

  selector:
    app: node-red

Ingress

Create an ingress.yml file to define the ingress. This ingress exposes both HTTP and HTTPS traffic, but I have a redirect middleware defined in the default namespace that reroutes HTTP to HTTPS. You also find the auth middleware defined in the node-red namespace, which applies basic auth to the ingress. I also use CertManager to issue TLS certs for TLS termination.

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: node-red-ingress
  namespace: node-red
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-redirect@kubernetescrd,node-red-auth@kubernetescrd
    traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
    cert-manager.io/cluster-issuer: letsencrypt-aws
spec:
  rules:
    - host: your.node-red.domain
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: node-red-service
                port:
                  number: 1880
  tls:
    - secretName: ssl-cert
      hosts:
        - your.node-red.domain

Deployment

Lastly, create a deployment.yml file to define the deployment.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: node-red
  name: node-red
  namespace: node-red
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-red
  template:
    metadata:
      labels:
        app: node-red
    spec:
      terminationGracePeriodSeconds: 40
      containers:
        - name: node-red
          image: nodered/node-red:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 1880
              protocol: TCP
          volumeMounts:
            - name: node-red-volume
              mountPath: /data
              readOnly: false
      volumes:
        - name: node-red-volume
          persistentVolumeClaim:
            claimName: node-red-pvc

Apply the Configuration

Once all files are created, we can run the following command to apply them to the cluster.

kubectl apply -f .

Watch the namespace and when the deployment is up and the TLS certs have been issued, then you should be able navigate to the domain name that you used for your ingress. You’ll then be presented with a username and password for the basic auth that you configured. Once logged in, you will be able to use Node-RED on your kubernetes cluster.