Mastering Google Cloud Automation: Terraform Challenge Lab Tutorial

Mastering Google Cloud Automation: Terraform Challenge Lab Tutorial

Welcome to Tools to Learning, your go-to resource for hands-on cloud mastery! In this tutorial, we’ll dive into the world of automating infrastructure on Google Cloud using Terraform, all while conquering a practical Challenge Lab. If you’re eager to elevate your automation skills in the context of Google Cloud, you’re in the right place.

What is Terraform and Why Use it on Google Cloud?

Terraform is an infrastructure as code (IaC) tool that allows you to declaratively define and provision infrastructure resources. Paired with the powerful Google Cloud, it offers a seamless way to scale and manage your infrastructure efficiently and consistently.

Lab Challenge: Automating Infrastructure on Google Cloud

Embark on a journey of tasks designed to showcase Terraform’s prowess in orchestrating cloud resources. By following the outlined steps, you’ll apply practical knowledge and confront real-world scenarios.

Ready for the challenge? Access the Automating Infrastructure on Google Cloud with Terraform Challenge Lab now.

Step-by-Step Guide:

To kickstart our Terraform project, let’s begin by creating essential files and directories. Open your terminal and execute the following commands:

touch main.tf
touch variables.tf
mkdir modules
cd modules
mkdir instances
cd instances
touch instances.tf
touch outputs.tf
touch variables.tf
cd ..
mkdir storage
cd storage
touch storage.tf
touch outputs.tf
touch variables.tf
cd ..
  1. touch main.tf: This command creates a file named main.tf, typically used to define the main configuration in Terraform, including resources and provider settings.
  2. touch variables.tf: Creates a file named variables.tf, which is used to define variables that can be utilized across different parts of your Terraform code.
  3. mkdir modules: Creates a directory named modules to organize and store reusable Terraform modules.
  4. cd modules: Changes the current directory to the newly created modules directory.
  5. mkdir instances: Inside the modules directory, creates a subdirectory named instances to store a module specifically related to instances.
  6. cd instances: Changes the current directory to the instances directory.
  7. touch instances.tf: Creates a file named instances.tf to define the specific configuration for this module, which may include resources related to instances.
  8. touch outputs.tf: Creates a file named outputs.tf to define the outputs of the module, which can be important information or results used in other modules or parts of the code.
  9. touch variables.tf: Creates a file named variables.tf in this subdirectory to define variables specific to the instances module.
  10. cd ..: Moves up one level in the directory to the modules directory.
  11. mkdir storage: Creates a subdirectory named storage within the modules directory to store another module related to storage.
  12. cd storage: Changes the current directory to the storage directory.
  13. touch storage.tf: Creates a file named storage.tf to define the specific configuration for the storage module.
  14. touch outputs.tf: Creates a file named outputs.tf to define the outputs of the storage module.
  15. touch variables.tf: Creates a file named variables.tf to define variables specific to the storage module.

Navigate to variable.tf (located alongside main.tf) and paste the following content – in the code, edit with your region, zone, and project ID

variable "region" {
default = "****us-central1*****"
}
variable "zone" {
default = "*****us-central1-a*****"
}
variable "project_id" {
default = "****REPLACE PROJECT ID*****"
}

These variables provide a flexible way to parameterize your Terraform configuration, allowing you to reuse the same configuration for different regions, zones, or projects by adjusting the variable values.Add the following to main.tf:

terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "4.53.0"
}
}
}
provider "google" {
project = var.project_id
region = var.region
zone = var.zone
}
module "instances" {
source = "./modules/instances"
}
  1. Terraform Block:

    • The terraform block specifies the required provider for Google Cloud.
    • required_providers indicates that Terraform should use the Google Cloud provider.
    • The specified version of the provider is “4.53.0,” sourced from HashiCorp.
  2. Google Cloud Provider Block:

    • The provider "google" block configures the Google Cloud provider.
    • It uses the values from the provided variables (var.project_id, var.region, and var.zone) to set the project, region, and zone, respectively.
  3. Module Block:

    • The module "instances" block declares a Terraform module named “instances.”
    • The source attribute indicates the local path to the module, which is “./modules/instances.”

In this Terraform configuration, we’ve set up the essential components for deploying infrastructure on Google Cloud. The required provider from HashiCorp ensures compatibility with Google Cloud, utilizing version “4.53.0.” The Google Cloud provider block specifies key details such as the project, region, and zone, allowing for seamless integration with your Google Cloud environment. Additionally, the modular approach is embraced with the inclusion of the “instances” module, which is sourced locally from “./modules/instances.” This modular structure enhances maintainability and scalability of your infrastructure deployment.Execute in Cloud Shell:

terraform init

Running the terraform init command is the crucial first step in your Terraform journey. This command initializes your Terraform working directory, setting up the necessary components for your infrastructure deployment. During initialization, Terraform downloads the required provider plugins and ensures your configuration is ready for execution.

This command is essential for kickstarting your Terraform project, ensuring a smooth setup process before you proceed to plan and apply your infrastructure changes. Whether you’re a seasoned cloud architect or an aspiring developer, terraform init is your gateway to orchestrating infrastructure with precision.

Make this command your initial move in the cloud orchestration dance – execute it confidently in your Cloud Shell to pave the way for seamless infrastructure provisioning.

Navigate to modules/instances/instances.tf and paste the following code, don’t forget to modify your zone in the indicated items :

resource "google_compute_instance" "tf-instance-1" {
  name         = "tf-instance-1"
  machine_type = "n1-standard-1"
  zone         = "<****Add_Zone****>"
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-10"
    }
  }
  network_interface {
 network = "default"
  }
  metadata_startup_script = <<-EOT
        #!/bin/bash
    EOT
  allow_stopping_for_update = true
}
resource "google_compute_instance" "tf-instance-2" {
  name         = "tf-instance-2"
  machine_type = "n1-standard-1"
  zone         =  "<****Add_Zone****>"
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-10"
    }
  }
  network_interface {
 network = "default"
  }
  metadata_startup_script = <<-EOT
        #!/bin/bash
    EOT
  allow_stopping_for_update = true
}

This Terraform code defines two Google Compute Engine instances, tf-instance-1 and tf-instance-2. Let’s break down the key components:

  1. Instance Configuration:

    • name: Specifies the name of the instances as “tf-instance-1” and “tf-instance-2.”
    • machine_type: Sets the machine type to “n1-standard-1,” indicating a standard machine type with one virtual CPU and 3.75 GB of memory.
    • zone: Replace <****Add_Zone****> with the desired Google Cloud zone where the instances should be created.
  2. Boot Disk Configuration:

    • Configures a boot disk with the Debian 10 image from the “debian-cloud” project.
  3. Network Interface Configuration:

    • Connects the instances to the default network.
  4. Startup Script:

    • Provides a simple startup script in Bash as a placeholder.
  5. Allow Stopping for Update:

    • Enables the instances to be stopped during updates.

Ensure you replace <****Add_Zone****> with your preferred Google Cloud zone before deploying. This code sets up two basic virtual machines.

Run the following commands in Cloud Shell – to find the ID, go to the instances, click on the name, and look for the ID:

terraform import module.instances.google_compute_instance.tf-instance-1 <Instance ID - 1>
terraform import module.instances.google_compute_instance.tf-instance-2 <Instance ID - 2>
terraform plan
terraform apply

Terraform Import Commands:

  • The terraform import commands are used to associate existing resources in your cloud environment with Terraform configurations. In this case, it’s linking instances (tf-instance-1 and tf-instance-2) defined in your Terraform module with their corresponding instance IDs.

Terraform Plan:

  • The terraform plan command is used to generate an execution plan that describes what actions Terraform will take to achieve the desired state specified in your configuration files.

Terraform Apply:

  • The terraform apply command is used to apply the changes proposed in the execution plan. This step will modify or create resources as needed to match the desired configuration.

These commands play a crucial role in the Terraform workflow, allowing you to bring existing resources under Terraform management and apply changes to your infrastructure in a controlled manner. Always exercise caution and review the plan before applying changes, especially in a production environment.

Insert the following in the storage.tf file – refer to the bucket name in the lab instructions:

resource "google_storage_bucket" "storage-bucket" {
  name          = "<****YOUR-BUCKET****>"
  location      = "US"
  force_destroy = true
  uniform_bucket_level_access = true
}

This Terraform code defines a resource block for creating a Google Cloud Storage bucket. Let’s break down the key components:

  1. Resource Block:

    • google_storage_bucket is the resource type that represents a Google Cloud Storage bucket.
    • "storage-bucket" is the name given to this particular instance of the resource. You’ll reference this name elsewhere in your Terraform configuration.
  2. Attributes:

    • name: Specifies the name of the bucket. Replace <****YOUR-BUCKET****> with your bucket name. This should be unique within Google Cloud Storage.
    • location: Sets the location of the bucket. In this case, it’s set to “US,” indicating the United States. Adjust this based on your preferred region.
    • force_destroy: When set to true, this allows Terraform to delete the bucket even if it contains objects. Exercise caution with this option as it irreversibly deletes data.
    • uniform_bucket_level_access: Enables uniform bucket-level access. When set to true, it simplifies access management for objects in the bucket.

Note: Ensure you replace <****YOUR-BUCKET****> with your bucket name.

Insert into the main.tf file:

module "storage" {
  source     = "./modules/storage"
}

This Terraform code snippet is utilizing a module in your infrastructure configuration. Let’s break down the key components:

  1. Module Declaration:

    • module is a keyword used to declare the usage of a Terraform module.
    • "storage" is a local name assigned to this instance of the module. You will reference this name to interact with the module in other parts of your Terraform configuration.
  2. Module Source:

    • source specifies the location or source of the module. In this case, the module is sourced locally from the directory path “./modules/storage.” This indicates that the module is defined in a subdirectory named “storage” within the same directory as the main Terraform configuration file.

Note:

  • The “./modules/storage” path assumes that the module is structured in a way that Terraform can recognize and utilize it.
  • The module itself likely contains its own set of Terraform files, potentially including resource configurations, variables, and outputs.

Run in Cloud Shell:

terraform init
terraform apply

Modify the beginning of the main.tf file, and remember to place the bucket name in the indicated location.

terraform {
  backend "gcs" {
    bucket  = "<****REPLACE YOUR BUCKET****>"
 prefix  = "terraform/state"
  }
  required_providers {
    google = {
      source = "hashicorp/google"
      version = "4.53.0"
    }
  }
}

This Terraform configuration is setting up the backend for storing the Terraform state and specifying the required Google Cloud provider. Let’s break down the key components:

  1. Terraform Backend Configuration:

    • backend "gcs" specifies the Google Cloud Storage (GCS) backend for storing Terraform state remotely.
    • bucket is a placeholder where you should replace <****REPLACE YOUR BUCKET****> with the actual name of your Google Cloud Storage bucket.
    • prefix sets a prefix for the storage path within the bucket. In this case, it’s “terraform/state.” Adjust this prefix as needed.
  2. Required Providers:

    • The required_providers block indicates the necessary provider for this Terraform configuration.
    • google is specified as the required provider.
    • source points to the source of the Google Cloud provider, and version specifies the required version, which is “4.53.0” in this case.

Purpose:

  • Configuring a backend is crucial for Terraform to store its state information. Using Google Cloud Storage as a backend provides a centralized location to store and manage the state file securely.
  • Specifying the required Google Cloud provider ensures compatibility and sets the version to a specific release for stability.

Note:

  • Ensure you replace <****REPLACE YOUR BUCKET****> with the actual name of your Google Cloud Storage bucket before deploying.

Run in Cloud Shell:

terraform init

Insert the code below in the instance.tf file, change the type of all machines according to the lab, and add the code below. Include the provided instance name.

resource "google_compute_instance" "****Instance Name****" {
  name         = "****Instance Name****"
  machine_type = "<****MACHINE TYPE****>"
  zone         = "<****Add_Zone****>"
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-10"
    }
  }
  network_interface {
 network = "default"
  }
  metadata_startup_script = <<-EOT
        #!/bin/bash
    EOT
  allow_stopping_for_update = true
}

This Terraform code defines a Google Compute Engine instance. Let’s break down the key components:

  1. Instance Configuration:

    • google_compute_instance is the resource type for a Google Compute Engine instance.
    • "****Instance Name****" is a local name assigned to this particular instance. This is both the name of the instance and the reference name used in other parts of your Terraform configuration.
  2. Attributes:

    • name: Specifies the name of the instance. This is set as “Instance Name.” Ensure that you replace both occurrences with your desired instance name.
    • machine_type: Defines the machine type for the instance. Replace <****Machine Type****> with the desired machine type for the instance.
    • zone: Replace <****Add_Zone****> with the desired Google Cloud zone where the instance should be created.
  3. Boot Disk Configuration:

    • Configures a boot disk with the Debian 10 image from the “debian-cloud” project.
  4. Network Interface Configuration:

    • Connects the instance to the default network.
  5. Startup Script:

    • Provides a simple startup script in Bash as a placeholder.
  6. Allow Stopping for Update:

    • Enables the instance to be stopped during updates.

Note:

  • Replace "****Instance Name****" with a unique and meaningful name for your instance.
  • Update <****Machine Type****> with the desired machine type, and <****Add_Zone****> with your preferred Google Cloud zone.

Run in Cloud Shell – modify Instance_name with the instance name:

terraform init
terraform apply

terraform taint module.instances.google_compute_instance.****Instance_name****

terraform plan
terraform apply

go to instance.tf and remove instance 3

terraform apply

Go to main.tf and add the code below:

module "vpc" {
    source  = "terraform-google-modules/network/google"
    version = "~> 6.0.0"

    project_id   = "****PROJECT_ID****"
    network_name = "****VPC_NAME****"
    routing_mode = "GLOBAL"

    subnets = [
        {
            subnet_name           = "subnet-01"
            subnet_ip             = "10.10.10.0/24"
            subnet_region         = "****us-central1****"
        },
        {
            subnet_name           = "subnet-02"
            subnet_ip             = "10.10.20.0/24"
            subnet_region         = "****us-central1****"
            subnet_private_access = "true"
            subnet_flow_logs      = "true"
            description           = "This subnet has a description"
        },
    ]
}

run in cloud shell:

terraform init
terraform apply

go to Instance.tf and modify network_interface:
instance 1

  network_interface {
    network = "****VPC_NAME****"
     subnetwork = "subnet-01"
  }

instance 2

  network_interface {
    network = "****VPC_NAME*****"
     subnetwork = "subnet-02"
  }

Run in on cloud shell:

terraform init
terraform apply

go to main.tf and put the code below. make changes according to the lab

resource "google_compute_firewall" "tf-firewall"{
  name    = "tf-firewall"
 network = "projects/<*****PROJECT_ID*****>/global/networks/<****VPC_Name****>"

  allow {
    protocol = "tcp"
    ports    = ["80"]
  }

  source_tags = ["web"]
  source_ranges = ["0.0.0.0/0"]
}

Run in cloud shell:

terraform init
terraform apply