feature/tofu (#15)
@thomas.solbjor her er "import" av tofu fra ditt repo med justeringer for å tilpasse patterns her. Også minimalisert til å kun opprette cluster, ingen managed services som postgres etc. Ta en titt. Co-authored-by: Danijel Simeunovic <danijel.simeunovic@fortedigital.com> Reviewed-on: #15 Reviewed-by: Danijel Simeunovic <danijel.simeunovic@fortedigital.com> Co-authored-by: Ghost <> Co-committed-by: Ghost <>
This commit was merged in pull request #15.
This commit is contained in:
17
.tofu/platforms/gke/dev/main.tf
Normal file
17
.tofu/platforms/gke/dev/main.tf
Normal file
@@ -0,0 +1,17 @@
|
||||
module "cluster" {
|
||||
source = "../modules/cluster"
|
||||
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
prefix = "clst-dev"
|
||||
|
||||
# GKE — small dev nodes
|
||||
node_machine_type = "e2-standard-2"
|
||||
node_count = 2
|
||||
deletion_protection = false
|
||||
|
||||
labels = {
|
||||
environment = "dev"
|
||||
managed-by = "tofu"
|
||||
}
|
||||
}
|
||||
3
.tofu/platforms/gke/dev/outputs.tf
Normal file
3
.tofu/platforms/gke/dev/outputs.tf
Normal file
@@ -0,0 +1,3 @@
|
||||
output "cluster_name" { value = module.cluster.cluster_name }
|
||||
output "project_id" { value = module.cluster.project_id }
|
||||
output "region" { value = module.cluster.region }
|
||||
26
.tofu/platforms/gke/dev/providers.tf
Normal file
26
.tofu/platforms/gke/dev/providers.tf
Normal file
@@ -0,0 +1,26 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Authentication: use Application Default Credentials (gcloud auth application-default login)
|
||||
# or set GOOGLE_APPLICATION_CREDENTIALS to a service account key file.
|
||||
provider "google" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "GCP project ID for the dev environment"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "GCP region"
|
||||
type = string
|
||||
default = "europe-west4"
|
||||
}
|
||||
115
.tofu/platforms/gke/modules/cluster/main.tf
Normal file
115
.tofu/platforms/gke/modules/cluster/main.tf
Normal file
@@ -0,0 +1,115 @@
|
||||
# ─── Required APIs ────────────────────────────────────────────────────
|
||||
|
||||
resource "google_project_service" "compute" {
|
||||
project = var.project_id
|
||||
service = "compute.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "container" {
|
||||
project = var.project_id
|
||||
service = "container.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
# ─── Networking ───────────────────────────────────────────────────────
|
||||
|
||||
resource "google_compute_network" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-vpc"
|
||||
auto_create_subnetworks = false
|
||||
|
||||
depends_on = [google_project_service.compute]
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-subnet"
|
||||
ip_cidr_range = "10.100.0.0/22"
|
||||
region = var.region
|
||||
network = google_compute_network.main.id
|
||||
|
||||
# Secondary ranges required for GKE VPC-native cluster
|
||||
secondary_ip_range {
|
||||
range_name = "pods"
|
||||
ip_cidr_range = "10.200.0.0/14" # /14 = ~262k pod IPs
|
||||
}
|
||||
|
||||
secondary_ip_range {
|
||||
range_name = "services"
|
||||
ip_cidr_range = "10.204.0.0/20" # /20 = ~4k service IPs
|
||||
}
|
||||
}
|
||||
|
||||
# ─── GKE Cluster ──────────────────────────────────────────────────────
|
||||
#
|
||||
# Regional cluster (3 control-plane replicas) for HA.
|
||||
# Workload Identity enabled — allows K8s service accounts to impersonate
|
||||
# Google Service Accounts for keyless access to GCP services.
|
||||
|
||||
resource "google_container_cluster" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-gke"
|
||||
location = var.region # regional cluster
|
||||
|
||||
network = google_compute_network.main.id
|
||||
subnetwork = google_compute_subnetwork.main.id
|
||||
|
||||
# VPC-native cluster with alias IP ranges
|
||||
ip_allocation_policy {
|
||||
cluster_secondary_range_name = "pods"
|
||||
services_secondary_range_name = "services"
|
||||
}
|
||||
|
||||
# Workload Identity pool — enables OIDC token projection for pods
|
||||
workload_identity_config {
|
||||
workload_pool = "${var.project_id}.svc.id.goog"
|
||||
}
|
||||
|
||||
# Remove default node pool — we manage our own below
|
||||
remove_default_node_pool = true
|
||||
initial_node_count = 1
|
||||
|
||||
deletion_protection = var.deletion_protection
|
||||
|
||||
dynamic "release_channel" {
|
||||
for_each = var.kubernetes_version == null ? [1] : []
|
||||
content {
|
||||
channel = "STABLE"
|
||||
}
|
||||
}
|
||||
|
||||
resource_labels = var.labels
|
||||
|
||||
depends_on = [google_project_service.container]
|
||||
}
|
||||
|
||||
resource "google_container_node_pool" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-nodes"
|
||||
location = var.region
|
||||
cluster = google_container_cluster.main.name
|
||||
node_count = var.node_count
|
||||
|
||||
node_config {
|
||||
machine_type = var.node_machine_type
|
||||
|
||||
# GKE_METADATA mode is required for Workload Identity
|
||||
workload_metadata_config {
|
||||
mode = "GKE_METADATA"
|
||||
}
|
||||
|
||||
oauth_scopes = [
|
||||
"https://www.googleapis.com/auth/cloud-platform",
|
||||
]
|
||||
|
||||
labels = merge(var.labels, {
|
||||
role = "worker"
|
||||
})
|
||||
}
|
||||
|
||||
management {
|
||||
auto_repair = true
|
||||
auto_upgrade = true
|
||||
}
|
||||
}
|
||||
16
.tofu/platforms/gke/modules/cluster/outputs.tf
Normal file
16
.tofu/platforms/gke/modules/cluster/outputs.tf
Normal file
@@ -0,0 +1,16 @@
|
||||
# ─── Cluster ─────────────────────────────────────────────────────────
|
||||
|
||||
output "cluster_name" {
|
||||
description = "GKE cluster name"
|
||||
value = google_container_cluster.main.name
|
||||
}
|
||||
|
||||
output "project_id" {
|
||||
description = "GCP project ID"
|
||||
value = var.project_id
|
||||
}
|
||||
|
||||
output "region" {
|
||||
description = "GCP region"
|
||||
value = var.region
|
||||
}
|
||||
8
.tofu/platforms/gke/modules/cluster/providers.tf
Normal file
8
.tofu/platforms/gke/modules/cluster/providers.tf
Normal file
@@ -0,0 +1,8 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
48
.tofu/platforms/gke/modules/cluster/variables.tf
Normal file
48
.tofu/platforms/gke/modules/cluster/variables.tf
Normal file
@@ -0,0 +1,48 @@
|
||||
# ─── Project / Region ────────────────────────────────────────────────
|
||||
|
||||
variable "project_id" {
|
||||
description = "GCP project ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "GCP region (e.g., europe-west4, europe-west1)"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "prefix" {
|
||||
description = "Prefix for resource names (e.g., clst-dev)"
|
||||
type = string
|
||||
}
|
||||
|
||||
# ─── GKE Cluster ─────────────────────────────────────────────────────
|
||||
|
||||
variable "node_machine_type" {
|
||||
description = "GKE node machine type (e.g., e2-standard-2, e2-standard-4)"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "node_count" {
|
||||
description = "Number of nodes per zone (regional cluster spawns nodes in each zone)"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "kubernetes_version" {
|
||||
description = "GKE Kubernetes version channel (null = STABLE release channel)"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "deletion_protection" {
|
||||
description = "Prevent cluster deletion (set true for production)"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
# ─── Labels ──────────────────────────────────────────────────────────
|
||||
|
||||
variable "labels" {
|
||||
description = "Labels applied to all resources"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
17
.tofu/platforms/gke/prod/main.tf
Normal file
17
.tofu/platforms/gke/prod/main.tf
Normal file
@@ -0,0 +1,17 @@
|
||||
module "cluster" {
|
||||
source = "../modules/cluster"
|
||||
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
prefix = "clst"
|
||||
|
||||
# GKE — general-purpose nodes for production
|
||||
node_machine_type = "e2-standard-4"
|
||||
node_count = 3
|
||||
deletion_protection = true
|
||||
|
||||
labels = {
|
||||
environment = "prod"
|
||||
managed-by = "tofu"
|
||||
}
|
||||
}
|
||||
3
.tofu/platforms/gke/prod/outputs.tf
Normal file
3
.tofu/platforms/gke/prod/outputs.tf
Normal file
@@ -0,0 +1,3 @@
|
||||
output "cluster_name" { value = module.cluster.cluster_name }
|
||||
output "project_id" { value = module.cluster.project_id }
|
||||
output "region" { value = module.cluster.region }
|
||||
24
.tofu/platforms/gke/prod/providers.tf
Normal file
24
.tofu/platforms/gke/prod/providers.tf
Normal file
@@ -0,0 +1,24 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "google" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "GCP project ID for the prod environment"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "GCP region"
|
||||
type = string
|
||||
default = "europe-west1"
|
||||
}
|
||||
194
.tofu/platforms/gke/workload/main.tf
Normal file
194
.tofu/platforms/gke/workload/main.tf
Normal file
@@ -0,0 +1,194 @@
|
||||
# =============================================================================
|
||||
# GCP Workload Cluster
|
||||
# =============================================================================
|
||||
# A lean GKE cluster for running application workloads. No managed data
|
||||
# services — those live on the platform cluster. ArgoCD (on the platform
|
||||
# cluster) deploys apps to this cluster via the app-of-apps pattern.
|
||||
#
|
||||
# Platform components deployed by deploy-workload.sh:
|
||||
# nginx-ingress, cert-manager, external-dns, external-secrets, alloy
|
||||
#
|
||||
# Usage:
|
||||
# tofu init && tofu plan && tofu apply
|
||||
# ./sync-tofu-outputs.sh --env gcp-workload
|
||||
# ./deploy-workload.sh --env gcp-workload
|
||||
# =============================================================================
|
||||
|
||||
variable "prefix" {
|
||||
description = "Prefix for resource names (e.g., clst-workload)"
|
||||
type = string
|
||||
default = "clst-workload"
|
||||
}
|
||||
|
||||
variable "node_machine_type" {
|
||||
description = "GKE node machine type"
|
||||
type = string
|
||||
default = "e2-standard-2"
|
||||
}
|
||||
|
||||
variable "node_count" {
|
||||
description = "Number of nodes per zone"
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "kubernetes_version" {
|
||||
description = "GKE Kubernetes version (null = STABLE release channel)"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "deletion_protection" {
|
||||
description = "Prevent cluster deletion"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "Labels applied to all resources"
|
||||
type = map(string)
|
||||
default = {
|
||||
environment = "workload"
|
||||
managed-by = "tofu"
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Required APIs ────────────────────────────────────────────────────
|
||||
|
||||
resource "google_project_service" "compute" {
|
||||
project = var.project_id
|
||||
service = "compute.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "container" {
|
||||
project = var.project_id
|
||||
service = "container.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "iam" {
|
||||
project = var.project_id
|
||||
service = "iam.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
resource "google_project_service" "dns" {
|
||||
project = var.project_id
|
||||
service = "dns.googleapis.com"
|
||||
disable_on_destroy = false
|
||||
}
|
||||
|
||||
# ─── Networking ───────────────────────────────────────────────────────
|
||||
|
||||
resource "google_compute_network" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-vpc"
|
||||
auto_create_subnetworks = false
|
||||
|
||||
depends_on = [google_project_service.compute]
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-subnet"
|
||||
ip_cidr_range = "10.110.0.0/22"
|
||||
region = var.region
|
||||
network = google_compute_network.main.id
|
||||
|
||||
secondary_ip_range {
|
||||
range_name = "pods"
|
||||
ip_cidr_range = "10.210.0.0/14"
|
||||
}
|
||||
|
||||
secondary_ip_range {
|
||||
range_name = "services"
|
||||
ip_cidr_range = "10.214.0.0/20"
|
||||
}
|
||||
}
|
||||
|
||||
# ─── GKE Cluster ──────────────────────────────────────────────────────
|
||||
|
||||
resource "google_container_cluster" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-gke"
|
||||
location = var.region
|
||||
|
||||
network = google_compute_network.main.id
|
||||
subnetwork = google_compute_subnetwork.main.id
|
||||
|
||||
ip_allocation_policy {
|
||||
cluster_secondary_range_name = "pods"
|
||||
services_secondary_range_name = "services"
|
||||
}
|
||||
|
||||
workload_identity_config {
|
||||
workload_pool = "${var.project_id}.svc.id.goog"
|
||||
}
|
||||
|
||||
remove_default_node_pool = true
|
||||
initial_node_count = 1
|
||||
|
||||
deletion_protection = var.deletion_protection
|
||||
|
||||
dynamic "release_channel" {
|
||||
for_each = var.kubernetes_version == null ? [1] : []
|
||||
content {
|
||||
channel = "STABLE"
|
||||
}
|
||||
}
|
||||
|
||||
resource_labels = var.labels
|
||||
|
||||
depends_on = [google_project_service.container]
|
||||
}
|
||||
|
||||
resource "google_container_node_pool" "main" {
|
||||
project = var.project_id
|
||||
name = "${var.prefix}-nodes"
|
||||
location = var.region
|
||||
cluster = google_container_cluster.main.name
|
||||
node_count = var.node_count
|
||||
|
||||
node_config {
|
||||
machine_type = var.node_machine_type
|
||||
|
||||
workload_metadata_config {
|
||||
mode = "GKE_METADATA"
|
||||
}
|
||||
|
||||
oauth_scopes = [
|
||||
"https://www.googleapis.com/auth/cloud-platform",
|
||||
]
|
||||
|
||||
labels = merge(var.labels, { role = "worker" })
|
||||
}
|
||||
|
||||
management {
|
||||
auto_repair = true
|
||||
auto_upgrade = true
|
||||
}
|
||||
}
|
||||
|
||||
# ─── External-DNS Workload Identity ──────────────────────────────────
|
||||
# Allows external-dns to manage Cloud DNS records for app ingresses.
|
||||
|
||||
resource "google_service_account" "external_dns" {
|
||||
project = var.project_id
|
||||
account_id = "${var.prefix}-external-dns"
|
||||
display_name = "External-DNS Service Account (Workload Identity)"
|
||||
|
||||
depends_on = [google_project_service.iam]
|
||||
}
|
||||
|
||||
resource "google_project_iam_member" "external_dns_dns_admin" {
|
||||
project = var.project_id
|
||||
role = "roles/dns.admin"
|
||||
member = "serviceAccount:${google_service_account.external_dns.email}"
|
||||
}
|
||||
|
||||
resource "google_service_account_iam_member" "external_dns_workload_identity" {
|
||||
service_account_id = google_service_account.external_dns.name
|
||||
role = "roles/iam.workloadIdentityUser"
|
||||
member = "serviceAccount:${var.project_id}.svc.id.goog[external-dns/external-dns]"
|
||||
}
|
||||
4
.tofu/platforms/gke/workload/outputs.tf
Normal file
4
.tofu/platforms/gke/workload/outputs.tf
Normal file
@@ -0,0 +1,4 @@
|
||||
output "cluster_name" { value = google_container_cluster.main.name }
|
||||
output "project_id" { value = var.project_id }
|
||||
output "region" { value = var.region }
|
||||
output "external_dns_gsa_email" { value = google_service_account.external_dns.email }
|
||||
26
.tofu/platforms/gke/workload/providers.tf
Normal file
26
.tofu/platforms/gke/workload/providers.tf
Normal file
@@ -0,0 +1,26 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Authentication: use Application Default Credentials (gcloud auth application-default login)
|
||||
# or set GOOGLE_APPLICATION_CREDENTIALS to a service account key file.
|
||||
provider "google" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "GCP project ID for the workload environment"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "GCP region"
|
||||
type = string
|
||||
default = "europe-west4"
|
||||
}
|
||||
Reference in New Issue
Block a user