commit 665aee5895da1f6e6238fac495f9e636a4d7d4cb Author: RaviAnand Mohabir Date: Fri Jan 27 14:08:59 2023 +0100 feat: add Terraform Kubernetes MariaDB module diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b8a46e --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..9e722da --- /dev/null +++ b/main.tf @@ -0,0 +1,158 @@ +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.13.1" + } + } +} + +locals { + port = 3306 + app = "mariadb" + replicas = 1 + match_labels = merge({ + "app.kubernetes.io/name" = "mariadb" + "app.kubernetes.io/instance" = "mariadb" + }, var.match_labels) + labels = merge(local.match_labels, var.labels) + env = "mariadb-env" +} + +resource "kubernetes_stateful_set" "mariadb" { + metadata { + name = var.stateful_set_name + namespace = var.namespace + labels = local.labels + } + spec { + selector { + match_labels = local.labels + } + service_name = local.app + replicas = local.replicas + template { + metadata { + labels = local.labels + } + spec { + affinity { + pod_affinity {} + pod_anti_affinity { + preferred_during_scheduling_ignored_during_execution { + pod_affinity_term { + label_selector { + match_labels = local.match_labels + } + namespaces = [var.namespace] + topology_key = "kubernetes.io/hostname" + } + weight = 1 + } + } + node_affinity {} + } + security_context { + fs_group = 1001 + } + container { + image = var.image_registry == "" ? "${var.image_repository}:${var.image_tag}" : "${var.image_registry}/${var.image_repository}:${var.image_tag}" + name = var.container_name + env_from { + config_map_ref { + name = kubernetes_config_map.mariadb.metadata.0.name + } + } + env { + name = "MARIADB_ROOT_PASSWORD" + value_from { + secret_key_ref { + name = kubernetes_secret.mariadb.metadata.0.name + key = "mariadb-mariadb-password" + } + } + } + env { + name = "MARIADB_PASSWORD" + value_from { + secret_key_ref { + name = kubernetes_secret.mariadb.metadata.0.name + key = "mariadb-password" + } + } + } + port { + name = "tcp-mariadb" + container_port = local.port + } + volume_mount { + name = "data" + mount_path = "/bitnami/mariadb" + } + } + } + } + volume_claim_template { + metadata { + name = "data" + } + spec { + access_modes = ["ReadWriteOnce"] + resources { + requests = { + storage = var.storage_size + } + } + storage_class_name = var.storage_class_name + } + } + } +} + +resource "kubernetes_service" "mariadb" { + metadata { + name = var.service_name + namespace = var.namespace + labels = merge({ + "service.alpha.kubernetes.io/tolerate-unready-endpoints" = "true" + }, local.labels) + } + spec { + type = var.service_type + publish_not_ready_addresses = true + selector = local.match_labels + port { + name = "tcp-mariadb" + port = local.port + } + } + count = var.enable_service ? 1 : 0 +} + +resource "kubernetes_secret" "mariadb" { + metadata { + name = "mariadb" + namespace = var.namespace + labels = local.match_labels + } + type = "Opaque" + data = { + "mariadb-mariadb-password" = var.mariadb_root_password + "mariadb-password" = var.mariadb_password + } +} + +resource "kubernetes_config_map" "mariadb" { + metadata { + name = local.env + namespace = var.namespace + } + + data = { + BITNAMI_DEBUG = "false" + MARIADB_SKIP_TEST_DB = "yes" + MARIADB_ROOT_USER = var.mariadb_root_user + MARIADB_USER = var.mariadb_user + MARIADB_DATABASE = var.mariadb_db + } +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..a724e34 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,23 @@ +output "mariadb_namespace_host" { + value = var.service_name +} + +output "mariadb_cluster_host" { + value = "${var.service_name}.${var.namespace}" +} + +output "mariadb_port" { + value = local.port +} + +output "mariadb_user" { + value = var.mariadb_user +} + +output "mariadb_password" { + value = var.mariadb_password +} + +output "mariadb_db" { + value = var.mariadb_db +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..0f8e2d1 --- /dev/null +++ b/variables.tf @@ -0,0 +1,119 @@ +variable "namespace" { + description = "Namespace to deploy MariaDB" + type = string + default = "default" +} + +variable "mariadb_root_user" { + description = "Username for the root user" + default = "root" + type = string +} + +variable "mariadb_root_password" { + description = "Password for the `root` user" + type = string + sensitive = true +} + +variable "mariadb_user" { + description = "Username for the user" + default = "user" + type = string +} + +variable "mariadb_password" { + description = "Password for the user" + type = string + sensitive = true +} + +variable "mariadb_db" { + description = "Name of the default database" + type = string + sensitive = true +} + +variable "stateful_set_name" { + description = "Name of StatefulSet" + type = string + default = "mariadb" +} + +variable "match_labels" { + description = "Match labels to add to the MariaDB deployment, will be merged with labels" + type = map(any) + default = {} +} + +variable "labels" { + description = "Labels to add to the MariaDB deployment" + type = map(any) + default = {} +} + +variable "volum_claim_template_name" { + description = "Name to use for the volume claim template" + type = string + default = "mariadb-pvc" +} + +variable "replicas" { + description = "Replicas to deploy in the MariaDB StatefulSet" + type = number + default = 1 +} + +variable "storage_size" { + description = "Storage size for the StatefulSet PVC" + type = string + default = "10Gi" +} + +variable "storage_class_name" { + description = "Storage class to use for MariaDB PVCs" + type = string + default = "" +} + +variable "image_registry" { + description = "Image registry, e.g. gcr.io, docker.io" + type = string + default = "" +} + +variable "image_repository" { + description = "Image to start for this pod" + type = string + default = "bitnami/mariadb" +} + +variable "image_tag" { + description = "Image tag to use" + type = string + default = "10.10.2" +} + +variable "container_name" { + description = "Name of the MariaDB container" + type = string + default = "mariadb" +} + +variable "enable_service" { + description = "Enable service for MariaDB" + type = bool + default = true +} + +variable "service_name" { + description = "Name of service to deploy" + type = string + default = "mariadb" +} + +variable "service_type" { + description = "Type of service to deploy" + type = string + default = "ClusterIP" +}