introduction
MQTT is a lightweight messaging protocol for IoT applications to communicate between devices. As a mainstream open source MQTT Broker, EMQX can provide highly scalable, reliable and secure MQTT messaging services.
With Terraform, a widely used infrastructure-as-code (IaC) tool, you can easily and automatically deploy EMQX MQTT Broker on GCP, thereby simplifying and standardizing the setup and management of MQTT infrastructure.
This article will guide you how to set up GCP projects, create service accounts, and write Terraform configuration files to easily deploy EMQX MQTT Broker.
Preparation
Before you begin, prepare the following:
- Sign up for a Google Cloud Platform account
- Install the Google Cloud SDK on your local machine
- Install Terraform on your local machine
- Basic understanding of GCP, Terraform and MQTT
Configure the GCP environment
Follow the steps below to configure your GCP environment:
- Create a new GCP project or use an existing project (Project).
- Enable the required API (Compute Engine API) for your project.
- Create a service account for Terraform with the required permissions. The Compute Engine Admin role is recommended.
- Download the JSON key file.
Deploy EMQX on GCP using Terraform
Configure Terraform
Configure the GCP Provider in your Terraform code and use the service account key file for authentication.
provider "google" {
credentials = file("<PATH-TO-KEY-FILE>")
project = "<PROJECT-ID>"
region = "<REGION>"
zone = "<ZONE>"
}
configure network
This step requires an understanding of three basic terms related to GCP: project, VPC, and subnet. The definitions of these terms are as follows:
- A project is the top-level organizational unit in GCP and contains all resources.
- A VPC is a private network defined within a GCP project that allows you to create and manage IP addresses, subnets, and route tables.
- Subnets are a way of dividing a VPC network into smaller, more manageable sections. They can assign IP addresses to specific resources and define different network segments.
The relationship between them can be illustrated by the following figure:
Create a VPC network
We need to create a VPC network to provide connectivity for your network-related resources, including:
- Compute Engine VM instance
- Container Engine container
- App Engine Flex Services
- Other web-related resources
resource "google_compute_network" "vnet" {
project = "<PROJECT>"
name = "<NAME>"
auto_create_subnetworks = false
}
Create subnets in VPC
Each VPC network is divided into several subnets, here we create a subnet.
resource "google_compute_subnetwork" "sn" {
name = "<NAME>"
ip_cidr_range = cidrsubnet(var.address_space, 8, 1)
region = var.region
network = google_compute_network.vnet.id
}
Create firewall rules
Each network has its own firewall that controls access between instances and between instances and the outside world. All traffic to the instance, including traffic from other instances, is blocked by the firewall unless firewall rules are created to allow access to the instance.
"ports" defines some MQTT-related ports, such as "1883", "8883", "8083", "8084".
resource "google_compute_firewall" "fw" {
name = "<NAME>"
network = google_compute_network.vnet.name
source_ranges = ["0.0.0.0/0"]
allow {
protocol = "icmp"
}
allow {
protocol = "tcp"
ports = "<PORTS>"
}
}
Configure EMQX cluster
Create a virtual machine instance for each EMQX node
Virtual machine instances can be used to deploy applications, run services, or perform computing tasks.
In the example below, we create a google_compute_instance resource called example-instance and specify the name, machine_type, boot_disk, network_interface properties.
resource "google_compute_instance" "example" {
name = "example-instance"
machine_type = "n1-standard-1"
boot_disk {
initialize_params {
image = ""ubuntu-os-cloud/ubuntu-2004-lts""
}
}
network_interface {
network = google_compute_network.example.name
subnetwork = google_compute_subnetwork.example.name
access_config {
// Ephemeral external IP
}
}
}
Start the EMQX node
After creating a virtual machine instance, each EMQX node needs to be initialized. First, you must initialize and copy init.sh to each node. Then download the EMQX package and execute the copied init.sh on each node . Finally, start EMQX respectively.
resource "null_resource" "init" {
depends_on = [google_compute_instance.example]
count = "<INSTANCE-COUNT>"
connection {
type = "ssh"
host = "<HOST-LIST>"
user = "ubuntu"
private_key = "<YOUR-PRIVATE-KEY>"
}
# config init script
provisioner "file" {
content = templatefile("${path.module}/scripts/init.sh", { local_ip = <PRIVATE-IPS>[count.index],
emqx_lic = <EMQX-LICENSE>, emqx_ca = <EMQX-CA> emqx_cert = <EMQX-CERT>, emqx_key = <PRIVATE-KEY> })
destination = "/tmp/init.sh"
}
# download EMQX package
provisioner "remote-exec" {
inline = [
"curl -L --max-redirs -1 -o /tmp/emqx.zip <EMQX-PACKAGE-URL>"
]
}
# init system
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/init.sh",
"/tmp/init.sh",
"sudo mv /tmp/emqx <HOME>",
]
}
# start EMQX
provisioner "remote-exec" {
inline = [
"sudo <HOME>/bin/emqx start"
]
}
}
Add EMQX nodes to the cluster
Randomly select a node in the EMQX cluster, and then add other nodes to this node one by one.
resource "null_resource" "emqx_cluster" {
depends_on = [null_resource.init]
count = "<INSTANCE-COUNT>-1"
connection {
type = "ssh"
host = <OTHERS>[count.index % <OTHERS>]
user = "ubuntu"
private_key = "<YOUR-PRIVATE-KEY>"
}
provisioner "remote-exec" {
inline = [
"/home/ubuntu/emqx/bin/emqx_ctl cluster join emqx@${local.another_emqx}"
]
}
}
Configure load balancing
In the example above:
- Created a google_compute_http_health_check resource for configuring health checks.
- A google_compute_target_pool resource is created, which references the instance group and health check.
- Created a google_compute_forwarding_rule resource that sets forwarding rules to route inbound traffic on port 1883 to the target pool.
- You can also add more google_compute_forwarding_rules for other ports ("8883", "8083", "8084", "18083").
resource "google_compute_http_health_check" "example" {
name = "example-health-check"
check_interval_sec = 30
timeout_sec = 5
port = 8081
request_path = "/status"
}
resource "google_compute_target_pool" "example" {
name = "example-target-pool"
instances = [
google_compute_instance_group.example.self_link
]
health_checks = [
google_compute_http_health_check.example.name
]
}
resource "google_compute_forwarding_rule" "example-1883" {
name = "example-forwarding-rule"
target = google_compute_target_pool.example.self_link
port_range = "1883"
ip_protocol = "TCP"
}
resource "google_compute_forwarding_rule" "example-8883" {
...
}
Initialize and apply Terraform
terraform init
terraform plan
terraform apply
When applied successfully, the following will be output:
Outputs:
loadbalancer_ip = ${loadbalancer_ip}
tls_ca = <sensitive>
tls_cert = <sensitive>
tls_key = <sensitive>
You can now access different services through the corresponding ports.
Dashboard: ${loadbalancer_ip}:18083
MQTT: ${loadbalancer_ip}:1883
MQTTS: ${loadbalancer_ip}:8883
WS: ${loadbalancer_public_ip}:8083
WSS: ${loadbalancer_public_ip}:8084
epilogue
Using Terraform to deploy EMQX on GCP allows you to easily manage IoT infrastructure and focus on creating IoT applications. Following the guidelines in this article, you can quickly build an MQTT Broker with strong scalability and high reliability on GCP to provide support for your IoT projects.
Copyright statement: This article is original by EMQ, please indicate the source for reprinting.
Original link: https://www.emqx.com/zh/blog/one-click-deploying-emqx-mqtt-broker-on-gcp-using-terraform