Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/device-agent/install/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ navTitle: Installation
redirect:
to: /docs/device-agent/install/overview
layout: redirect
navOrder: 1
navOrder: 3
tags:
- noDropdown
---
2 changes: 1 addition & 1 deletion docs/device-agent/install/docker.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
navGroup: DeviceAgentInstallation
navTitle: Docker Install
navOrder: 4
navOrder: 3
meta:
description: Run the FlowFuse Device Agent with Docker or Docker Compose, including configuration binding, ports, time zone, and verification steps.
tags:
Expand Down
191 changes: 191 additions & 0 deletions docs/device-agent/install/kubernetes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
---
navGroup: DeviceAgentInstallation
navTitle: Kubernetes Install
navOrder: 4
meta:
description: Run the FlowFuse Device Agent in a Kubernetes cluster
tags:
- device agent
- kubernetes
- installation
---

# Kubernetes Install

## When to Use Each Option

Running the Device Agent in Kubernetes is appropriate when devices are containerized or managed as part of a Kubernetes-based edge or infrastructure platform.

Choose your deployment pattern based on how you manage device identity:

- **Fixed Configuration**
Use when the device already exists in FlowFuse and you have a `device.yml` with its credentials. One deployment maps to one device identity.

- **Automatic Provisioning**
Use when devices should register themselves at startup using a Provisioning Token. Each instance requires writable persistent storage.

Any deployment on Kubernetes is going to be specific to the environment and requirements of the solution. The following examples show two common patterns for running the FlowFuse Device Agent on Kubernetes:

- Fixed configuration using a static `device.yml`
- Automatic provisioning using a FlowFuse Provisioning Token

Choose the approach that matches how you manage device lifecycle and credentials.

## Fixed Configuration

If you have an existing `device.yml` file containing a set of Device Agent credentials.

```bash
kubectl create secret generic device-one-secret --from-file=device.yml=./device.yml
```

The following manifest will create a Deployment and Service for a device using the supplied Secret as its credentials

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: device-one
labels:
app: device-one
spec:
replicas: 1 # there can only be one replica as there is one configuration
revisionHistoryLimit: 10
selector:
matchLabels:
app: device-one
template:
metadata:
labels:
app: device-one
spec:
containers:
- name: device-one
image: flowfuse/device-agent:latest
ports:
- containerPort: 1880
volumeMounts:
- name: config
mountPath: "/opt/flowfuse-device/device.yml"
subPath: "device.yml"
readOnly: true
resources:
limits:
cpu: 1000m
memory: 256Mi
requests:
cpu: 500m
memory: 128Mi
volumes:
- name: config
secret:
secretName: device-one-secret
---
apiVersion: v1
kind: Service
metadata:
name: device-one-service
spec:
selector:
app: device-one
ports:
- protocol: TCP
port: 1880
targetPort: 1880
```

## Automatic Provisioning

Using a FlowFuse Provisioning Token to automatically configure a new Device Agent on deployment.

Because the Device Agent will need to re-write the `device.yml` file it can no longer be stored in a Secret and a PersistentVolume must be used for each instance of the Device Agent.

A Secret is used to hold the initial `device.yml` which contains the provisioning token.

```bash
kubectl create secret generic device-provisioning-secret --from-file=device.yml=./device.yml
```

The following manifest will create a Deployment, Service and PVC for a device using the supplied Secret as the source of the Provisioning token.

The PVC will be used to store the updated `device.yml` and the Node-RED nodes installed by the Remote Instance.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: device-one
labels:
app: device-one
spec:
replicas: 1 # to scale to more than one instance you should modify this to use a StatefulSet
revisionHistoryLimit: 10
selector:
matchLabels:
app: device-one
template:
metadata:
labels:
app: device-one
spec:
initContainers: # on first run copies the device.yml from Secret to PVC volume
- name: config-copy
image: busybox:latest
command:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this initContainer only copies the file if it does not already exist, should we add a short note explaining that the provisioning configuration is only applied on first start and that subsequent restarts preserve the existing device.yml on the pvc?

- "/bin/sh"
- "-c"
- "if [ ! -f /opt/flowfuse-device/device.yml ]; then cp /tmp/device.yml /opt/flowfuse-device/device.yml; fi"
volumeMounts:
- name: config
mountPath: "/opt/flowfuse-device"
- name: initial-config
mountPath: "/tmp/device.yml"
subPath: "device.yml"
readOnly: true
containers:
- name: device-one
image: flowfuse/device-agent:latest
ports:
- containerPort: 1880
volumeMounts:
- name: config
mountPath: "/opt/flowfuse-device"
resources:
limits:
cpu: 1000m
memory: 256Mi
requests:
cpu: 500m
memory: 128Mi
volumes:
- name: initial-config
secret:
secretName: device-provisioning-secret
- name: config
persistentVolumeClaim:
claimName: device-one-pvc

---
apiVersion: v1
kind: Service
metadata:
name: device-one-service
spec:
selector:
app: device-one
ports:
- protocol: TCP
port: 1880
targetPort: 1880
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: device-one-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this assumes the cluster has a default StorageClass. Should we add a brief note that users may need to set storageClassName depending on their Kubernetes setup, for example storageClassName: <your-storage-class>?

Also, should we mention what gets stored here (the updated device.yml and installed nodes) so users can size the pvc appropriately?

```
2 changes: 1 addition & 1 deletion docs/device-agent/install/manual.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
navGroup: DeviceAgentInstallation
navTitle: Manual Install with NPM
navOrder: 3
navOrder: 5
meta:
description: Install the FlowFuse Device Agent using NPM, configure its working directory and service, and verify the setup.
tags:
Expand Down
4 changes: 3 additions & 1 deletion docs/device-agent/install/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ meta:

## Choose your install path

Most users should use the Device Agent Installer. Power users can choose Manual ( using `npm`) or Docker deployments.
**Recommended for most users:** Use the Device Agent Installer (Quick Start), the fastest way to deploy with minimal configuration. Power users can choose Manual (using `npm`), Docker, or Kubernetes deployments.

- Recommended: Use the Device Agent Installer
- Fastest way to get started with a one-line command in the [Quick Start guide](../quickstart.md)
Expand All @@ -23,6 +23,8 @@ Most users should use the Device Agent Installer. Power users can choose Manual
- Install the npm package, set working directory, configure, and run as a service. See [Manual install](./manual.md)
- Alternative: Docker / Docker Compose
- Run the agent in a container; bind-mount the configuration. See [Docker install](./docker.md)
- Alternative: Kubernetes
- Deploy the agent in a Kubernetes cluster. See [Kubernetes install](./kubernetes.md)

## Prerequisites

Expand Down