Gcp (Cloud)

From campisano.org
Jump to navigation Jump to search

GCP - Google Cloud Platform

There is a really interesting free tier offer at Google Cloud Platform (GCP), where we can obtain a minimal Virtual Private Server (VPS) completely free and forever (under certain limits like bandwidth consumption etc.), and the costs for developers who want to test GCP services are pretty low, so lets start with a free VPS using Terraform.

Configure a GCP account

  • Note: the free tier has strict limits, the first that you must manage is to use a free tier compatible region as place to create your resources. In this example we will use us-east1.
  • Ensure to have enabled the Compute Engine API to allow the creation of VPSs via API (Terraform will use that).
  • Create a new project inside the GCP Console to easy map the resources that we will create.
  • Create a new JSON Key for the new project in the Service Account section. This will be used by Terraform to create and manage resources e.g. the VPS creation. Follow those steps:
go to the Service Account section
create a new Service Account and click continue
select the role Owner and click complete
select the new Service Account, go to Key section and create a new JSON key
save the key in a local folder e.g. ~/.gcp/my-project-key.json
  • Choose a O.S. image to use in your VPSs. A list is available here. In this example we will use debian-cloud/debian-10.

Install and configure gcloud client

See Gcloud (Application)

Create a custom ssh keypair

  • Define a SSH Key Pair to have access to the VPS. To create a new keypair, do the following:
ssh-keygen -q -t rsa -b 2048 -N '' -f ~/.ssh/gcp-keypair
chmod 400 ~/.ssh/gcp-keypair

Install Terraform

Terraform allows to manage Infrastructure as Code, so that you can programmatically define (and versioning) your infrastructure using code and setup virtual servers and other resources in the Cloud in few minutes.

To install, follow Terraform_(Application) instructions or see the official doc.

Setup a new f1-micro machine using Terraform

Note: the source code is available at GitLab - terraform_gcp_module.

  • configure Terraform
cat > versions.tf << 'EOF'
terraform {
  required_version = ">= 0.13"

  required_providers {
    google = ">= 3.0"
  • define a google provider
cat > provider.tf << 'EOF'
provider "google" {
  region      = var.google_provider.region
  credentials = file(var.google_provider.credentials_file)
  project     = var.google_provider.project
  • create a module to optionally manage multiple machines
mkdir -p modules/google
cat > modules/google/input.tf << 'EOF'
variable "name"             { type = string }
variable "zone"             { type = string }
variable "keypair_path"     { type = string }
variable "machine_type"     { type = string }
variable "image_name"       { type = string }
variable "boot_disk_size"   { type = string }
variable "init_script_path" {
  type = string
  default = null
cat > modules/google/main.tf << 'EOF'
data "template_file" "init_script" {
  count = var.init_script_path != null ? 1 : 0

  template = file(var.init_script_path)

resource "google_compute_instance" "instance" {
  name         = var.name
  zone         = var.zone
  machine_type = var.machine_type

  boot_disk {
    initialize_params {
      image = var.image_name
      size  = var.boot_disk_size

  metadata_startup_script = var.init_script_path == null ? null : data.template_file.init_script[0].rendered

  metadata = {
    ssh-keys = "root:${file(var.keypair_path)}"

  network_interface {
    network = "default"

    access_config {
      // Include this section to give the VM an external ip address
cat > modules/google/output.tf << 'EOF'
output "static_ip" {
  value = google_compute_instance.instance.network_interface.0.access_config.0.nat_ip
  • configure the module using external variables
cat > input.tf << 'EOF'
variable "google_provider" { type = map(string) }
variable "google_module"   { type = map(any) }
cat > main.tf << 'EOF'
module "google" {
  source = "./modules/google"

  for_each = var.google_module

  name             = each.key
  zone             = each.value.zone
  keypair_path     = each.value.keypair_path
  machine_type     = each.value.machine_type
  image_name       = each.value.image_name
  boot_disk_size   = each.value.boot_disk_size
  init_script_path = lookup(each.value, "init_script_path", null)
cat > output.tf << 'EOF'
output "google_instances" {
  value = {for key, val in module.google : key => val.static_ip}
  • configure external variables
cat > vars.json << 'EOF'
    "google_provider": {
        "region": "us-east1",
        "project": "my-project-id",
        "credentials_file": "~/.gcp/my-project-key.json"
    "google_module": {
        "my-instance-name-1": {
            "zone": "us-east1-c",
            "keypair_path": "~/.ssh/gcp-keypair.pub",
            "machine_type": "f1-micro",
            "image_name": "debian-cloud/debian-10",
            "boot_disk_size": "10",
            "init_script_path": "init_script.sh"
  • (optionally) configure init_script.sh

The script can be used to customize the O.S. image. You may use it as example or skip it.

cat > init_script.sh << 'EOF'

export DEBIAN_FRONTEND=noninteractive

apt-get -y update
apt-get -y dist-upgrade
apt-get -y clean

echo "custom init script completed" > /var/log/init_script.log
  • execute creation
terraform init
terraform apply -input=false -var-file=vars.json
  • destroy all resources
terraform destroy -input=false -var-file=vars.json
  • Optionally, use a simple Makefile to setup the previous custom commands:
cat > Makefile << 'EOF'
export TF_PLUGIN_CACHE_DIR := ${HOME}/.terraform.d/plugin-cache

.PHONY: clean
	@mkdir -p ${TF_PLUGIN_CACHE_DIR} || true
	@rm -rf .terraform

.PHONY: init
init: clean
	terraform init

.PHONY: apply
	terraform apply -input=false -var-file=vars.json

.PHONY: destroy
	terraform destroy -input=false -var-file=vars.json