Gcp (Cloud)
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
- Create a GCP free 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
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" } } 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
- https://cloud.google.com/community/tutorials/getting-started-on-gcp-with-terraform
- https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/getting_started
- https://dev.to/phocks/how-to-get-a-free-google-server-forever-1fpf
- https://cloud.google.com/products/calculator#id=03338b0b-e25d-437d-8a9e-67812be1568f