This guide provides a step-by-step approach to deploying a Docker Compose application on a virtual machine (VM) using Terraform, with a focus on leveraging snapshots for efficient deployment and recovery. It automates the setup process, including provisioning a VM, configuring Docker Compose, and restoring from a pre-existing snapshot to save time and effort. While the deployment process is the primary focus, the guide uses Decidim—a digital platform for participatory democracy—as an example application. Decidim enables organizations to create democratic processes like participatory budgeting and public consultations, but its role here is illustrative rather than central. The guide emphasizes infrastructure automation and efficient deployment techniques using VM snapshots, Terraform, and Docker Compose.
Automation is a cornerstone of modern DevOps practices, enabling faster, more reliable deployments while minimizing human error. By using Terraform for Infrastructure as Code (IaC), you can define and provision your infrastructure in a repeatable and consistent way. Docker containerization ensures that your application runs seamlessly across different environments, eliminating compatibility issues. Leveraging snapshots allows you to quickly restore or scale your setup without needing to redo installations or configurations, saving time and effort. Together, these tools—Terraform, Docker Compose, and snapshots—demonstrate how automation empowers developers to focus on building and improving applications rather than managing infrastructure manually.
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 4.0"
}
}
}
# Variables
variable "snapshot_name" {
description = "Name of the snapshot to restore from. Leave empty for fresh install."
type = string
default = ""
}
variable "project_id" {
description = "GCP Project ID"
type = string
default = "your-gcp-project-name"
}
# Provider
provider "google" {
project = var.project_id
region = "us-central1"
}
# Data source for snapshot (if it exists)
data "google_compute_snapshot" "decidim_snapshot" {
count = var.snapshot_name != "" ? 1 : 0
name = var.snapshot_name
project = var.project_id
}
resource "google_compute_disk" "boot_disk" {
name = "decidim-boot-disk"
zone = "us-central1-a"
type = "pd-ssd"
size = 50
snapshot = var.snapshot_name != "" ? var.snapshot_name : null
image = var.snapshot_name == "" ? "ubuntu-os-cloud/ubuntu-2204-lts" : null
}
# VM Instance
resource "google_compute_instance" "decidim_vm" {
name = "decidim-vm"
machine_type = "e2-standard-4"
zone = "us-central1-a"
boot_disk {
source = google_compute_disk.boot_disk.self_link
}
network_interface {
network = "default"
access_config {
# This empty block assigns a public IP
}
}
metadata_startup_script = var.snapshot_name == "" ? "#!/bin/bash\\napt-get update\\napt-get install -y docker.io docker-compose\\nsystemctl start docker\\nsystemctl enable docker" : ""
tags = ["http-server", "https-server"]
}
# Firewall rules
resource "google_compute_firewall" "decidim" {
name = "decidim-firewall"
network = "default"
allow {
protocol = "tcp"
ports = ["3000", "80", "443"]
}
source_ranges = ["0.0.0.0/0"]
target_tags = ["http-server", "https-server"]
}
# Outputs
output "instance_ip" {
description = "The public IP of the VM instance"
value = google_compute_instance.decidim_vm.network_interface[0].access_config[0].nat_ip
}
terraform init
terraform plan
terraform apply
VM Type and Configuration:
The VM in this Terraform configuration is of type e2-standard-4
, which belongs to Google Cloud's general-purpose machine family. This machine type provides 4 vCPUs and 16 GB of memory, making it suitable for most standard workloads, including running Docker Compose applications in production. It strikes a balance between performance and cost, making it ideal for medium-scale deployments.
Boot Disk Configuration:
The configuration allows the VM to boot either from:
ubuntu-2204-lts
image from Google Cloud's public repository as the base operating system.This dual-option setup is controlled by the snapshot_name
variable. If it's empty, the default disk image is used; otherwise, the snapshot is applied to create the boot disk.
Networking Configuration:
The VM's networking is configured with: