Hi.
I note that there are no official docs for deploying node-red on k8s, so here's what I've done:
---
apiVersion: v1
kind: Service
metadata:
name: node-red-service
annotations:
"external-dns.alpha.kubernetes.io/ttl": "5"
"external-dns.alpha.kubernetes.io/hostname": <FQDN-HERE>
spec:
type: LoadBalancer
selector:
app: node-red
ports:
- protocol: TCP
port: 443
targetPort: 1880
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: node-red-cert
spec:
secretName: node-red-tls
duration: 2160h # 90d
renewBefore: 360h # 15d
subject:
organizations:
- <ORG-HERE>
isCA: false
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
usages:
- server auth
- client auth
dnsNames:
- <FQDN-HERE>
issuerRef:
name: cluster-letsencrypt-issuer
kind: ClusterIssuer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
creationTimestamp: null
labels:
app: node-red
name: node-red-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: node-red
name: node-red
namespace: node-red
spec:
replicas: 1
selector:
matchLabels:
app: node-red
strategy:
type: Recreate
template:
metadata:
labels:
app: node-red
spec:
securityContext:
fsGroup: 1000
runAsUser: 1000
runAsGroup: 1000
containers:
- image: nodered/node-red
command: ['/mnt/config/startup.sh']
imagePullPolicy: Always
name: node-red
ports:
- containerPort: 1880
protocol: TCP
resources: {}
envFrom:
- secretRef:
name: node-red-okta-creds
- secretRef:
name: node-red-keys
env:
- name: FLOWS
value: "-s /mnt/config/settings.js"
- name: WEB_DOMAIN
value: <FQDN-HERE>
- name: DO_NPM_INSTALL
value: passport-okta-oauth
- name: TZ
value: UTC
- name: PGID
value: "1000"
- name: PUID
value: "1000"
volumeMounts:
- name: node-red-data
mountPath: /data
- name: node-red-config
mountPath: /mnt/config
- name: node-red-tls
mountPath: /mnt/tls
readOnly: true
volumes:
- name: node-red-data
persistentVolumeClaim:
claimName: node-red-data
- name: node-red-config
configMap:
name: node-red-configmap
defaultMode: 0754
- name: node-red-tls
secret:
secretName: node-red-tls
---
apiVersion: v1
kind: ConfigMap
metadata:
name: node-red-configmap
data:
settings.js: |
module.exports = {
credentialSecret: process.env.CREDS_KEY || false,
flowFile: 'flows.json',
flowFilePretty: true,
adminAuth: {
type:"strategy",
strategy: {
name: "okta",
label: 'Sign in with Okta',
icon:"fa-o",
strategy: require("passport-okta-oauth").Strategy,
options: {
audience: process.env.OKTA_AUDIENCE,
clientID: process.env.OKTA_CLIENTID,
clientSecret: process.env.OKTA_CLIENTSECRET,
// idp: process.env.OKTA_IDP,
scope: ['openid', 'email', 'profile'],
response_type: 'code',
callbackURL: "https://" + process.env.WEB_DOMAIN + "/auth/strategy/callback",
verify: (token, tokenSecret, profile, done) => {
//console.log(profile)
return done(null, profile);
}
},
},
users: (username) =>{
return Promise.resolve({ username: username, permissions: ["*"] })
}
},
https: {
key: require("fs").readFileSync('/mnt/tls/tls.key'),
cert: require("fs").readFileSync('/mnt/tls/tls.crt')
},
requireHttps: true,
uiPort: process.env.PORT || 1880,
diagnostics: {
enabled: true,
ui: true,
},
runtimeState: {
enabled: false,
ui: false,
},
logging: {
console: {
level: "info",
metrics: false,
audit: true
}
},
exportGlobalContextKeys: false,
externalModules: {
},
editorTheme: {
palette: {
},
projects: {
enabled: false,
workflow: {
mode: "manual"
}
},
codeEditor: {
lib: "monaco",
options: {
}
}
},
functionExternalModules: true,
functionGlobalContext: {
},
debugMaxLength: 1000,
mqttReconnectTime: 15000,
serialReconnectTime: 15000,
}
startup.sh: |
#!/bin/sh
set -e
cd ~
for DNI in $DO_NPM_INSTALL; do
echo "Installing NPM package: $DNI"
npm install "$DNI"
done
exec ./entrypoint.sh $@
Some notes on this setup:
- Makes use of dns-external to update DNS records
- Makes use of cert-manager for certificate generation/handling
- Overrides entrypoint to allow extra packages to be installed (e.g. for auth)
- Uses Okta OIDC authentication (you dont have to, but I left everything in)
- Misuses the FLOWS envvar to pass arguments to node-red (e.g. the location of the settings.js from the config map)
- Although a Deployment, its not safe for replica >1 - As such it should probably be a Pod.