Note: Some of this is a duplicate of the AWS EC2 article, modified for Google Compute Engine and a recent Terraform 0.14.x version.
Google Compute Engine is the compute service in Google Cloud. It is flexible, adaptable, scalable and is able to run Virtual Machine workloads to fit most every need.
In this article we will use Terraform (Infrastructure as Code) to swiftly bring up a Google Compute Engine instance in us-east-4 on a static IP, in a new VPC, add a DNS Zone for the site in mention and install docker/docker-compose on it.
We will use ‘myweb’ as an example in this article, using the same base path of ‘dev’ that was previously created and using ~/.local/bin for certain binaries and system for others.
Please use ‘Google Cloud Free Tier‘ prior to commencing with this article if you do not already have an account.
Note: The Compute Engine instance used here is one step above F1-Micro (which is free-tier). The reason for not going with the F1-Micro instance, is it doesn’t provide enough resources for the boot up work to complete in a near timely manner.
–>
Go in to the dev directory/link located within your home directory:
$ cd ~/dev
Grab/Update to the latest version of Terraform:
$ wget https://releases.hashicorp.com/terraform/0.14.7/terraform_0.14.7_linux_amd64.zip
Install Unzip if you do not have it installed:
$ sudo apt update && sudo apt -y install unzip
Unzip it to ~/.local/bin and set permissions accordingly on it (type y and hit enter to replace if upgrading, at the prompt):
$ unzip terraform_0.14.7_linux_amd64.zip -d ~/.local/bin && chmod 754 ~/.local/bin/terraform
Install GCLOUD SDK/CLI:
Note: The below instructions will use an Ubuntu distribution and have assumed you have prepared a development environment with pre-requisite packages (apt-transport-https, ca-certificates and gnupg2/gnupg) from the preceding article(s)):
$ echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list $ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - $ sudo apt-get update && sudo apt-get -install -y google-cloud-sdk
Initialize/Authenticate/Authorize via GCLOUD CLI:
$ gcloud auth login
You must log in to continue. Would you like to log in (Y/n)? Y
Go to the following link in your browser: https://…..
In browser: Choose an account to continue to Google Cloud SDK
Im browser: Google Cloud SDK wants to access your Google Account -> Allow
Please copy this code, switch to your application and paste it there:
<COPY and PASTE back in to the terminal window>
Enter verification code: <CODE> and hit Enter.
Create a Terraform work folder, a folder for the script(s), a service account folder and change in to the base path:
$ mkdir -p terraform/gcp/myweb/scripts && cd terraform/gcp/myweb && mkdir service-account
Generate an SSH Key Pair (no password) and restrict permissions on it if you don’t already have one:
$ ssh-keygen -q -t rsa -b 2048 -N '' -f ~/.ssh/myweb && chmod 400 ~/.ssh/myweb
Pin the Terraform version to greater then or equal to 0.14:
$ cat << 'EOF' > versions.tf > terraform { > required_version = ">= 0.14" > } > EOF
Set the default region as a variable, set prefix of myweb and create an empty ‘project’ variable:
$ cat << 'EOF' > vars.tf > variable "region" { > default = "us-east4" > } > > variable "prefix" { > default = "myweb" > } > > variable "project" { > default = "" > } > EOF
Configure the google provider and use a service account:
$ cat << 'EOF' > provider.tf > provider "google" { > credentials = file("~/dev/terraform/gcp/myweb/service-account/${var.project}.json") > project = var.project > region = var.region > zone = "${var.region}-a" > } > EOF
The following is performed with this script/code:
- create a DNS Zone of myweb.com (no A records will be added)
- create a Virtual Private Cloud
- add a subnet of 10.0.1.0/24 within the VPC
- allocate a static Public IP
- create a Firewall and add a rule for allowing SSH (port 22) Inbound
- create a G1-Small instance based off of Ubuntu 20.04, our public key added as authorized and reference an extraneous file for user_data (initialization script on Virtual Machine boot).
- tag resources as applicable
$ cat << 'EOF' > compute_engine.tf > # Create a DNS Zone > resource "google_dns_managed_zone" "myweb_zone" { > name = "${var.prefix}-zone" > dns_name = "${var.prefix}.com." > description = "${var.prefix}.com" > labels = { > site = "${var.prefix}-com" > } > } > > # Allocate a Static Public IP > resource "google_compute_address" "myweb_static" { > name = "${var.prefix}-ipv4" > } > > # Create an Ubuntu Virtual Machine with key based access and run a script on boot > resource "google_compute_instance" "myweb_vm" { > name = "${var.prefix}-vm" > machine_type = "g1-small" > boot_disk { > initialize_params { > image = "ubuntu-os-cloud/ubuntu-2004-lts" > } > } > > metadata = { > ssh-keys = "ubuntu:${file("~/.ssh/myweb.pub")}" > } > > metadata_startup_script = file("~/dev/terraform/gcp/myweb/scripts/install.sh") > > network_interface { > network = google_compute_network.myweb_vpc.self_link > subnetwork = google_compute_subnetwork.myweb_subn.self_link > access_config { > nat_ip = google_compute_address.myweb_static.address > } > } > > labels = { > site = "${var.prefix}-com" > } > } > > # Create a Firewall and allow inbound port(s) > resource "google_compute_firewall" "myweb_vpc" { > name = "${var.prefix}-fw" > network = google_compute_network.myweb_vpc.name > allow { > protocol = "tcp" > ports = ["22"] > } > } > > # Add a Subnet > resource "google_compute_subnetwork" "myweb_subn" { > name = "${var.prefix}-subn" > ip_cidr_range = "10.0.1.0/24" > region = var.region > network = google_compute_network.myweb_vpc.id > } > > # Create a Virtual Private Cloud > resource "google_compute_network" "myweb_vpc" { > name = "${var.prefix}-net" > auto_create_subnetworks = "false" > } > EOF
Output our allocated and attached static Public IP after creation:
$ cat << 'EOF' > output.tf > output "static_public_ip" { > value = google_compute_instance.myweb_vm.network_interface.0.access_config.0.nat_ip > } > EOF
Create the shell script for metadata_startup:
$ cat << 'EOF' > scripts/install.sh
> #!/bin/bash
>
> MY_HOME="/home/ubuntu"
> export DEBIAN_FRONTEND=noninteractive
>
> # Install prereqs
> apt update
> apt install -y python3-pip apt-transport-https ca-certificates curl software-properties-common
> # Install docker
> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
> add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
> apt update
> apt install -y docker-ce
> # Install docker-compose
> su ubuntu -c "mkdir -p $MY_HOME/.local/bin"
> su ubuntu -c "pip3 install docker-compose --upgrade --user && chmod 754 $MY_HOME/.local/bin/docker-compose"
> usermod -aG docker ubuntu
> # Add PATH
> printf "\nexport PATH=\$PATH:$MY_HOME/.local/bin\n" >> $MY_HOME/.bashrc
>
> exit 0
> EOF
Create a Google Cloud project with a random numeric number at the end of it:
$ gcloud projects create myweb-$(tr -cd "[:digit:]" < /dev/urandom | head -c 5) --name=myweb
Assign the created project name to a variable:
$ myweb=$(gcloud projects list | grep myweb | awk '{print $1}')
Create a service account to be used by Terraform:
$ gcloud iam service-accounts create container-admin --description=gcloud-cli --project=$myweb
Create a Private key for the Service Account and download it to .JSON format:
$ gcloud iam service-accounts keys create service-account/$myweb.json --iam-account=$(gcloud iam service-accounts list --project=$myweb | grep container-admin | awk '{print $1}') --key-file-type=json
List your billing accounts:
$ gcloud beta billing accounts list
Link the newly created project with the billing Account:
$ gcloud beta billing projects link $myweb --billing-account=<ACCOUNT ID>
Enable Compute and DNS Google APIs:
$ gcloud services enable compute.googleapis.com dns.googleapis.com --project=$myweb
Add all encompassing IAM roles for required operations:
$ for role in 'roles/compute.networkAdmin' 'roles/dns.admin' 'roles/container.serviceAgent'; do gcloud projects add-iam-policy-binding $myweb --member="serviceAccount:$(gcloud iam service-accounts list --project=$myweb | grep container-admin | awk '{print $1}')" --role=$role; done
Initialize the Terraform directory:
$ terraform init
Run a dry-run to see what will occur:
$ terraform plan -var 'project=$myweb'
Provision:
$ terraform apply -var 'project=$myweb' -auto-approve
Log on to the instance after a short while:
$ ssh -i ~/.ssh/myweb ubuntu@<The value of static_public_ip that was reported. One can also use 'terraform output static_public_ip' to print it again.>
Type yes and hit enter to accept.
On the host (a short while is needed for the run-once script to complete):
$ docker --version
$ docker-compose --version
$ logout
Tear down what was created by first performing a dry-run to see what will occur:
$ terraform plan -var 'project=$myweb' -destroy
Tear down the instance:
$ terraform destroy -var 'project=$myweb' -auto-approve
If you would like to remove the project –>
Unlink Billing:
$ gcloud beta billing projects unlink $myweb
Delete the project:
$ gcloud projects delete $myweb --quiet
Remove the .JSON key file from Terraform:
$ rm service-account/$myweb.json
Unset the myweb variable:
$ unset myweb
<–
References:
Source: