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 Github - terraform_google_module.

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

  required_providers {
    google = ">= 3.0"
  }
}
EOF
  • 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
}
EOF
  • 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
}
EOF
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
    }
  }
}
EOF
cat > modules/google/output.tf << 'EOF'
output "static_ip" {
  value = google_compute_instance.instance.network_interface.0.access_config.0.nat_ip
}
EOF
  • configure the module using external variables
cat > input.tf << 'EOF'
variable "google_provider" { type = map(string) }
variable "google_module"   { type = map(any) }
EOF
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)
}
EOF
cat > output.tf << 'EOF'
output "google_instances" {
  value = {for key, val in module.google : key => val.static_ip}
}
EOF
  • 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"
        }
    }
}
EOF
  • (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'
#!/bin/bash

export DEBIAN_FRONTEND=noninteractive

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

echo "custom init script completed" > /var/log/init_script.log
EOF
  • 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
clean:
	@mkdir -p ${TF_PLUGIN_CACHE_DIR} || true
	@rm -rf .terraform

.PHONY: init
init: clean
	terraform init

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

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

References