diff --git a/infrastructure/kubernetes/main.tf b/infrastructure/kubernetes/main.tf index 53230c26bb..505725bd0f 100644 --- a/infrastructure/kubernetes/main.tf +++ b/infrastructure/kubernetes/main.tf @@ -39,6 +39,8 @@ locals { k8s_client_certificate = base64decode(data.azurerm_kubernetes_cluster.k8s_cluster.kube_config.0.client_certificate) k8s_client_key = base64decode(data.azurerm_kubernetes_cluster.k8s_cluster.kube_config.0.client_key) k8s_cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.k8s_cluster.kube_config.0.cluster_ca_certificate) + backend_storage_class = "azurefile-csi-nfs" + backend_storage_pvc_name = "backend-shared-spatial-data-storage" } module "k8s_namespaces" { @@ -59,6 +61,15 @@ module "cert_manager" { email = var.cert_email } +module "k8s_storage" { + source = "./modules/storage" + k8s_host = local.k8s_host + k8s_client_certificate = local.k8s_client_certificate + k8s_client_key = local.k8s_client_key + k8s_cluster_ca_certificate = local.k8s_cluster_ca_certificate + backend_storage_class = local.backend_storage_class +} + #### # Production #### @@ -95,6 +106,18 @@ module "k8s_geoprocessing_database_production" { key_vault_id = module.key_vault_production.key_vault_id } +module "backend_storage_pvc_production" { + source = "./modules/volumes" + k8s_host = local.k8s_host + k8s_client_certificate = local.k8s_client_certificate + k8s_client_key = local.k8s_client_key + k8s_cluster_ca_certificate = local.k8s_cluster_ca_certificate + namespace = "production" + backend_storage_class = local.backend_storage_class + backend_storage_pvc_name = local.backend_storage_pvc_name + backend_storage_size = var.backend_storage_size +} + module "api_production" { source = "./modules/api" k8s_host = local.k8s_host @@ -107,6 +130,7 @@ module "api_production" { application_base_url = "https://${var.domain}" network_cors_origins = "https://${var.domain}" http_logging_morgan_format = "" + backend_storage_pvc_name = local.backend_storage_pvc_name } module "geoprocessing_production" { @@ -118,6 +142,7 @@ module "geoprocessing_production" { namespace = "production" image = "marxan.azurecr.io/marxan-geoprocessing:production" deployment_name = "geoprocessing" + backend_storage_pvc_name = local.backend_storage_pvc_name } module "client_production" { @@ -211,6 +236,18 @@ module "k8s_geoprocessing_database_staging" { key_vault_id = module.key_vault_staging.key_vault_id } +module "backend_storage_pvc_staging" { + source = "./modules/volumes" + k8s_host = local.k8s_host + k8s_client_certificate = local.k8s_client_certificate + k8s_client_key = local.k8s_client_key + k8s_cluster_ca_certificate = local.k8s_cluster_ca_certificate + namespace = "staging" + backend_storage_class = local.backend_storage_class + backend_storage_pvc_name = local.backend_storage_pvc_name + backend_storage_size = var.backend_storage_size +} + module "api_staging" { source = "./modules/api" k8s_host = local.k8s_host @@ -223,6 +260,7 @@ module "api_staging" { application_base_url = "https://staging.${var.domain}" network_cors_origins = "https://staging.${var.domain}" http_logging_morgan_format = "short" + backend_storage_pvc_name = local.backend_storage_pvc_name } module "geoprocessing_staging" { @@ -235,6 +273,7 @@ module "geoprocessing_staging" { image = "marxan.azurecr.io/marxan-geoprocessing:staging" deployment_name = "geoprocessing" cleanup_temporary_folders = "false" + backend_storage_pvc_name = local.backend_storage_pvc_name } module "client_staging" { diff --git a/infrastructure/kubernetes/modules/api/main.tf b/infrastructure/kubernetes/modules/api/main.tf index 4c4e6af1f1..9d43d577b1 100644 --- a/infrastructure/kubernetes/modules/api/main.tf +++ b/infrastructure/kubernetes/modules/api/main.tf @@ -53,6 +53,13 @@ resource "kubernetes_deployment" "api_deployment" { } } + volume { + name = "shared-spatial-data-storage" + persistent_volume_claim { + claim_name = var.backend_storage_pvc_name + } + } + container { image = var.image image_pull_policy = "Always" @@ -60,6 +67,11 @@ resource "kubernetes_deployment" "api_deployment" { args = ["start"] + volume_mount { + mount_path = "/tmp/storage" + name = "shared-spatial-data-storage" + } + env { name = "API_POSTGRES_HOST" value_from { diff --git a/infrastructure/kubernetes/modules/api/variable.tf b/infrastructure/kubernetes/modules/api/variable.tf index 7dcbfdfbbc..53a4fe2325 100644 --- a/infrastructure/kubernetes/modules/api/variable.tf +++ b/infrastructure/kubernetes/modules/api/variable.tf @@ -48,3 +48,8 @@ variable "http_logging_morgan_format" { type = string description = "Value for the BACKEND_HTTP_LOGGING_MORGAN_FORMAT env var" } + +variable "backend_storage_pvc_name" { + type = string + description = "Name of the PVC to use for backend storage" +} diff --git a/infrastructure/kubernetes/modules/geoprocessing/main.tf b/infrastructure/kubernetes/modules/geoprocessing/main.tf index 898ef7dd47..a2730a6098 100644 --- a/infrastructure/kubernetes/modules/geoprocessing/main.tf +++ b/infrastructure/kubernetes/modules/geoprocessing/main.tf @@ -53,6 +53,13 @@ resource "kubernetes_deployment" "geoprocessing_deployment" { } } + volume { + name = "shared-spatial-data-storage" + persistent_volume_claim { + claim_name = var.backend_storage_pvc_name + } + } + container { image = var.image image_pull_policy = "Always" @@ -60,6 +67,10 @@ resource "kubernetes_deployment" "geoprocessing_deployment" { args = ["start"] + volume_mount { + mount_path = "/tmp/storage" + name = "shared-spatial-data-storage" + } env { name = "API_POSTGRES_HOST" diff --git a/infrastructure/kubernetes/modules/geoprocessing/variable.tf b/infrastructure/kubernetes/modules/geoprocessing/variable.tf index 1604ac74e9..47d8a6409a 100644 --- a/infrastructure/kubernetes/modules/geoprocessing/variable.tf +++ b/infrastructure/kubernetes/modules/geoprocessing/variable.tf @@ -38,3 +38,8 @@ variable "cleanup_temporary_folders" { default = true description = "Whether to cleanup temporary folders (should only be false temporarily and for diagnostic purposes)" } + +variable "backend_storage_pvc_name" { + type = string + description = "Name of the PVC to use for backend storage" +} diff --git a/infrastructure/kubernetes/modules/key_vault/variable.tf b/infrastructure/kubernetes/modules/key_vault/variable.tf index 4cdcc09b67..b62d47a8cb 100644 --- a/infrastructure/kubernetes/modules/key_vault/variable.tf +++ b/infrastructure/kubernetes/modules/key_vault/variable.tf @@ -7,7 +7,6 @@ variable "resource_group" { description = "The Azure resource group where the module will create its resources" } - variable "namespace" { description = "The k8s namespace in which to deploy resources" } diff --git a/infrastructure/kubernetes/modules/storage/main.tf b/infrastructure/kubernetes/modules/storage/main.tf new file mode 100644 index 0000000000..7ccc0bad0f --- /dev/null +++ b/infrastructure/kubernetes/modules/storage/main.tf @@ -0,0 +1,11 @@ +resource "kubernetes_storage_class" "azurefile_csi_nfs" { + metadata { + name = var.backend_storage_class + } + storage_provisioner = "file.csi.azure.com" + reclaim_policy = "Delete" + parameters = { + protocol = "nfs" + } + mount_options = ["nconnect=8"] +} diff --git a/infrastructure/kubernetes/modules/storage/variable.tf b/infrastructure/kubernetes/modules/storage/variable.tf new file mode 100644 index 0000000000..66407fbcb8 --- /dev/null +++ b/infrastructure/kubernetes/modules/storage/variable.tf @@ -0,0 +1,24 @@ +variable "k8s_host" { + description = "Hostname of the k8s cluster" + type = string +} + +variable "k8s_client_certificate" { + description = "Client certificate for the k8s cluster" + type = string +} + +variable "k8s_client_key" { + description = "Client key for the k8s cluster" + type = string +} + +variable "k8s_cluster_ca_certificate" { + description = "Cluster CA certificate for the k8s cluster" + type = string +} + +variable "backend_storage_class" { + description = "Storage class for backend storage" + type = string +} diff --git a/infrastructure/kubernetes/modules/storage/versions.tf b/infrastructure/kubernetes/modules/storage/versions.tf new file mode 100644 index 0000000000..deb9e3ee86 --- /dev/null +++ b/infrastructure/kubernetes/modules/storage/versions.tf @@ -0,0 +1,21 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "2.92.0" + } + + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.8.0" + } + } + required_version = "1.1.3" +} + +provider "kubernetes" { + host = var.k8s_host + client_certificate = var.k8s_client_certificate + client_key = var.k8s_client_key + cluster_ca_certificate = var.k8s_cluster_ca_certificate +} diff --git a/infrastructure/kubernetes/modules/volumes/main.tf b/infrastructure/kubernetes/modules/volumes/main.tf new file mode 100644 index 0000000000..40907ab634 --- /dev/null +++ b/infrastructure/kubernetes/modules/volumes/main.tf @@ -0,0 +1,15 @@ +resource "kubernetes_persistent_volume_claim" "backend_shared_spatial_data_storage" { + metadata { + name = var.backend_storage_pvc_name + namespace = var.namespace + } + spec { + access_modes = ["ReadWriteMany"] + storage_class_name = var.backend_storage_class + resources { + requests = { + storage = var.backend_storage_size + } + } + } +} diff --git a/infrastructure/kubernetes/modules/volumes/variable.tf b/infrastructure/kubernetes/modules/volumes/variable.tf new file mode 100644 index 0000000000..34a769f827 --- /dev/null +++ b/infrastructure/kubernetes/modules/volumes/variable.tf @@ -0,0 +1,38 @@ +variable "k8s_host" { + description = "Hostname of the k8s cluster" + type = string +} + +variable "k8s_client_certificate" { + description = "Client certificate for the k8s cluster" + type = string +} + +variable "k8s_client_key" { + description = "Client key for the k8s cluster" + type = string +} + +variable "k8s_cluster_ca_certificate" { + description = "Cluster CA certificate for the k8s cluster" + type = string +} + +variable "namespace" { + description = "The k8s namespace in which to deploy resources" +} + +variable "backend_storage_class" { + description = "Storage class for backend storage" + type = string +} + +variable "backend_storage_size" { + type = string + description = "Size of the PVC to use for backend storage" +} + +variable "backend_storage_pvc_name" { + type = string + description = "Name of the PVC to use for backend storage" +} diff --git a/infrastructure/kubernetes/modules/volumes/versions.tf b/infrastructure/kubernetes/modules/volumes/versions.tf new file mode 100644 index 0000000000..deb9e3ee86 --- /dev/null +++ b/infrastructure/kubernetes/modules/volumes/versions.tf @@ -0,0 +1,21 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "2.92.0" + } + + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.8.0" + } + } + required_version = "1.1.3" +} + +provider "kubernetes" { + host = var.k8s_host + client_certificate = var.k8s_client_certificate + client_key = var.k8s_client_key + cluster_ca_certificate = var.k8s_cluster_ca_certificate +} diff --git a/infrastructure/kubernetes/variables.tf b/infrastructure/kubernetes/variables.tf index 382eacc2ea..a0fd6a7d4c 100644 --- a/infrastructure/kubernetes/variables.tf +++ b/infrastructure/kubernetes/variables.tf @@ -29,3 +29,9 @@ variable "sparkpost_api_key" { type = string description = "The API key for Sparkpost" } + +variable "backend_storage_size" { + type = string + default = "100Gi" + description = "Size of the backend storage claim" +}