GCP | Dynamic GLB Backend Service with “dynamic” block using Terraform
By: Ravish Kumar
Tags: Load Balancing, Blue Green Deployment, Google Cloud Platform, Terraform Provider, Terraform

Terraform is a popular and widely accepted tool for provisioning, changing, and versioning infrastructure efficiently. I have used it for both Cloud and OnPrem solutions. There is a new feature in 0.12.x version onwards which, helped to solve a tricky problem that was not present in earlier versions.

I will try to keep it short and crisp.

Problem Statement:

Backend Service resource in GLB needs to be generated dynamically as per the user’s input. Additionally, “capacity_scaler” which represents the servicing capacity for each backend service resource, needs to be adjusted dynamically as per the user’s input.

For this blog, a random backend resource is used. Each Backend resource will be forwarding the traffic to the GKE Ingress.

This will help to perform blue/green deployment traffic shift from the GLB perspective.

More info :

https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_backend_service#backend

Check below the pictorial representation of GLB Traffic Shift for Blue/Green Deployment.

Solution:

Using the “dynamic” block feature of terraform to generate main.tf with dynamic Backend blocks.

“capacity_scaler” will be gradually decremented to slowly drain the traffic from the active cluster(green), and incremented for inactive(blue) to start the traffic flow. Valid range is [0.0,1.0]. Value of 1 means 100%.

Repeated nested blocks will be created as per user input within the top-level resource construct. User’s input will be supplied by variables.tfvars file.

More info about the feature — https://www.terraform.io/docs/configuration/expressions.html#dynamic-blocks

Code snippet-

$ cat main.tf

//Backend Configuration

resource "google_compute_backend_service" "glb_backend" {

provider = google-beta

project = sandbox-project

name = "test-backend"

port_name = "http"

protocol = "HTTP"

timeout_sec = "10"



dynamic "backend" {

for_each = var.enable_backend1 == "true" ? var.backend1 : []

content {

group = backend.value["group"]

balancing_mode = "RATE"

max_rate = 1000

capacity_scaler = backend.value["capacity_scaler"]



}

}



dynamic "backend" {

for_each = var.enable_backend2 == "true" ? var.backend2 : []

content {

group = backend.value["group"]

balancing_mode = "RATE"

max_rate = 1000

capacity_scaler = backend.value["capacity_scaler"]



}

}



health_checks = var.health

enable_cdn = "false"

}

Now let’s look at variables.

$ cat variables.tf

// Using count to determine creation.

variable "enable_backend1" {

description = "Count of backend resource"

} //List of map is used to provide self link and scaler values.

variable "backend1"{

type = list(map(string))

description = "Used in dynamic block for East4"

} // Using count to determine creation.

variable "enable_backend2" {

description = "Count of backend resource"

} //List of map is used to provide self link and scaler values.

variable "backend2"{

type = list(map(string))

description = "Used in dynamic block for East4"

} //Health check self link

variable "health" {

type = list

}

As per the diagram, the Green cluster is currently Active and the associated Backend resource is “backend2 a/b”.

Let’s see the variables.tfvars.

$ cat variables.tfvars

enable_backend1 = "false" ##Backend1 Self link and scaler values##

backend1 = [

{

group = "https://www.googleapis.com/compute/v1/<self-link-a>"

capacity_scaler = "0"

},

{

group = "https://www.googleapis.com/compute/v1/<self-link-b>"

capacity_scaler = "0"

},

] enable_backend2 = "true" ##Backend2 Self link and scaler values##

backend2 = [

{

group = "https://www.googleapis.com/compute/v1/<self-link-a>"

capacity_scaler = "1"

},

{

group = "https://www.googleapis.com/compute/v1/<self-link-b>"

capacity_scaler = "1"

},

] ##Health check URL##

health = ["https://www.googleapis.com/compute/v1/<self-link>"]

For gradual shift from Active ( green ) →Inactive ( blue), follow below modifications for each Terraform apply.

Enable the associated “Backend resource 1a/b”.

enable_backend1 = "true"

Update the scaler values of Backend 1a/b from 0 to 0.25 [this will enable 25% (0.25 × max-rate RPS) traffic to Blue Cluster].

backend1 = [

{

group = "https://www.googleapis.com/compute/v1/<self-link-a>"

capacity_scaler = "0.25"

},

{

group = "https://www.googleapis.com/compute/v1/<self-link-b>"

capacity_scaler = "0.25"

},

]

Valid ranges is [0.0,1.0]. So will gradually increase the scaler values for 1a/b.

0 → 0.25 ; 0.25 → 0.5 ; 0.5 → 0.75 ; 0.75 →1

For 100% (1.0 × max-rate RPS) traffic flow, the value is made 1. See below:-

backend1 = [

{

group = "https://www.googleapis.com/compute/v1/projects/<self-link-a>"

capacity_scaler = "1"

},

{

group = "https://www.googleapis.com/compute/v1/projects/<self-link-b>"

capacity_scaler = "1"

},

]

As the scaler will be made “1” for resource 1a/b; it’s time to decrease the scaler values for Backend 2a/b as:-

backend2 = [

{

group = "https://www.googleapis.com/compute/v1/projects/<self-link-a>"

capacity_scaler = "0.75"

},

{

group = "https://www.googleapis.com/compute/v1/projects/<self-link-b>"

capacity_scaler = "0.75"

},

]

Gradually decrease the value.

1 →0.75 ; 0.75 →0.5 ; 0.5 →0.25 ; 0.25 →0

With final value as 0, backend 2a/b will be servicing 0% (0.0 × max-rate RPS) traffic.

As a final switch, disable the Backend resource 2a/b to avoid accidental flow.

enable_backend2 = "false"

Once the switch is complete, variables.tfvars should look like as below:-

$ cat variables.tfvars

enable_backend1 = "true" ##Backend1 Self link and scaler values##

backend1 = [

{

group = "https://www.googleapis.com/compute/v1/<self-link-a>"

capacity_scaler = "1"

},

{

group = "https://www.googleapis.com/compute/v1/<self-link-b>"

capacity_scaler = "1"

},

] enable_backend2 = "false" ##Backend2 Self link and scaler values##

backend2 = [

{

group = "https://www.googleapis.com/compute/v1/<self-link-a>"

capacity_scaler = "0"

},

{

group = "https://www.googleapis.com/compute/v1/<self-link-b>"

capacity_scaler = "0"

},

] ##Health check URL##

health = ["https://www.googleapis.com/compute/v1/<self-link>"]

This concludes Blue/Green Switch from the GLB perspective.

That’s all !!!