Skip to content
Stand with Ukraine flag

GKE Monolith Setup

This guide walks you through deploying ThingsBoard CE in monolith mode on Google Kubernetes Engine. We use Google Cloud SQL for managed PostgreSQL.

Install kubectl and gcloud. See before you begin for more info.

Create a new GCP project (recommended) or choose an existing one:

Terminal window
gcloud init
Terminal window
gcloud services enable container.googleapis.com sql-component.googleapis.com sqladmin.googleapis.com

Step 1. Clone ThingsBoard CE K8S scripts repository

Section titled “Step 1. Clone ThingsBoard CE K8S scripts repository”
Terminal window
git clone -b release-4.3 https://github.com/thingsboard/thingsboard-ce-k8s.git
cd thingsboard-ce-k8s/gcp/monolith
Terminal window
export GCP_PROJECT=$(gcloud config get-value project)
export GCP_REGION=us-central1
export GCP_ZONE=us-central1-a
export GCP_NETWORK=default
export TB_CLUSTER_NAME=tb-ce
export TB_DATABASE_NAME=tb-db
echo "Project: $GCP_PROJECT, region: $GCP_REGION, zone: $GCP_ZONE, network: $GCP_NETWORK, cluster: $TB_CLUSTER_NAME, database: $TB_DATABASE_NAME"
VariableDefaultDescription
GCP_PROJECT(auto-detected)Your GCP project ID
GCP_REGIONus-central1Compute region
GCP_ZONEus-central1-aCompute zone (must match region)
GCP_NETWORKdefaultGCP network name
TB_CLUSTER_NAMEtb-ceGKE cluster name
TB_DATABASE_NAMEtb-dbCloud SQL instance name

Create a zonal cluster with 1 node of e2-standard-4 machine type:

Terminal window
gcloud container clusters create $TB_CLUSTER_NAME \
--release-channel stable \
--zone $GCP_ZONE \
--node-locations $GCP_ZONE \
--network=$GCP_NETWORK \
--enable-ip-alias \
--num-nodes=1 \
--node-labels=role=main \
--machine-type=e2-standard-4

Alternatively, see the custom cluster setup guide.

Terminal window
gcloud container clusters get-credentials $TB_CLUSTER_NAME --zone $GCP_ZONE

5.1 Google Cloud SQL (PostgreSQL) instance

Section titled “5.1 Google Cloud SQL (PostgreSQL) instance”

Enable service networking:

Terminal window
gcloud services enable servicenetworking.googleapis.com --project=$GCP_PROJECT
gcloud compute addresses create google-managed-services-$GCP_NETWORK \
--global \
--purpose=VPC_PEERING \
--prefix-length=16 \
--network=projects/$GCP_PROJECT/global/networks/$GCP_NETWORK
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--ranges=google-managed-services-$GCP_NETWORK \
--network=$GCP_NETWORK \
--project=$GCP_PROJECT

Create a PostgreSQL 16 instance. Recommendations:

  • Use the same region and VPC network as your GKE cluster
  • Use private IP address and disable public IP
  • Use highly available instance for production, single zone for development
  • At least 2 vCPUs and 7.5 GB RAM
Terminal window
gcloud beta sql instances create $TB_DATABASE_NAME \
--database-version=POSTGRES_16 \
--region=$GCP_REGION --availability-type=regional \
--no-assign-ip --network=projects/$GCP_PROJECT/global/networks/$GCP_NETWORK \
--cpu=2 --memory=7680MB

Note the IP address (YOUR_DB_IP_ADDRESS) from the command output.

Terminal window
gcloud sql users set-password postgres \
--instance=$TB_DATABASE_NAME \
--password=secret
Terminal window
gcloud sql databases create thingsboard --instance=$TB_DATABASE_NAME

Using Cassandra is optional. We recommend it if you plan to insert more than 5K data points per second or want to optimize storage space.

Create 3 separate node pools with 1 node per zone. At least 4 vCPUs and 16 GB of RAM is recommended.

Terminal window
gcloud container node-pools create cassandra1 --cluster=$TB_CLUSTER_NAME --zone=$GCP_ZONE --node-locations=$GCP_ZONE1 \
--node-labels=role=cassandra --num-nodes=1 --min-nodes=1 --max-nodes=1 --machine-type=e2-standard-4
gcloud container node-pools create cassandra2 --cluster=$TB_CLUSTER_NAME --zone=$GCP_ZONE --node-locations=$GCP_ZONE2 \
--node-labels=role=cassandra --num-nodes=1 --min-nodes=1 --max-nodes=1 --machine-type=e2-standard-4
gcloud container node-pools create cassandra3 --cluster=$TB_CLUSTER_NAME --zone=$GCP_ZONE --node-locations=$GCP_ZONE3 \
--node-labels=role=cassandra --num-nodes=1 --min-nodes=1 --max-nodes=1 --machine-type=e2-standard-4
Terminal window
kubectl apply -f tb-namespace.yml
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard
kubectl apply -f receipts/cassandra.yml
Terminal window
echo " DATABASE_TS_TYPE: cassandra" >> tb-node-db-configmap.yml
echo " CASSANDRA_URL: cassandra:9042" >> tb-node-db-configmap.yml
echo " CASSANDRA_LOCAL_DATACENTER: $GCP_REGION" >> tb-node-db-configmap.yml
Terminal window
kubectl exec -it cassandra-0 -- bash -c "cqlsh -e \
\"CREATE KEYSPACE IF NOT EXISTS thingsboard \
WITH replication = { \
'class' : 'NetworkTopologyStrategy', \
'us-central1' : '3' \
};\""

Edit tb-node-db-configmap.yml and replace YOUR_DB_IP_ADDRESS and YOUR_DB_PASSWORD:

Terminal window
nano tb-node-db-configmap.yml

Run the installation:

Terminal window
./k8s-install-tb.sh --loadDemo

Where --loadDemo is an optional argument to load additional demo data.

After this command finishes you should see:

Installation finished successfully!
Terminal window
./k8s-deploy-resources.sh

After a few minutes, call kubectl get pods. If everything went fine, you should see tb-node-0 pod in the READY state.

You have 3 options:

  • HTTP — recommended for development. Simple configuration and minimum costs.
  • HTTPS — recommended for production. Uses Google-managed SSL certificate with automatic HTTP to HTTPS redirect.
  • Transparent — forwards traffic to ThingsBoard HTTP/HTTPS ports. Requires you to provision your own SSL certificate.
Terminal window
kubectl apply -f receipts/http-load-balancer.yml

Check the status:

Terminal window
kubectl get ingress

Use the address to access the web UI (port 80) and connect devices via HTTP API.

Default credentials:

The process of configuring the load balancer with Google-managed SSL certificates is described in the official documentation. Make sure you read the prerequisites.

Reserve a static IP address:

Terminal window
gcloud compute addresses create thingsboard-http-lb-address --global

Edit receipts/https-load-balancer.yml and replace PUT_YOUR_DOMAIN_HERE with your domain name:

Terminal window
nano receipts/https-load-balancer.yml

Deploy:

Terminal window
kubectl apply -f receipts/https-load-balancer.yml

Check the status:

Terminal window
kubectl get ingress

Assign the domain name to the load balancer IP address. Then wait for the Google-managed certificate to finish provisioning (up to 60 minutes):

Terminal window
kubectl describe managedcertificate managed-cert

Follow the HTTPS (TLS) configuration guide to configure SSL in tb-node.yml. Then deploy:

Terminal window
kubectl apply -f receipts/transparent-http-load-balancer.yml

8.2 Configure MQTT load balancer (optional)

Section titled “8.2 Configure MQTT load balancer (optional)”
Terminal window
kubectl apply -f receipts/mqtt-load-balancer.yml

The load balancer forwards all TCP traffic for ports 1883 and 8883.

For MQTT over SSL, follow the MQTT over SSL guide to configure the required environment variables in tb-node.yml.

8.3 Configure UDP load balancer (optional)

Section titled “8.3 Configure UDP load balancer (optional)”
Terminal window
kubectl apply -f receipts/udp-load-balancer.yml

The load balancer forwards all UDP traffic for ports:

PortProtocol
5683CoAP non-secure
5684CoAP secure DTLS
5685LwM2M non-secure
5686LwM2M secure DTLS
5687LwM2M bootstrap DTLS
5688LwM2M bootstrap secure DTLS

For CoAP over DTLS, follow the CoAP over DTLS guide. For LwM2M over DTLS, follow the LwM2M over DTLS guide.

8.4 Configure Edge load balancer (optional)

Section titled “8.4 Configure Edge load balancer (optional)”
Terminal window
kubectl apply -f receipts/edge-load-balancer.yml

The load balancer forwards all TCP traffic on port 7070. Use the external IP as CLOUD_RPC_HOST in Edge connection parameters.

Terminal window
kubectl get ingress
Terminal window
kubectl get service

Two load balancers are available:

  • tb-mqtt-loadbalancer — for MQTT protocol
  • tb-udp-loadbalancer — for CoAP/LwM2M protocols
Terminal window
kubectl logs -f tb-node-0

See the kubectl Cheat Sheet for more details.

If a database upgrade is needed:

Terminal window
./k8s-delete-resources.sh
./k8s-upgrade-tb.sh --fromVersion=[FROM_VERSION]
./k8s-deploy-resources.sh

Where FROM_VERSION is the starting version. See Upgrade Instructions for valid values. Upgrade versions one by one.

Delete ThingsBoard pods and load balancers:

Terminal window
./k8s-delete-resources.sh

Delete all data including database:

Terminal window
./k8s-delete-all.sh