This project demonstrates Infrastructure as Code (IaC) using Terraform and Packer to automate the deployment of Google Compute Engine (GCE) instances with pre-configured Apache2 web servers. The solution combines image building automation with infrastructure deployment in a complete CI/CD pipeline.
- π Automated Image Building - Packer creates custom GCE images with Apache2 pre-installed
- ποΈ Infrastructure as Code - Terraform manages VM instances, networking, and firewall rules
- π CI/CD Integration - GitHub Actions automates the entire build and deployment process
- π¦ Immutable Infrastructure - VMs are deployed from pre-baked images for consistency
- π Security Best Practices - Service account authentication, least privilege access
- π Production Ready - Environment-specific configurations using
.tfvarsfiles
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GitHub Actions Workflow β
β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββββ β
β β Packer β ββββΊ β Custom β ββββΊ β Terraform β β
β β Build β β Image β β Apply β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β Google Cloud Platform β
β β
β ββββββββββββββββ ββββββββββββββββ β
β β VM-1 β β VM-2 β β
β β Apache2 β β Apache2 β β
β β Running β β Running β β
β ββββββββββββββββ ββββββββββββββββ β
β β β β
β βββββββββββ¬ββββββββββββ β
β β β
β ββββββββββββΌβββββββββββ β
β β Firewall Rules β β
β β HTTP/HTTPS/SSH β β
β βββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ
Google-compute-engine/
βββ .github/
β βββ workflows/
β βββ image-build-and-apply.yml # Combined Packer + Terraform workflow
β βββ terraform.yml # Terraform apply workflow
β βββ terraform-destroy.yml # Terraform destroy workflow
β
βββ packer/
β βββ template.pkr.hcl # Packer template for Apache2 image
β βββ README.md # Detailed Packer documentation
β
βββ main.tf # Main Terraform configuration
βββ variables.tf # Terraform variable definitions
βββ providers.tf # GCP provider configuration
βββ dev.tfvars # Development environment variables
βββ startup.sh # VM startup script
βββ README.md # This file
| Tool | Purpose | Version |
|---|---|---|
| Terraform | Infrastructure provisioning | 1.5.7 |
| Packer | Custom image creation | Latest |
| Google Cloud Platform | Cloud infrastructure | - |
| GitHub Actions | CI/CD automation | - |
| Apache2 | Web server | 2.4.x |
| Ubuntu | Base operating system | 22.04 LTS |
-
Google Cloud Platform Account
- Active GCP project
- Billing enabled
- Compute Engine API enabled
-
Local Tools (for manual execution)
- Terraform (v1.5.7+)
- Packer (latest)
- Google Cloud SDK
-
GCP Service Account
- Roles required:
- Compute Admin
- Service Account User
- JSON key file downloaded
- Roles required:
git clone https://github.com/gcpt0801/Google-compute-engine.git
cd Google-compute-engine# Set your GCP project ID
export GCP_PROJECT="your-gcp-project-id"
# Set credentials path
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"Edit dev.tfvars to match your requirements:
instance_count = 2 # Number of VM instances
machine_type = "n2-standard-2" # VM machine type
zone = "us-central1-a" # GCP zone
# image_name is provided by the workflow via -var flag
# Format: custom-apache-image-{github.run_id}Note: The image_name variable is required and must be a Packer-built custom image. The GitHub Actions workflow automatically generates unique image names using github.run_id (e.g., custom-apache-image-19388339951).
Using GitHub Actions workflow:
-
Configure GitHub Secrets
Go to:
Settings β Secrets and variables β ActionsAdd secret:
- Name:
GCP_SA_KEY - Value: Paste entire contents of your service account JSON key
- Name:
-
Trigger Workflow
Go to:
Actions β Build image and apply Terraform β Run workflowThe workflow will:
- β Build custom Apache2 image using Packer with unique name (custom-apache-image-{run_id})
- β Deploy VMs using Terraform with the newly built image
- β Configure firewall rules
- β Output VM IP addresses
Image Naming: Each workflow run generates a unique image name using GitHub's
run_id. For example:- Run #1:
custom-apache-image-19388339951 - Run #2:
custom-apache-image-19400123456
This ensures every deployment uses a fresh, versioned image.
-
Monitor Progress
Watch the workflow execution in the Actions tab
# Navigate to packer directory
cd packer
# Initialize Packer
packer init .
# Build the image
packer build \
-var "project_id=${GCP_PROJECT}" \
-var "image_name=custom-apache-image-$(date +%s)" \
template.pkr.hcl
# Note the output image name# Return to root directory
cd ..
# Initialize Terraform
terraform init
# Plan the deployment
terraform plan \
-var "image_name=custom-apache-image-XXXXX" \
-var-file="dev.tfvars"
# Apply the configuration
terraform apply \
-var "image_name=custom-apache-image-XXXXX" \
-var-file="dev.tfvars" \
-auto-approve# Get VM IP addresses
terraform output
# Test web server
curl http://<VM_IP_ADDRESS>File: packer/template.pkr.hcl
What it does:
- Creates temporary VM in GCP
- Installs Apache2 web server
- Configures Apache2 to start on boot
- Creates machine image
- Cleans up temporary resources
Variables:
project_id- GCP project ID (required)image_name- Name for the custom image (default: "custom-apache-image")
Build time: ~3-5 minutes
Main Resources:
| Resource | Description | Configuration |
|---|---|---|
google_compute_instance |
VM instances | n2-standard-2, 20GB disk |
google_compute_firewall |
HTTP/HTTPS access | Ports 80, 443 |
google_compute_firewall |
SSH access | Port 22 |
Variables:
| Variable | Type | Default | Description |
|---|---|---|---|
project_id |
string | - | GCP project ID |
region |
string | us-central1 | GCP region |
zone |
string | us-central1-a | GCP zone |
instance_count |
number | 2 | Number of VMs |
machine_type |
string | n2-standard-2 | VM size |
image_name |
string | required | Custom Packer image (auto-generated in workflow) |
Important: image_name has no default value and must be provided. The GitHub Actions workflow automatically passes this using custom-apache-image-${{ github.run_id }}.
File: .github/workflows/image-build-and-apply.yml
Trigger: Manual (workflow_dispatch)
Steps:
- Checkout code
- Authenticate to GCP
- Install Packer
- Build custom image
- Setup Terraform
- Apply infrastructure
Duration: ~8-10 minutes
Image Versioning: Each workflow execution creates a new image with a unique name based on the GitHub run ID. This provides:
- Traceability: Match deployed VMs to specific workflow runs
- Rollback capability: Keep multiple image versions for easy rollback
- Immutable infrastructure: Each deployment uses a specific versioned image
- No conflicts: Multiple builds never overwrite each other
Example image progression:
custom-apache-image-19388339951 (First build)
custom-apache-image-19400123456 (Second build - next day)
custom-apache-image-19412567890 (Third build - after updates)
File: .github/workflows/terraform.yml
Trigger: Push to main, Pull requests
Use case: Deploy using existing image
File: .github/workflows/terraform-destroy.yml
Trigger: Manual
Use case: Clean up all infrastructure
# List all instances
gcloud compute instances list
# Get instance details
gcloud compute instances describe <instance-name> --zone=us-central1-a# Get external IP
EXTERNAL_IP=$(gcloud compute instances describe <instance-name> \
--zone=us-central1-a \
--format='get(networkInterfaces[0].accessConfigs[0].natIP)')
# Test HTTP response
curl http://${EXTERNAL_IP}
# Expected: Apache2 default page HTMLgcloud compute ssh <instance-name> --zone=us-central1-a| Resource | Specification | Estimated Cost |
|---|---|---|
| 2x n2-standard-2 VMs | 2 vCPU, 8GB RAM | ~$100/month |
| 2x 20GB Standard Disks | Persistent storage | ~$4/month |
| External IP addresses | 2 static IPs | ~$14/month |
| Total | ~$118/month |
| Item | Cost |
|---|---|
| Custom image (2-3GB) | ~$0.15/month |
Note: Costs vary by region and usage. Use GCP Pricing Calculator for accurate estimates.
- β Service account with minimum required permissions
- β No hardcoded credentials in code
- β GitHub Secrets for sensitive data
- β IAM roles following least privilege principle
- β Firewall rules limiting access to specific ports
- β SSH access can be restricted by IP range
- β HTTPS ready (requires SSL certificate configuration)
- Immutable Infrastructure - VMs deployed from pre-baked images
- Version Control - All configurations in Git
- Environment Separation - Use different
.tfvarsfor prod/dev - State Management - Consider using remote state (GCS backend)
Solution: Ensure ssh_username = "packer" is in the source block of template.pkr.hcl
Solution:
- Verify image name matches Packer output
- Check image exists:
gcloud compute images list --filter="name:custom-apache"
Solution:
- Verify firewall rules:
gcloud compute firewall-rules list - Check Apache2 status:
systemctl status apache2 - Ensure external IP is correct
Solution:
- Verify
GCP_SA_KEYsecret is set correctly - Ensure service account has required permissions
- Check JSON key format is valid
# Check Terraform state
terraform show
# Validate Terraform configuration
terraform validate
# View Packer logs
PACKER_LOG=1 packer build template.pkr.hcl
# SSH and check Apache
gcloud compute ssh <instance-name> --zone=us-central1-a
sudo systemctl status apache2- Go to
Actions β Terraform Destroy - Click
Run workflow - Confirm destruction
terraform destroy -var-file="dev.tfvars" -auto-approve# List images
gcloud compute images list --filter="name:custom-apache"
# Delete specific image
gcloud compute images delete custom-apache-image-XXXXX- Packer Details: See packer/README.md for comprehensive Packer documentation
- Terraform Variables: See variables.tf for all configurable options
- GCP Documentation: Google Compute Engine
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is open source and available under the MIT License.
- gcpt0801 - Initial work
- HashiCorp for Terraform and Packer
- Google Cloud Platform documentation
- Ubuntu community
For issues and questions:
- Open an issue in GitHub
- Check existing issues for solutions
- Review documentation in
packer/README.md
Last Updated: November 15, 2025
Project Status: β Active