Creating a Debian VM with Startup Script and Metadata in GCP using Terraform
Introduction
This tutorial guides you through creating a Debian Linux virtual machine in Google Cloud Platform (GCP) using Terraform. You’ll learn how to:
- Define infrastructure as code with Terraform.
- Create a Debian VM instance.
- Add a startup script to configure the VM on boot.
- Set custom metadata for the instance.
- Use a dedicated service account for the VM.
- Utilize Free Tier resources where applicable.
Prerequisites:
- A Google Cloud Platform (GCP) account with billing enabled.
- The Google Cloud SDK (gcloud) installed and configured.
- Terraform installed.
- Basic understanding of Terraform syntax and concepts.
Task 1: Project Setup and Authentication
First, set up your GCP project and authenticate Terraform.
-
Set the Project ID: Replace
your-project-idwith your actual GCP project ID.NODE_TYPE // bashgcloud config set project your-project-id -
Authenticate with GCP: This command will open a browser window to authenticate.
NODE_TYPE // bashgcloud auth application-default login -
Create a Terraform Project Directory: Create a directory for your Terraform configuration files.
NODE_TYPE // bashmkdir gcp-debian-vm && cd gcp-debian-vm
Task 2: Terraform Configuration Files
Create the following Terraform configuration files.
-
main.tf: This file defines the core resources: the Google Compute Engine instance and associated configurations.NODE_TYPE // terraformterraform { required_providers { google = { source = "hashicorp/google" version = "~> 5.0" } } } provider "google" { project = "your-project-id" # Replace with your Project ID region = "us-central1" } resource "google_compute_network" "vpc_network" { name = "terraform-network" auto_create_subnetworks = false } resource "google_compute_subnetwork" "default" { name = "terraform-subnet" ip_cidr_range = "10.10.10.0/24" network = google_compute_network.vpc_network.id region = "us-central1" } resource "google_compute_address" "static" { name = "static-ip" address_type = "EXTERNAL" prefix_length = 20 region = "us-central1" } resource "google_compute_firewall" "firewall" { name = "terraform-firewall" network = google_compute_network.vpc_network.name allow { protocol = "tcp" ports = ["22", "80", "443"] } source_ranges = ["0.0.0.0/0"] } resource "google_service_account" "default" { account_id = "debian-vm-sa" display_name = "Debian VM Service Account" } resource "google_project_iam_member" "default" { project = "your-project-id" # Replace with your Project ID role = "roles/logging.logWriter" member = "serviceAccount:${google_service_account.default.email}" } resource "google_project_iam_member" "default_storage" { project = "your-project-id" # Replace with your Project ID role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.default.email}" } resource "google_compute_instance" "default" { name = "debian-vm" machine_type = "e2-micro" # Use a Free Tier machine type zone = "us-central1-a" boot_disk { initialize_params { image = "debian-cloud/debian-11" # Debian 11 } } network_interface { subnetwork = google_compute_subnetwork.default.id access_config { network_tier = "PREMIUM" nat_ip = google_compute_address.static.address } } metadata = { "startup-script" = file("startup.sh") } service_account { email = google_service_account.default.email scopes = ["cloud-platform"] } depends_on = [ google_project_iam_member.default, google_project_iam_member.default_storage ] } -
startup.sh: This script will execute when the VM instance starts. For this example, it will update the package list, installnginx, and start the service.NODE_TYPE // bash#!/bin/bash apt-get update apt-get install -y nginx systemctl start nginx -
variables.tf(Optional): This file can hold variable definitions to make your configuration more reusable.NODE_TYPE // terraformvariable "project_id" { type = string description = "The GCP project ID" } variable "region" { type = string default = "us-central1" description = "The GCP region to deploy resources in" } variable "zone" { type = string default = "us-central1-a" description = "The GCP zone to deploy the VM in" }If you create this file, update
main.tfto use the variables:NODE_TYPE // terraformprovider "google" { project = var.project_id region = var.region } resource "google_compute_instance" "default" { name = "debian-vm" machine_type = "e2-micro" zone = var.zone # ... } -
terraform.tfvars(Optional): If you createdvariables.tf, you can define the values of your variables here. Important: Do not commit this file to version control if it contains sensitive information!NODE_TYPE // terraformproject_id = "your-project-id" # Replace with your Project ID
Task 3: Initialize, Plan, and Apply
Now, use Terraform to create the infrastructure.
-
Initialize Terraform:
NODE_TYPE // bashterraform initThis command downloads the necessary provider plugins (in this case, the Google Cloud provider).
NODE_TYPE // outputInitializing the backend... Initializing provider plugins... - Finding hashicorp/google versions matching "~> 5.0"... - Installing hashicorp/google v5.X.Y... - Installed hashicorp/google v5.X.Y (signed by HashiCorp) Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command after saving the changes. -
Create an Empty
startup.shFileNODE_TYPE // bashtouch startup.shThis is necessary because Terraform will read and inject the contents of this file into the metadata of the compute resource.
-
Plan:
NODE_TYPE // bashterraform planThis command shows you the changes Terraform will make to your infrastructure. Review the plan carefully. If you are not using variables, you’ll need to replace
your-project-iddirectly inmain.tfbefore runningterraform plan.NODE_TYPE // outputTerraform will perform the following actions: # google_compute_instance.default will be created + resource "google_compute_instance" "default" { # ... (Output showing planned changes) } Plan: 1 to add, 0 to change, 0 to destroy. -
Apply:
NODE_TYPE // bashterraform applyThis command applies the changes defined in your Terraform configuration. Type
yeswhen prompted to confirm.NODE_TYPE // outputApply complete! Resources: 1 added, 0 changed, 0 destroyed. Outputs: instance_ip = "34.X.X.X"
Task 4: Verify the Deployment
-
Get the External IP: After the
terraform applycommand completes, it will output the external IP address of the VM. You can also find it in the Google Cloud Console. -
Access the VM via SSH:
NODE_TYPE // bashgcloud compute ssh debian-vm --zone us-central1-a -
Check Nginx: Once connected via SSH, verify that Nginx is running:
NODE_TYPE // bashsudo systemctl status nginxYou should see output indicating that the Nginx service is active.
-
Test the VM in a Browser: Open a web browser and navigate to the external IP address of your VM. You should see the default Nginx welcome page.
Task 5: Cleanup
When you’re finished, destroy the resources to avoid incurring unnecessary charges.
terraform destroyType yes when prompted to confirm.
Conclusion
In this tutorial, you learned how to create a Debian Linux virtual machine in Google Cloud Platform (GCP) using Terraform. You configured a startup script to automate initial setup, customized instance metadata, and assigned a service account for secure access to other GCP services. This example demonstrates a foundational infrastructure setup that can be extended for more complex applications and deployments.