Introduction
Infrastructure as Code (IaC) has completely changed how modern cloud environments are deployed and managed.
Instead of manually creating:
- VPC networks
- Cloud SQL databases
- Compute instances
- Load balancers
- Autoscaling policies
Modern cloud environments require infrastructure that is:
- Repeatable
- Version-controlled
- Automated
- Scalable
- Easy to maintain
we can define the entire cloud architecture using Terraform and deploy it consistently. Manually creating cloud resources through the console works for experimentation, but enterprise environments need an Infrastructure as Code (IaC) approach.
In this hands-on guide, we will deploy a complete 3-tier web application architecture on Google Cloud using Terraform.
The solution includes:
- Custom VPC Network
- Regional Subnet
- Cloud NAT Gateway
- Cloud SQL PostgreSQL Database
- Compute Engine Managed Instance Group
- Auto Scaling
- External HTTP Load Balancer
- Health Checks
- Terraform Remote State using Cloud Storage
If you are new to Infrastructure as Code, check my Terraform beginner guide before continuing.
We will build a production-style architecture:
Architecture Components
The final infrastructure contains:
| Component | Resource Name |
|---|---|
| VPC Network | cepf-vpc |
| Subnet | cepf-subnet |
| Cloud SQL Instance | cepf-instance |
| Database | cepf-db |
| Database User | postgres |
| Instance Template | cepf-template-v2 |
| Managed Instance Group | cepf-infra-lb-group1-mig |
| Backend Service | cepf-infra-lb-backend-default |
| HTTP Load Balancer | cepf-infra-lb |
| Health Check | cepf-http-health-check |
| Cloud NAT | cepf-nat |
Project Structure
Terraform configuration:
cepf-iac
│
├── backend.tf
├── provider.tf
├── main.tf
├── variables.tf
├── network.tf
├── sql.tf
├── instance_template.tf
├── mig.tf
├── loadbalancer.tf
├── nat.tf
└── outputs.tf
Why Terraform?
Terraform allows us to define infrastructure using configuration files instead of manually clicking through the cloud console.
Traditional approach:
Console → Create Network
→ Create VM
→ Configure Firewall
→ Setup Database
→ Configure Load Balancer
Terraform approach:
Terraform Code
|
|
terraform apply
|
|
Google Cloud Infrastructure
Benefits:
- Infrastructure versioning
- Repeatable deployments
- Disaster recovery
- Automated provisioning
- Collaboration through Git
The deployed architecture contains three logical layers.
1. Presentation Layer
Responsible for receiving user traffic.
Components:
- Global External HTTP Load Balancer
- Backend Service
- Health Check
Traffic flow:
Client
|
|
HTTP Load Balancer
|
|
Backend Service
2. Application Layer
The application layer runs inside Compute Engine instances.
Components:
- Instance Template
- Regional Managed Instance Group
- Autoscaler
Configuration:
| Parameter | Value |
|---|---|
| Region | us-west1 |
| MIG Name | cepf-infra-lb-group1-mig |
| Minimum Instances | 2 |
| Maximum Instances | 4 |
| CPU Threshold | 60% |
| OS | Debian 12 |
Autoscaling:
CPU > 60%
2 VM
|
|
Scale Out
|
|
4 VM
3. Database Layer
Database layer uses:
- Cloud SQL
- PostgreSQL 14
Configuration:
| Parameter | Value |
|---|---|
| Instance Name | cepf-instance |
| Database Engine | PostgreSQL 14 |
| Database | cepf-db |
| User | postgres |
| Password | postgres |
Application communicates with Cloud SQL using:
Application VM
|
|
Cloud SQL Proxy
|
|
Cloud SQL PostgreSQL
Prerequisites
Before starting, ensure:
- Google Cloud Skills Boost lab is active
- Terraform installed
- gcloud configured
- Project ID available
Verify:
terraform version
Example:
Terraform v1.x.x
Check project:
gcloud config get-value project
Output:
qwiklabs-gcp-03-838d0a020856
Step 1: Connect to Lab Setup VM
From Cloud Shell:
gcloud compute ssh lab-setup
Verify:
whoami
Output:
student-01-xxxx
Step 2: Create Terraform Workspace
Create project folder:
mkdir cepf-iac
cd cepf-iac
Install Terraform
wget https://releases.hashicorp.com/terraform/1.12.2/terraform_1.12.2_linux_amd64.zip
Check Terraform:
terraform version
Create files:
IAC Configuration
1. Terraform Backend Configuration
Terraform state is stored remotely in Google Cloud Storage.
backend.tf
terraform {
backend "gcs" {
bucket = "qwiklabs-gcp-03-838d0a020856-bucket-tfstate"
}
}
Terraform state:
gs://qwiklabs-gcp-03-838d0a020856-bucket-tfstate/default.tfstate
2. Provider Configuration
provider.tf
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~>5.0"
}
}
}
provider "google" {
project = "qwiklabs-gcp-03-838d0a020856"
region = "us-west1"
zone = "us-west1-a"
}
3. Enable Google Cloud APIs
main.tf
resource "google_project_service" "compute" {
service="compute.googleapis.com"
}
resource "google_project_service" "sql" {
service="sqladmin.googleapis.com"
}
4. Create Custom VPC Network
network.tf
resource "google_compute_network" "vpc" {
name="cepf-vpc"
auto_create_subnetworks=false
}
resource "google_compute_subnetwork" "subnet" {
name="cepf-subnet"
region="us-west1"
network=google_compute_network.vpc.id
ip_cidr_range="10.10.0.0/24"
}
Allow HTTP Traffic
The load balancer requires HTTP access.
resource "google_compute_firewall" "allow_http" {
name="allow-http"
network=google_compute_network.vpc.name
allow {
protocol="tcp"
ports=["80"]
}
source_ranges=["0.0.0.0/0"]
}
5. Cloud SQL PostgreSQL Deployment
sql.tf
resource "google_sql_database_instance" "postgres" {
name="cepf-instance"
database_version="POSTGRES_14"
region="us-west1"
settings {
tier="db-f1-micro"
ip_configuration {
ipv4_enabled=true
}
}
}
resource "google_sql_database" "db" {
name="cepf-db"
instance=google_sql_database_instance.postgres.name
}
resource "google_sql_user" "user" {
name="postgres"
instance=google_sql_database_instance.postgres.name
password="postgres"
}
Created:
Instance:
cepf-instance
Database:
cepf-db
Username:
postgres
Password:
postgres
6. Cloud NAT Configuration
The VM instances do not have external IP addresses.
Therefore Cloud NAT provides outbound internet access for:
- package installation
- downloading Cloud SQL Proxy
- application dependencies
nat.tf
resource "google_compute_router" "router" {
name="cepf-router"
region="us-west1"
network=google_compute_network.vpc.id
}
resource "google_compute_router_nat" "nat" {
name="cepf-nat"
router=google_compute_router.router.name
region="us-west1"
nat_ip_allocate_option="AUTO_ONLY"
source_subnetwork_ip_ranges_to_nat=
"ALL_SUBNETWORKS_ALL_IP_RANGES"
}
7. Instance Template
This was the most important component.
The VM startup script performs:
- Download Flask application
- Install Python dependencies
- Install Cloud SQL Proxy
- Connect to PostgreSQL
- Start Flask application
instance_template.tf
resource "google_compute_instance_template" "template" {
name="cepf-template-v2"
machine_type="e2-medium"
disk {
source_image=
"projects/debian-cloud/global/images/family/debian-12"
auto_delete=true
boot=true
}
network_interface {
subnetwork=
google_compute_subnetwork.subnet.id
}
service_account {
email=
"603008115106-compute@developer.gserviceaccount.com"
scopes=[
"https://www.googleapis.com/auth/cloud-platform"
]
}
metadata_startup_script = <<SCRIPT
#!/bin/bash
apt-get update
apt-get install unzip python3-venv wget -y
gsutil cp gs://cloud-training/cepf/cepf020/flask_cloudsql_example_v1.zip /tmp/
cd /tmp
unzip flask_cloudsql_example_v1.zip
cd flask_cloudsql_example/sqlalchemy
curl -o cloud-sql-proxy \
https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.15.2/cloud-sql-proxy.linux.amd64
chmod +x cloud-sql-proxy
./cloud-sql-proxy \
qwiklabs-gcp-03-838d0a020856:us-west1:cepf-instance &
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt
sed -i 's/127.0.0.1/0.0.0.0/g' app.py
nohup python app.py &
SCRIPT
}
8. Managed Instance Group
mig.tf
Important fix:
For regional MIG, Terraform does not support:
region="us-west1"
inside the resource.
Correct:
resource "google_compute_region_instance_group_manager" "mig" {
name="cepf-infra-lb-group1-mig"
region="us-west1"
base_instance_name="cepf-vm"
version {
instance_template=
google_compute_instance_template.template.id
}
target_size=2
named_port {
name="http"
port=80
}
}
Autoscaling Configuration
resource "google_compute_region_autoscaler" "autoscaler" {
name="cepf-autoscaler"
region="us-west1"
target=
google_compute_region_instance_group_manager.mig.id
autoscaling_policy {
min_replicas=2
max_replicas=4
cpu_utilization {
target=0.6
}
}
}
9. Load Balancer Configuration
Health Check
The first deployment failed because Backend Service requires a health check.
Added:
resource "google_compute_health_check" "http_health_check" {
name="cepf-http-health-check"
http_health_check {
port=80
request_path="/"
}
}
Backend Service
resource "google_compute_backend_service" "backend" {
name="cepf-infra-lb-backend-default"
protocol="HTTP"
health_checks=[
google_compute_health_check.http_health_check.id
]
backend {
group=
google_compute_region_instance_group_manager.mig.instance_group
}
}
URL Map
resource "google_compute_url_map" "map" {
name="cepf-map"
default_service=
google_compute_backend_service.backend.id
}
Target HTTP Proxy
resource "google_compute_target_http_proxy" "proxy" {
name="cepf-proxy"
url_map=
google_compute_url_map.map.id
}
Forwarding Rule
resource "google_compute_global_forwarding_rule" "lb" {
name="cepf-infra-lb"
target=
google_compute_target_http_proxy.proxy.id
port_range="80"
}
Deployment Commands
Initialize:
terraform init
Validate:
terraform validate
Plan:
terraform plan
Deploy:
terraform apply
Verification
Check MIG
gcloud compute instance-groups managed list \
--regions us-west1
Expected:
cepf-infra-lb-group1-mig
SIZE 2
Check Application Health
gcloud compute backend-services get-health \
cepf-infra-lb-backend-default \
--global
Expected:
healthState: HEALTHY
Get Load Balancer IP
gcloud compute forwarding-rules list
Example:
NAME
cepf-infra-lb
IP:
8.xxx.xxx.xxx
Open:
http://LOAD_BALANCER_IP
Troubleshooting Issues Encountered
Issue 1: Backend Service Creation Failed
Error:
At least one health check needs to be specified
Solution:
Added:
google_compute_health_check
Issue 2: Terraform Invalid Expression
Problem:
group=
google_compute_instance_group_manager.mig.instance_group
Terraform requires same line:
Correct:
group = google_compute_instance_group_manager.mig.instance_group
Issue 3: Cloud SQL Proxy Permission
Error:
metadata service account token not defined
Solution:
Attach service account:
roles/cloudsql.client
and use:
service_account {}
Issue 4: MIG Update Failure
Error:
maxSurge fixed has to equal number of zones
Solution:
Regional MIG uses multiple zones.
Changed update policy:
max_surge_fixed = 0
Final Result
We successfully deployed:
- Fully automated Google Cloud infrastructure
- Terraform managed state
- Regional Managed Instance Group
- Autoscaling
- External HTTP Load Balancer
- Flask application
- Cloud SQL PostgreSQL backend
- Cloud SQL Proxy connectivity
- High availability architecture
This project demonstrates how Terraform can automate a complete cloud-native application platform using Google Cloud services.
Leave a Reply