NashTech Blog

Creating a Virtual Machine on Google Cloud with Terraform: A Comprehensive Guide

Table of Contents

In the last blog, we covered how to create and manage virtual machines (VMs) using the Google Cloud Console and the gcloud CLI. In this blog, we will take things to the next level by using Terraform to create a VM with advanced configurations. Terraform is a powerful tool for infrastructure automation, and in this tutorial, we’ll go through how to set up a VM with:

  • A specific service account for secure operations,
  • Serial port access for debugging,
  • SSH key injection for secure access,
  • A static external IP to make sure your VM has a fixed IP,
  • A firewall rule for opening SSH access,
  • Startup scripts for automated VM initialization.

Prerequisites:

Before starting, ensure you have:

  1. Terraform installed.
  2. Access to a Google Cloud account with the necessary permissions (Compute Admin, Service Account User).
  3. A service account JSON file for authentication.
  4. A public SSH key for secure login to your VM.

Step 1: Initialize Your Terraform Project

In your Terraform configuration directory, you should have the following files:

  1. main.tf: Defines the resources (VM, firewall, etc.).
  2. variables.tf: Declares all variables.
  3. provider.tf: Specifies the Google Cloud provider configuration.
  4. terraform.tfvars: Sets values for the variables defined in variables.tf.
  5. startup.sh: Custom script that runs when the VM starts.
  6. output.tf: Outputs to show essential details such as IP addresses and SSH connection commands.

Step 2: Writing the Terraform Configuration

Here’s a breakdown of the core Terraform configuration that you can use to create your VM with all the features mentioned above.

main.tf

resource "google_compute_address" "static_ip" {
  name   = "my-static-ip"
  region = var.region
}

resource "google_compute_instance" "vm_instance" {
  name         = "my-vm"
  machine_type = "e2-micro"
  zone         = var.zone

  tags = ["allow-ssh"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  network_interface {
    network = "default"
    access_config {
      nat_ip = google_compute_address.static_ip.address
    }
  }

  metadata = {
    serial-port-enable = "1"
    ssh-keys           = "${var.ssh_user}:${file(var.ssh_public_key_path)}"
    startup-script     = file("startup.sh")
  }

  service_account {
    email  = var.service_account_email
    scopes = ["https://www.googleapis.com/auth/cloud-platform"]
  }
}

resource "google_compute_firewall" "ssh" {
  name    = "allow-ssh"
  network = "default"

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

  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["allow-ssh"]
}

Explanation:

  1. Static IP: The google_compute_address resource creates a static external IP to be assigned to the VM.
  2. VM Creation: The google_compute_instance resource defines the VM, including boot disk settings, network interfaces, metadata (for serial port access and SSH key injection), and startup script.
  3. Service Account: The VM uses a service account with the required permissions to interact with Google Cloud.
  4. Firewall Rule: The google_compute_firewall resource opens port 22 for SSH access from anywhere (0.0.0.0/0).

variables.tf

variable "project_id" {
  type        = string
  description = "The GCP project ID"
  default     = "celestial-tract-413511"
}

variable "region" {
  type    = string
  default = "us-central1"
}

variable "zone" {
  type    = string
  default = "us-central1-c"
}

variable "credentials_file" {
  type        = string
  description = "Path to service account key file"
  default     = "/home/nashtech/Downloads/celestial-tract-413511-becfe2019156.json"
}

variable "service_account_email" {
  type        = string
  description = "Service account to attach to the VM"
  default     = "test-657@celestial-tract-413511.iam.gserviceaccount.com"
}

variable "ssh_user" {
  type    = string
  default = "nashtech"
}

variable "ssh_public_key_path" {
  type    = string
  default = "~/.ssh/google_compute_engine.pub"
}

terraform.tfvars

project_id            = "celestial-tract-413511"
region                = "us-central1"
zone                  = "us-central1-c"
ssh_user              = "nashtech"
ssh_public_key_path   = "~/.ssh/google_compute_engine.pub"
service_account_email = "test-657@celestial-tract-413511.iam.gserviceaccount.com"

provider.tf

provider "google" {
  credentials = file(var.credentials_file)
  project     = var.project_id
  region      = var.region
  zone        = var.zone
}

startup.sh

#!/bin/bash
echo "Hello from startup script" > /var/log/startup-script.log
sudo apt update && sudo apt install -y nginx

output.tf

output "vm_external_ip" {
  description = "The external IP address of the VM"
  value       = google_compute_instance.vm_instance.network_interface[0].access_config[0].nat_ip
}

output "ssh_connection" {
  description = "SSH connection string"
  value       = "ssh ${var.ssh_user}@${google_compute_instance.vm_instance.network_interface[0].access_config[0].nat_ip}"
}

Terraform.tf

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 4.0"
    }
  }

  required_version = ">= 1.3"
}

Step 3: Running Terraform

Once you have all the configurations set, follow these steps:

  • Initialize Terraform:
    Run terraform init to initialize the working directory and download the required provider plugins.
  • Plan the Infrastructure:
    Run terraform plan to see the resources Terraform will create, modify, or destroy.
  • Apply the Configuration:
    Run terraform apply to provision the resources defined in your Terraform files. Terraform will prompt you to confirm before creating the resources.
  • Verify the Outputs:
    After the Terraform apply is complete, verify the output values to check the external IP and the SSH connection string:
terraform output vm_external_ip
terraform output ssh_connection

Step 4: Access the VM

Once the VM is up and running, you can connect to it using SSH. The command will be displayed in the output of your terraform output command.

Example:

ssh -i <key-file> nashtech@<external-ip>

You can also use the serial port connection:

gcloud compute connect-to-serial-port my-vm –zone=us-central1-c

Step 5: Verifying Nginx Installation and Startup Script Execution

Once your VM is created and running, you can verify that:

  • The startup script executed successfully.
  • Nginx was installed by the script.

✅ Check the startup script log

Then, check the content of the log file created by the startup script:

cat /var/log/startup-script.log

If the script executed successfully, you should see:

✅ Check if Nginx is installed

You should see that the service is active (running). If not, you can start it manually:

Run:

sudo systemctl status nginx

Final Thoughts

By verifying both the script execution and Nginx setup, you ensure that your VM is not just deployed—but also correctly bootstrapped to run services right from launch. This is especially powerful for setting up real-world environments where automation is key.

Conclusion

In this blog, we’ve demonstrated how to use Terraform to create a Google Cloud VM with the following configurations:

  • Specific service account with necessary permissions.
  • Serial port enabled for debugging.
  • SSH key injection for secure access.
  • Static external IP for persistent access.
  • Firewall rule to allow SSH traffic.
  • Startup script for automated VM setup.

With these steps, you now have a fully automated and secure VM deployment pipeline using Terraform, which is ideal for production environments.

In the next blog, we’ll explore how to automate the process of scaling and managing your infrastructure with Terraform. Stay tuned!

Picture of rupali1520

rupali1520

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top