Skip to main content
  1. Posts/

Using Terraform for deploying databases and applications in Google Cloud

··818 words·4 mins
Author
Hairizuan Noorazman
Software engineering experiments, implementation notes, and lessons learned.

Over the past few months, I have been toying with the idea of going all in with Ansible or all in with Terraform. Both tools are pretty popular tools when it comes to application and tools deployment. After tinkering around, I eventually somewhat come to conclusion where Terraform would be the “better” tool here. The main reason for this all comes down to this: https://github.com/ansible-collections/google.cloud/issues/301 - it seems that Ansible is not as “supported” as Terraform - and the more it seems that there are certain features that I may want to use to be missing. Rather than continue tinkering and hoping that something would happen (sometimes, these kind of code would never be resolved/fixed - it’s possible for me to dig into it to try to solve but I don’t feel like investing into this particular tool in depth)

And here we are, me trying out Terraform in order to deploy some stuff in Google Cloud via Terraform.

Initial setup
#

One of the first things to build out would be the following setup:

  • Setup of instances within a private virtual network
    • Generally done for better security - one way to secure servers would simply to avoid outsidrs from unnecessarily accessing it
  • Setup of bastion host
    • This should be publicly accessible via ssh.
    • This host would serve as a “jump” server that would allow an outside developer to access the various instances within the private network
  • Ensure that instance within the private virtual network is able to access the internet
    • If one were to create a Google Compute Engine with no public interface, you would realize that the instance wouldn’t be able to access the internet. In order for such instances to be able access the internet, we would need to setup a NAT connected to the VPN - from then on, it should be able to access the internet.

The first thing I would want to deploy in order to ensure that the internet works properly would be to install docker on the instance within the virtual private network. I generally use docker in various experiments so it would usually be the first things I think of to need to deploy contantly.

The code for this is here:
https://github.com/hairizuanbinnoorazman/terraform/tree/main/google

The portion to deploy the bastion host would be here:
https://github.com/hairizuanbinnoorazman/terraform/tree/main/google/bastion

We don’t need to run any further commands on bastion host as of now (maybe in the future, I will research into what tooling to install on bastion host in order to harden it against attackers). As of now, I didn’t look too deep into bastion host tooling since I would generally bootstrap and tear down the entire stack within the day.

The next critical piece of thing to cover would be the step on how to install on docker on the server. We would a way for us to inject it via terraform. One approach, especially in the case where we use Google Cloud instances would be to rely on the metadata_startup_script - there is service within each instance that would immediately run upon instance startup - which we would want in this case.

resource "google_compute_instance" "server" {
  count = var.service_meta[var.component].server_count
  zone  = var.gcp_zone

  ...

  metadata_startup_script =  data.local_file.script.content
  
  ...
}

We can simply read of the script from another file rather than putting it all within terraform scripts itself. For the case of docker, it is in the following file: https://github.com/hairizuanbinnoorazman/terraform/blob/main/google/server/scripts/docker. The file would be read via terraform’s local module which would then have that content be piped into the google_compute_instance module when starting our private server.

With that all in place, we can simply run the commands from the google folder of the git repo:

# If not yet initialized:
terraform init

# Convenience function for creating a docker with bastion host
components='["docker"]' add_bastion=true  make plan

Accidentally added a bunch of complex features where a make command would be needed. The make command essentially is wrapper around terraform plan; flags such as where the output of the plan would be is already decleared within the makefile. Other variables that need to be declared would also be things like which gcp project we would like to aim this deployment at.

gcp_id=$(shell gcloud config get project)
components?=[]
add_bastion?=false

plan:
	TF_VAR_gcp_project_id=$(gcp_id) terraform plan -out=initial.plan -var 'components=$(components)' -var 'enable_bastion=$(add_bastion)'

destroy:
	TF_VAR_gcp_project_id=$(gcp_id) terraform plan -out=destroy.plan -destroy

Once the plan is created, we can simply run the command:

terraform apply initial.plan

What’s available
#

If you see the codebase as of now, it has already been configured to be able to deploy a variety of common tools and services such as nginx, etcd, mariadb. The full list of what’s probably capable will be continually updated on the main Readme.md page of the git repo.

Eventually, I would cover other cases as well, such as deploying custom golang applications or ruby applications or even python applicaitons into the various environments - everything controlled or handled via terraform. Look forward to that.

Related

Building RPMs and storing it in Artifact Registry

··1659 words·8 mins
Introduction # When one mentions about application packaging - the usual first thought that can cross a person’s mind is how the application would be packaged in docker containers. That is a somewhat fair thing to think about - containers have gotten pretty common in developer circles. Tools such as docker or podman make it especially simple to write a simple straight forward file that would include their application file into a nice package. With this nice package - the people that are involved with running it production environments would only deal with a single artifact.

Github actions for shopping list application

··1485 words·7 mins
I have a basic shopping list application that is available in the following code base: https://github.com/hairizuanbinnoorazman/Go_Programming/tree/master/Apps/shopping-list. This is a simple Golang application that also embeds a generated javascripts that has been transpiled into Javascript files. We can then embed the required CSS, Javascript and HTML files that would be the frontend of the shopping list. The frontend would then call some backend apis that would simply store shopping list items into some form of datastore - which in this case, is Google Cloud Datastore (a NoSQL database)

GKE as Gitlab Runner

Part of my job involves me dealing with Gitlab on a daily basis. Gitlab is a complicated beast to handle and it took a while to get around the various features that the product offers. One of the offerings available is one where we can set an entire Kubernetes cluster as a potential target where we can then create containers and run tests on said cluster.