Skip to content

Commit

Permalink
GKE terraform module (#614)
Browse files Browse the repository at this point in the history
* add google's terraform module 'kubernetes-engine' to our local modules

* use zonal with minimal node pool as default for gke instance. This has the added benefit of quick provisioning, taking advantage of the GCP free tier, and keeping our configs simple

* move network topgraphy definition our of k8 module
  • Loading branch information
dpgraham4401 authored Oct 20, 2023
1 parent e48fdb2 commit 6246921
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 12 deletions.
42 changes: 42 additions & 0 deletions infra/gcp/dev/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 18 additions & 2 deletions infra/gcp/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,24 @@ for purposes of this demonstration, a pre-configured project and access is neces
4. Create a [service account for terraform](https://cloud.google.com/iam/docs/service-accounts-create)
- `gcloud iam service-accounts create <sa_name> --display-name "Terraform Service Account"`
- The account will need the following permissions
- `roles/storage.objectAdmin`
- `gcloud projects add-iam-policy-binding <project_id> -dev-test-123 --member="serviceAccount:<sa_name>@haztrak-epa-dev-test-123.iam.gserviceaccount.com" --role=roles/storage.objectAdmin --role=roles/serviceusage.serviceUsageAdmin`
```shell
gcloud projects add-iam-policy-binding <project_id> -dev-test-123 \
--member="serviceAccount:<sa_name>@<project_id>.iam.gserviceaccount.com" \
--role=roles/storage.objectAdmin \
--role=roles/serviceusage.serviceUsageAdmin \
--role=roles/iam.serviceAccountAdmin \
--role=roles/iam.serviceAccountUser \
--role=roles/resourcemanager.projectIamAdmin \
--role=roles/compute.viewer \
--role=roles/compute.securityAdmin \
--role=roles/container.clusterAdmin \
--role=roles/container.developer
```
- You can check that all the roles were successfully added to our service account with the following command:
```shell
gcloud projects get-iam-policy $PROJECT_ID --flatten="bindings[].members" --format='table(bindings.role)' --filter="bindings.members:<service_account>"
```
While this is a lot of permissions, and manually applying them is not ideal, it is necessary for terraform to be able to manage all the resources we need to get this project up and running.
5. [Create a GCP bucket](https://cloud.google.com/storage/docs/creating-buckets#storage-create-bucket-cli) to hold Terraform remote state
- `gcloud storage buckets create gc://<bucket_name> --project <project_id>`

Expand Down
8 changes: 8 additions & 0 deletions infra/gcp/dev/backend.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ provider "google" {
region = var.region
zone = var.zone
}

data "google_client_config" "default" {}

provider "kubernetes" {
host = "https://${module.k8.endpoint}"
token = data.google_client_config.default.access_token
cluster_ca_certificate = base64decode(module.k8.ca_certificate)
}
45 changes: 42 additions & 3 deletions infra/gcp/dev/main.tf
Original file line number Diff line number Diff line change
@@ -1,15 +1,54 @@
module "gcp_apis" {
source = "../modules/gcp-apis"
locals {
subnet_base_name = "${var.vpc_name}-subnet"
k8_subnet_pod_ip_range = "${local.subnet_base_name}-pods"
k8_subnet_service_ip_range = "${local.subnet_base_name}-services"
}

project = var.project
module "gcp_apis" {
source = "../modules/gcp-apis"
project = var.project
services = [
"compute.googleapis.com",
"container.googleapis.com"
]
}

module "vpc" {
source = "../modules/network"
vpc_name = var.vpc_name
project = var.project
region = var.region
depends_on = [module.gcp_apis]
subnets = [
{
subnet_name = local.subnet_base_name
subnet_ip = "10.0.0.0/16"
subnet_region = var.region
}
]
secondary_ranges = {
(local.subnet_base_name) = [
{
range_name = local.k8_subnet_pod_ip_range
ip_cidr_range = "10.1.0.0/24"
},
{
range_name = local.k8_subnet_service_ip_range
ip_cidr_range = "10.2.0.0/24"
}
]
}
}

module "k8" {
source = "../modules/k8"
name = "haztrak-gke"
network = module.vpc.network
project = var.project
region = var.region
zones = [var.zone]
subnet_name = local.subnet_base_name
pod_ip_range_name = local.k8_subnet_pod_ip_range
service_ip_range_name = local.k8_subnet_service_ip_range
depends_on = [module.gcp_apis, module.vpc]
}
6 changes: 6 additions & 0 deletions infra/gcp/dev/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ variable "zone" {
type = string
description = "the default zone to use for the terraform GCP provider"
}

variable "vpc_name" {
type = string
description = "The name of the VPC to create"
default = "haztrak-vpc"
}
1 change: 0 additions & 1 deletion infra/gcp/modules/gcp-apis/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ variable "project" {
error_message = "GCP project length must be greater than zero"
condition = length(var.project) > 0
}

}
25 changes: 25 additions & 0 deletions infra/gcp/modules/k8/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
locals {
env_name = var.environment == "prod" ? var.name : "${var.name}-${var.environment}"
name = var.regional ? local.env_name : "${local.env_name}-zonal"
cluster_type = "simple-autopilot-public"
}
module "gke" {
source = "terraform-google-modules/kubernetes-engine/google"
description = var.description
project_id = var.project
name = local.name
regional = false
region = var.region
zones = var.zones
network = var.network
service_account = "create"
service_account_name = "${var.project}-tf-sa"
subnetwork = var.subnet_name
ip_range_pods = var.pod_ip_range_name
ip_range_services = var.service_ip_range_name
release_channel = "REGULAR"
enable_vertical_pod_autoscaling = false
horizontal_pod_autoscaling = false
}
7 changes: 7 additions & 0 deletions infra/gcp/modules/k8/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
output "endpoint" {
value = module.gke.endpoint
}

output "ca_certificate" {
value = module.gke.ca_certificate
}
70 changes: 70 additions & 0 deletions infra/gcp/modules/k8/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
variable "project" {
description = "The Google Cloud project ID to enable services in."
type = string
validation {
error_message = "GCP project length must be greater than zero"
condition = length(var.project) > 0
}
}

variable "name" {
description = "The name of the GKE cluster."
type = string
}

variable "environment" {
description = "The environment to deploy to"
type = string
default = "dev"
validation {
condition = contains(["dev", "prod"], var.environment)
error_message = "Environment must be one of [dev, prod]"
}
}

variable "regional" {
description = "Whether to deploy a regional cluster (multiple zones) or zonal (single zone)"
type = bool
default = false
}

variable "region" {
description = "The region to deploy to"
default = "us-east1"
type = string
validation {
condition = can(regex("^[a-z]{2,}-[a-z]*[1-9]{1}$", var.region))
error_message = "Invalid GCP region format. See 'gcloud compute regions list' for available options"
}
}

variable "zones" {
type = list(string)
description = "The zone to host the cluster in (required if is a zonal cluster)"
}

variable "description" {
type = string
description = "The description of the cluster"
default = "Haztrak GKE Cluster"
}

variable "network" {
type = string
description = "The VPC network to host the cluster in (required)"
}

variable "subnet_name" {
type = string
description = "The name of the subnet to host the cluster in (required)"
}

variable "pod_ip_range_name" {
type = string
description = "The name of the secondary IP range the pods will be assigned to."
}

variable "service_ip_range_name" {
type = string
description = "The name of the secondary IP range the services will be assigned to."
}
2 changes: 2 additions & 0 deletions infra/gcp/modules/network/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ locals {
database_subnet_name = var.environment == "prod" ? "${var.project}-database-subnet-prod" : "${var.project}-database-subnet-dev"
}
module "vpc" {
source = "terraform-google-modules/network/google"
version = "~> 7.1"
Expand All @@ -11,4 +12,5 @@ module "vpc" {
routing_mode = "GLOBAL"
auto_create_subnetworks = false
subnets = var.subnets
secondary_ranges = var.secondary_ranges
}
6 changes: 1 addition & 5 deletions infra/gcp/modules/network/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
output "network" {
value = module.vpc.network
}

output "vpc" {
value = module.vpc.network_id
value = module.vpc.network_name
}
8 changes: 7 additions & 1 deletion infra/gcp/modules/network/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ variable "environment" {
# Note: A VPC is a global resource, subnets are regional.
variable "subnets" {
description = "Any subnets of the VPC."
type = list(object({
type = list(object({
subnet_name = string
subnet_ip = string
subnet_region = string
Expand All @@ -39,3 +39,9 @@ variable "subnets" {
}))
default = []
}

variable "secondary_ranges" {
type = map(list(object({ range_name = string, ip_cidr_range = string })))
description = "Secondary ranges that will be used in some of the subnets"
default = {}
}

0 comments on commit 6246921

Please sign in to comment.