Created: 5/27/2022
Terraform modules can significantly simplify the IaC that lives in your projects, particularly when you have common or repetitive use cases.
Terraform is an open source Infrastructure as Code tool. Terraform has the ability to observe the current state of a system, compare it to the desired state defined in your source code, create a plan of action to migrate between states, and execute that plan of action. Terraform doesn't do much on its own, but providers create an adapter layer between Terraform and the APIs for infrastructure platforms. Hashicorp (the company behind Terraform), maintains first-class providers for AWS, Azure, Google Cloud Platform, and Kubernetes.
Terraform's documentation is extremely clear and thorough, but in no particular order, these are some things I find particularly useful about Terraform modules:
My container deployment module is used to deploy a single container into a Kubernetes cluster. It takes care of replication, service load balancing, ingress, and TLS certificate generation. Despite the module doing all that, it's extremely simple to use in a project:
module "container-deployment" {
source = "jdevries3133/container-deployment/kubernetes"
version = "0.3.0"
app_name = "danart"
container = "jdevries3133/danart:1.0.1"
domain = "danart.us"
}
The desire to throw a container into my cluster and expose it on a domain is really common. I use it for simple static sites like my mom's cute little art site, or documentation sites for my software packages.
extra_env
The module support an extra_env
argument, whose values populate a ConfigMap
and are then injected into the pod environment. So, you can extend the
configuration for apps that use a 3rd API, for example:
module "container-deployment" {
...
extra_env = {
API_SECRET = "password!"
}
}
With HCL, this type of dynamic configuration is much better supported than with YAML.
To take things a step further, my basic
deployment
module provides everything a fledgling full-stack web app needs to grow. It
does everything the pod deployment does, but it also creates a PostgreSQL
database using Bitnami's helm chart. It provides database connection
information as environment variables, and also supports an extra_env
argument
for any other credential your app might need.
The end of the road with all this modularization is very clean and simple IaC. classfast.app is my most recent full-stack project, and its IaC looks like this
# ... terraform state and provider initialization boilerplate is omitted
variable "google_client_secret" {
type = string
sensitive = true
}
data "external" "git_describe" {
program = ["sh", "-c", "echo '{\"output\": \"'\"$(git describe --tags)\"'\"}'"]
}
resource "random_password" "django_secret" {
length = 48
special = true
}
module "basic-deployment" {
source = "jdevries3133/basic-deployment/kubernetes"
version = "0.1.2"
app_name = terraform.workspace == "production" ? "fast-grader" : "fast-grader-beta"
container = "jdevries3133/fast_grader_django:${data.external.git_describe.result.output}"
domain = terraform.workspace == "production" ? "classfast.app" : "beta.classfast.app"
extra_env = {
DJANGO_SECRET = random_password.django_secret.result
DJANGO_SETTINGS_MODULE = "fast_grader.settings.production"
GOOGLE_CLIENT_ID = "850669494212-rbi5f45edqpnru9a7gs1avgb480kr92b.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET = var.google_client_secret
IS_PRODUCTION = terraform.workspace == "production" ? "true" : "false"
}
}
This IaC yields:
That's a lot of bang for your buck for only 33 lines of infrastructure code if you ask me!