From bc74985380b631a1cfe84c984544071d45230034 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Fri, 12 Sep 2025 17:28:04 +0300 Subject: [PATCH 01/15] Create a MongoDB resource type schema and a matching Terraform Kubernetes Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/README.md | 39 +++++++ recipes/kubernetes/mongodb/main.tf | 132 ++++++++++++++++++++++++ recipes/kubernetes/mongodb/outputs.tf | 7 ++ recipes/kubernetes/mongodb/variables.tf | 73 +++++++++++++ schemas/databases/mongodb.yaml | 96 +++++++++++++++++ 5 files changed, 347 insertions(+) create mode 100644 recipes/kubernetes/mongodb/README.md create mode 100644 recipes/kubernetes/mongodb/main.tf create mode 100644 recipes/kubernetes/mongodb/outputs.tf create mode 100644 recipes/kubernetes/mongodb/variables.tf create mode 100644 schemas/databases/mongodb.yaml diff --git a/recipes/kubernetes/mongodb/README.md b/recipes/kubernetes/mongodb/README.md new file mode 100644 index 00000000..7cafba5e --- /dev/null +++ b/recipes/kubernetes/mongodb/README.md @@ -0,0 +1,39 @@ +# MongoDB Kubernetes Recipe (Terraform) + +This recipe provisions a MongoDB instance on Kubernetes using Terraform. + +## Inputs + +- `name` (string, required): MongoDB instance name +- `version` (string, default: 6.0): MongoDB version +- `replicas` (int, default: 1): Number of replicas +- `storage_size` (string, default: 10Gi): PVC size +- `storage_class` (string, default: standard): Storage class +- `username` (string, default: admin): Admin username +- `password` (string, required): Admin password +- `persistence` (bool, default: true): Enable persistence +- `backup_enabled` (bool, default: false): Enable backups +- `backup_schedule` (string): Cron schedule for backups +- `resources` (object): CPU/memory requests/limits + +## Outputs + +- `mongodb_service_name`: Kubernetes service name +- `mongodb_credentials_secret`: Secret containing credentials + +## Manual Testing + +1. Apply Terraform: + ```bash + terraform init + terraform apply -var="name=mydb" -var="password=MySecretPass123" + ``` + +2. Connect to MongoDB: + ```bash + kubectl run mongo-client --rm -it --image=mongo -- \ + mongo "mongodb://$(kubectl get svc mydb-svc -o jsonpath='{.spec.clusterIP}'):27017" \ + -u admin -p MySecretPass123 + ``` + +3. Verify database operations. diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf new file mode 100644 index 00000000..3d7cf7c1 --- /dev/null +++ b/recipes/kubernetes/mongodb/main.tf @@ -0,0 +1,132 @@ +provider "kubernetes" { + config_path = "~/.kube/config" +} + +# Secret for credentials +resource "kubernetes_secret" "mongodb_credentials" { + metadata { + name = "${var.name}-credentials" + namespace = "default" + } + data = { + username = base64encode(var.username) + password = base64encode(var.password) + } +} + +# Persistent Volume Claim (if persistence enabled) +resource "kubernetes_persistent_volume_claim" "mongodb" { + count = var.persistence ? 1 : 0 + + metadata { + name = "${var.name}-pvc" + namespace = "default" + } + + spec { + access_modes = ["ReadWriteOnce"] + resources { + requests = { + storage = var.storage_size + } + } + storage_class_name = var.storage_class + } +} + +# Service +resource "kubernetes_service" "mongodb" { + metadata { + name = "${var.name}-svc" + namespace = "default" + } + + spec { + selector = { + app = var.name + } + port { + port = 27017 + target_port = 27017 + } + type = "ClusterIP" + } +} + +# StatefulSet +resource "kubernetes_stateful_set" "mongodb" { + metadata { + name = var.name + namespace = "default" + labels = { + app = var.name + } + } + + spec { + service_name = "${var.name}-svc" + replicas = var.replicas + + selector { + match_labels = { + app = var.name + } + } + + template { + metadata { + labels = { + app = var.name + } + } + + spec { + container { + name = "mongodb" + image = "mongo:${var.version}" + + port { + container_port = 27017 + } + + env { + name = "MONGO_INITDB_ROOT_USERNAME" + value_from { + secret_key_ref { + name = kubernetes_secret.mongodb_credentials.metadata[0].name + key = "username" + } + } + } + + env { + name = "MONGO_INITDB_ROOT_PASSWORD" + value_from { + secret_key_ref { + name = kubernetes_secret.mongodb_credentials.metadata[0].name + key = "password" + } + } + } + + resources { + requests = var.resources.requests + limits = var.resources.limits + } + + volume_mount { + name = "data" + mount_path = "/data/db" + } + } + volume { + name = "data" + + persistent_volume_claim { + claim_name = kubernetes_persistent_volume_claim.mongodb[0].metadata[0].name + } + } + } + } + } +} diff --git a/recipes/kubernetes/mongodb/outputs.tf b/recipes/kubernetes/mongodb/outputs.tf new file mode 100644 index 00000000..67e8dacd --- /dev/null +++ b/recipes/kubernetes/mongodb/outputs.tf @@ -0,0 +1,7 @@ +output "mongodb_service_name" { + value = kubernetes_service.mongodb.metadata[0].name +} + +output "mongodb_credentials_secret" { + value = kubernetes_secret.mongodb_credentials.metadata[0].name +} diff --git a/recipes/kubernetes/mongodb/variables.tf b/recipes/kubernetes/mongodb/variables.tf new file mode 100644 index 00000000..209d70fa --- /dev/null +++ b/recipes/kubernetes/mongodb/variables.tf @@ -0,0 +1,73 @@ +variable "name" { + description = "The name of the MongoDB instance." + type = string +} + +variable "version" { + description = "MongoDB version" + type = string + default = "6.0" +} + +variable "replicas" { + description = "Number of replicas" + type = number + default = 1 +} + +variable "storage_size" { + description = "Persistent volume size" + type = string + default = "10Gi" +} + +variable "storage_class" { + description = "Kubernetes storage class" + type = string + default = "standard" +} + +variable "username" { + description = "Admin username" + type = string + default = "admin" +} + +variable "password" { + description = "Admin password" + type = string + sensitive = true +} + +variable "persistence" { + description = "Enable persistence" + type = bool + default = true +} + +variable "backup_enabled" { + description = "Enable backups" + type = bool + default = false +} + +variable "backup_schedule" { + description = "Cron schedule for backups" + type = string + default = "" +} + +variable "resources" { + description = "Resource requests and limits" + type = object({ + requests = optional(object({ + cpu = string + memory = string + }), { cpu = "250m", memory = "512Mi" }) + limits = optional(object({ + cpu = string + memory = string + }), { cpu = "500m", memory = "1Gi" }) + }) + default = {} +} diff --git a/schemas/databases/mongodb.yaml b/schemas/databases/mongodb.yaml new file mode 100644 index 00000000..27db7b50 --- /dev/null +++ b/schemas/databases/mongodb.yaml @@ -0,0 +1,96 @@ +type: object +title: MongoDB Database +description: Schema for provisioning a MongoDB database instance on Kubernetes using Terraform. +properties: + name: + type: string + description: The name of the MongoDB database instance. + pattern: '^[a-zA-Z0-9\-]+$' + version: + type: string + description: MongoDB server version to deploy. + default: "6.0" + replicas: + type: integer + description: Number of MongoDB replicas. + minimum: 1 + default: 1 + storage: + type: object + description: Storage configuration for MongoDB. + properties: + size: + type: string + description: Size of the persistent volume claim. + pattern: '^[0-9]+Gi$' + default: "10Gi" + storageClass: + type: string + description: Kubernetes storage class to use. + default: "standard" + required: + - size + credentials: + type: object + description: Database credentials for the admin user. + properties: + username: + type: string + description: Admin username. + default: "admin" + password: + type: string + description: Admin password. + minLength: 8 + required: + - username + - password + persistence: + type: boolean + description: Whether to persist data using PVCs. + default: true + backup: + type: object + description: Backup configuration for MongoDB. + properties: + enabled: + type: boolean + description: Enable/disable backups. + default: false + schedule: + type: string + description: Cron expression for backup schedule. + pattern: '^(@(yearly|annually|monthly|weekly|daily|hourly)|(@every .+)|((\*|[0-9]+)(/|-)?)+ .+)$' + resources: + type: object + description: Resource limits and requests. + properties: + requests: + type: object + properties: + cpu: + type: string + description: Requested CPU. + default: "250m" + memory: + type: string + description: Requested memory. + default: "512Mi" + limits: + type: object + properties: + cpu: + type: string + description: CPU limit. + default: "500m" + memory: + type: string + description: Memory limit. + default: "1Gi" + +required: + - name + - version + - replicas + - storage + - credentials From 3da2afdbd9ee8a119335fee8b67a6399ccaff622 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 11:35:41 +0300 Subject: [PATCH 02/15] Add GitHub Actions workflow that tests MongoDB Recipe (#21) Signed-off-by: Panagiotis Bellias --- .github/workflows/test-mongodb-recipe.yaml | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/test-mongodb-recipe.yaml diff --git a/.github/workflows/test-mongodb-recipe.yaml b/.github/workflows/test-mongodb-recipe.yaml new file mode 100644 index 00000000..27db1e8c --- /dev/null +++ b/.github/workflows/test-mongodb-recipe.yaml @@ -0,0 +1,50 @@ +name: Test MongoDB Recipe + +on: + push: + branches: + - main + - 21-add-k8s-mongodb-recipe-terraform + pull_request: + branches: + - 21-add-k8s-mongodb-recipe-terraform + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + # Install Terraform + - uses: hashicorp/setup-terraform@v2 + with: + terraform_version: 1.7.0 + + # Install kubectl and kind + - name: Install kubectl + run: | + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x kubectl + sudo mv kubectl /usr/local/bin/ + - name: Install kind + run: | + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + # Create a local Kubernetes cluster + - name: Create Kind Cluster + run: kind create cluster --name tf-test + + # Apply Terraform + - name: Terraform Init & Apply + working-directory: recipes/kubernetes/mongodb + run: | + terraform init + terraform apply -auto-approve \ + -var="name=test-mongodb" \ + -var="password=MySecretPass123" + + # Optional: Test pods + - name: List Pods + run: kubectl get pods From cab47a18a7772d0853f11935d60f1956866b8050 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 11:38:23 +0300 Subject: [PATCH 03/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/main.tf | 2 +- recipes/kubernetes/mongodb/variables.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index 3d7cf7c1..6a25dd90 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -83,7 +83,7 @@ resource "kubernetes_stateful_set" "mongodb" { spec { container { name = "mongodb" - image = "mongo:${var.version}" + image = "mongo:${var.mongodb_version}" port { container_port = 27017 diff --git a/recipes/kubernetes/mongodb/variables.tf b/recipes/kubernetes/mongodb/variables.tf index 209d70fa..ab727d75 100644 --- a/recipes/kubernetes/mongodb/variables.tf +++ b/recipes/kubernetes/mongodb/variables.tf @@ -3,7 +3,7 @@ variable "name" { type = string } -variable "version" { +variable "mongodb_version" { description = "MongoDB version" type = string default = "6.0" From 6b69b0c214b7bc2ca208cd1c49973437b759b8ea Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 11:47:17 +0300 Subject: [PATCH 04/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- .github/workflows/test-mongodb-recipe.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-mongodb-recipe.yaml b/.github/workflows/test-mongodb-recipe.yaml index 27db1e8c..604cebd0 100644 --- a/.github/workflows/test-mongodb-recipe.yaml +++ b/.github/workflows/test-mongodb-recipe.yaml @@ -41,9 +41,11 @@ jobs: working-directory: recipes/kubernetes/mongodb run: | terraform init - terraform apply -auto-approve \ - -var="name=test-mongodb" \ - -var="password=MySecretPass123" + terraform apply \ + -var="name=test-mongodb" \ + -var="password=MySecretPass123" \ + -var="persistence=false" \ + -auto-approve # Optional: Test pods - name: List Pods From ddc07ce865b81dfe2b49827e7f0b73fd2a8ac464 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 11:51:22 +0300 Subject: [PATCH 05/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/main.tf | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index 6a25dd90..b8546689 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -119,11 +119,14 @@ resource "kubernetes_stateful_set" "mongodb" { mount_path = "/data/db" } } - volume { - name = "data" + dynamic "volume" { + for_each = var.persistence ? [1] : [] + content { + name = "data" - persistent_volume_claim { - claim_name = kubernetes_persistent_volume_claim.mongodb[0].metadata[0].name + persistent_volume_claim { + claim_name = kubernetes_persistent_volume_claim.mongodb[0].metadata[0].name + } } } } From 6372a93927db01c15fa47ac87f2b3fc4b41d0184 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 12:02:20 +0300 Subject: [PATCH 06/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/kubernetes/mongodb/variables.tf b/recipes/kubernetes/mongodb/variables.tf index ab727d75..d8cb2a3f 100644 --- a/recipes/kubernetes/mongodb/variables.tf +++ b/recipes/kubernetes/mongodb/variables.tf @@ -6,7 +6,7 @@ variable "name" { variable "mongodb_version" { description = "MongoDB version" type = string - default = "6.0" + default = "6.0-focal" } variable "replicas" { From 96fa2af4ad73f300eae79eb86b55ddb79f2dd499 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 12:03:59 +0300 Subject: [PATCH 07/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/main.tf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index b8546689..6338c9d0 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -132,4 +132,8 @@ resource "kubernetes_stateful_set" "mongodb" { } } } + + timeouts { + create = "10m" + } } From 4a34026880a56f9b8a64e02231c972b5833459c8 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 12:14:54 +0300 Subject: [PATCH 08/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index 6338c9d0..c11a5d6d 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -134,6 +134,6 @@ resource "kubernetes_stateful_set" "mongodb" { } timeouts { - create = "10m" + create = "20m" } } From ba99840246def53629fe8f960088403ac76dc015 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 12:36:58 +0300 Subject: [PATCH 09/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index c11a5d6d..ea80d04d 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -134,6 +134,6 @@ resource "kubernetes_stateful_set" "mongodb" { } timeouts { - create = "20m" + create = "40m" } } From 51d65d622a9da810a8e9779b13b7991da69c4847 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 13:34:19 +0300 Subject: [PATCH 10/15] Fix MongoDB Terraform Recipe (#21) Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/main.tf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index ea80d04d..ed4698aa 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -114,9 +114,12 @@ resource "kubernetes_stateful_set" "mongodb" { limits = var.resources.limits } - volume_mount { - name = "data" - mount_path = "/data/db" + dynamic "volume_mount" { + for_each = var.persistence ? [1] : [] + content { + name = "data" + mount_path = "/data/db" + } } } dynamic "volume" { From 1e200e03cb20374cfb973173ca4d448370dd604f Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 14:43:08 +0300 Subject: [PATCH 11/15] Enhance GitHub Actions workflow that tests MongoDB Recipe (#21) Signed-off-by: Panagiotis Bellias --- .github/workflows/test-mongodb-recipe.yaml | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-mongodb-recipe.yaml b/.github/workflows/test-mongodb-recipe.yaml index 604cebd0..5123bdd4 100644 --- a/.github/workflows/test-mongodb-recipe.yaml +++ b/.github/workflows/test-mongodb-recipe.yaml @@ -42,11 +42,27 @@ jobs: run: | terraform init terraform apply \ - -var="name=test-mongodb" \ - -var="password=MySecretPass123" \ - -var="persistence=false" \ - -auto-approve + -var="name=test-mongodb" \ + -var="password=MySecretPass123" \ + -var="persistence=false" \ + -auto-approve # Optional: Test pods - name: List Pods run: kubectl get pods + + # Cleanup: Destroy Terraform resources + - name: Terraform Destroy + if: always() # ensure it runs even if previous steps fail + working-directory: recipes/kubernetes/mongodb + run: | + terraform destroy \ + -var="name=test-mongodb" \ + -var="password=MySecretPass123" \ + -var="persistence=false" \ + -auto-approve + + # Cleanup: Delete Kind cluster + - name: Delete Kind Cluster + if: always() + run: kind delete cluster --name tf-test From 2b85e6c00ba565d9534c55c844228bc22665b605 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 16 Sep 2025 14:48:01 +0300 Subject: [PATCH 12/15] Add MongoDB resource type and Kubernetes Terraform recipe (#21) - mongodb.yaml schema - Terraform recipe (main.tf, variables.tf, outputs.tf) - README.md with usage instructions and manual testing notes Signed-off-by: Panagiotis Bellias --- recipes/kubernetes/mongodb/README.md | 82 +++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/recipes/kubernetes/mongodb/README.md b/recipes/kubernetes/mongodb/README.md index 7cafba5e..a62b6c1d 100644 --- a/recipes/kubernetes/mongodb/README.md +++ b/recipes/kubernetes/mongodb/README.md @@ -2,38 +2,92 @@ This recipe provisions a MongoDB instance on Kubernetes using Terraform. +--- + ## Inputs -- `name` (string, required): MongoDB instance name -- `version` (string, default: 6.0): MongoDB version -- `replicas` (int, default: 1): Number of replicas -- `storage_size` (string, default: 10Gi): PVC size -- `storage_class` (string, default: standard): Storage class -- `username` (string, default: admin): Admin username -- `password` (string, required): Admin password -- `persistence` (bool, default: true): Enable persistence -- `backup_enabled` (bool, default: false): Enable backups -- `backup_schedule` (string): Cron schedule for backups -- `resources` (object): CPU/memory requests/limits +| Variable | Type | Default | Description | +|-------------------|--------|-------------|------------------------------------| +| `name` | string | required | MongoDB instance name | +| `version` | string | 6.0 | MongoDB version | +| `replicas` | int | 1 | Number of replicas | +| `storage_size` | string | 10Gi | PVC size | +| `storage_class` | string | standard | Kubernetes storage class | +| `username` | string | admin | Admin username | +| `password` | string | required | Admin password | +| `persistence` | bool | true | Enable persistence | +| `backup_enabled` | bool | false | Enable backups | +| `backup_schedule` | string | "" | Cron schedule for backups | +| `resources` | object | {} | CPU/memory requests and limits | + +> **Note:** For CI or ephemeral testing, `persistence` should be set to `false` to avoid PVC-related delays in Kind clusters. + +--- ## Outputs - `mongodb_service_name`: Kubernetes service name - `mongodb_credentials_secret`: Secret containing credentials +--- + ## Manual Testing 1. Apply Terraform: ```bash terraform init - terraform apply -var="name=mydb" -var="password=MySecretPass123" + terraform apply \ + -var="name=mydb" \ + -var="password=MySecretPass123" \ + -auto-approve ``` -2. Connect to MongoDB: +2. Check pod status: + ```bash + kubectl get pods + # Ensure test-mongodb-0 is READY=1/1 + ``` + +3. Connect to MongoDB: ```bash kubectl run mongo-client --rm -it --image=mongo -- \ mongo "mongodb://$(kubectl get svc mydb-svc -o jsonpath='{.spec.clusterIP}'):27017" \ -u admin -p MySecretPass123 ``` -3. Verify database operations. +4. Verify database operations. + +5. Clean up (optional): + ```bash + terraform destroy -var="name=mydb" -var="password=MySecretPass123" -auto-approve + ``` + +--- + +## CI / GitHub Actions Testing + +This recipe is automatically tested in GitHub Actions for pull requests and branch pushes. + +- A temporary Kind cluster is created. +- Terraform applies the recipe with `persistence=false` for fast ephemeral testing. +- The workflow waits for MongoDB pods to become ready. +- Terraform destroys the resources and deletes the Kind cluster after the test. + +Workflow file: `.github/workflows/test-mongodb-recipe.yml` + +Example ephemeral test run: +```bash +terraform apply -var="name=test-mongodb" -var="password=MySecretPass123" -var="persistence=false" -auto-approve +kubectl get pods +terraform destroy -var="name=test-mongodb" -var="password=MySecretPass123" -var="persistence=false" -auto-approve +``` + +> Make sure the MongoDB pod shows `READY=1/1` before connecting. + +--- + +## References + +- Radius MongoDB Resource Schema: https://docs.radapp.io/reference/resource-schema/databases/mongodb/ +- Example Kubernetes Recipe: https://github.com/radius-project/recipes/blob/main/local-dev/mongodatabases.bicep + From 8dd5049c5378abbb5707196a6025ff9dd995ca44 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Fri, 3 Oct 2025 12:47:36 +0300 Subject: [PATCH 13/15] Apply some PR review's comments before restructuring (#21) --- .github/workflows/test-mongodb-recipe.yaml | 68 ------ recipes/kubernetes/mongodb/README.md | 75 +++++-- recipes/kubernetes/mongodb/main.tf | 60 +++++- recipes/kubernetes/mongodb/outputs.tf | 7 - recipes/kubernetes/mongodb/variables.tf | 5 + schemas/databases/mongodb.yaml | 237 ++++++++++++--------- 6 files changed, 251 insertions(+), 201 deletions(-) delete mode 100644 .github/workflows/test-mongodb-recipe.yaml delete mode 100644 recipes/kubernetes/mongodb/outputs.tf diff --git a/.github/workflows/test-mongodb-recipe.yaml b/.github/workflows/test-mongodb-recipe.yaml deleted file mode 100644 index 5123bdd4..00000000 --- a/.github/workflows/test-mongodb-recipe.yaml +++ /dev/null @@ -1,68 +0,0 @@ -name: Test MongoDB Recipe - -on: - push: - branches: - - main - - 21-add-k8s-mongodb-recipe-terraform - pull_request: - branches: - - 21-add-k8s-mongodb-recipe-terraform - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - # Install Terraform - - uses: hashicorp/setup-terraform@v2 - with: - terraform_version: 1.7.0 - - # Install kubectl and kind - - name: Install kubectl - run: | - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x kubectl - sudo mv kubectl /usr/local/bin/ - - name: Install kind - run: | - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64 - chmod +x ./kind - sudo mv ./kind /usr/local/bin/kind - - # Create a local Kubernetes cluster - - name: Create Kind Cluster - run: kind create cluster --name tf-test - - # Apply Terraform - - name: Terraform Init & Apply - working-directory: recipes/kubernetes/mongodb - run: | - terraform init - terraform apply \ - -var="name=test-mongodb" \ - -var="password=MySecretPass123" \ - -var="persistence=false" \ - -auto-approve - - # Optional: Test pods - - name: List Pods - run: kubectl get pods - - # Cleanup: Destroy Terraform resources - - name: Terraform Destroy - if: always() # ensure it runs even if previous steps fail - working-directory: recipes/kubernetes/mongodb - run: | - terraform destroy \ - -var="name=test-mongodb" \ - -var="password=MySecretPass123" \ - -var="persistence=false" \ - -auto-approve - - # Cleanup: Delete Kind cluster - - name: Delete Kind Cluster - if: always() - run: kind delete cluster --name tf-test diff --git a/recipes/kubernetes/mongodb/README.md b/recipes/kubernetes/mongodb/README.md index a62b6c1d..dd45a492 100644 --- a/recipes/kubernetes/mongodb/README.md +++ b/recipes/kubernetes/mongodb/README.md @@ -1,37 +1,72 @@ # MongoDB Kubernetes Recipe (Terraform) -This recipe provisions a MongoDB instance on Kubernetes using Terraform. +This recipe provisions a MongoDB instance on Kubernetes using Terraform. It is implemented as a **Radius.Data/mongoDatabases** resource type and can be used in Bicep or Terraform-based applications. --- -## Inputs +## Overview -| Variable | Type | Default | Description | -|-------------------|--------|-------------|------------------------------------| -| `name` | string | required | MongoDB instance name | -| `version` | string | 6.0 | MongoDB version | -| `replicas` | int | 1 | Number of replicas | -| `storage_size` | string | 10Gi | PVC size | -| `storage_class` | string | standard | Kubernetes storage class | -| `username` | string | admin | Admin username | -| `password` | string | required | Admin password | -| `persistence` | bool | true | Enable persistence | -| `backup_enabled` | bool | false | Enable backups | -| `backup_schedule` | string | "" | Cron schedule for backups | -| `resources` | object | {} | CPU/memory requests and limits | +The `mongoDatabases` Resource Type provisions a MongoDB database instance on Kubernetes with optional persistence, resource configuration, and admin credentials. +It supports creating the database service, StatefulSet, PVCs (if persistence is enabled), and secrets for credentials. -> **Note:** For CI or ephemeral testing, `persistence` should be set to `false` to avoid PVC-related delays in Kind clusters. +--- + +## Recipes + +| Platform | IaC Language | Recipe Name | Stage | +|------------|-------------|---------------------|-------| +| Kubernetes | Terraform | kubernetes-mongodb/main.tf | Alpha | + +--- + +## Recipe Input Properties + +| Variable | Type | Default | Description | +|-------------------|--------|-------------|----------------------------------------------| +| `name` | string | required | MongoDB instance name | +| `version` | string | 6.0 | MongoDB version | +| `replicas` | int | 1 | Number of replicas | +| `storage_size` | string | 10Gi | PVC size | +| `storage_class` | string | standard | Kubernetes storage class | +| `username` | string | admin | Admin username | +| `password` | string | required | Admin password | +| `persistence` | bool | true | Enable persistence (creates PVC) | +| `backup_enabled` | bool | false | Enable backups | +| `backup_schedule` | string | "" | Cron schedule for backups | +| `resources` | object | {} | CPU/memory requests and limits | + +> **Note:** For CI or ephemeral testing, set `persistence=false` to avoid PVC-related delays in Kind clusters. --- -## Outputs +## Recipe Output Properties -- `mongodb_service_name`: Kubernetes service name -- `mongodb_credentials_secret`: Secret containing credentials +| Property | Description | +|--------------------------|------------------------------------------------------| +| `values.host` | MongoDB service host (read-only) | +| `values.port` | MongoDB service port (read-only) | +| `values.username` | Admin username (read-only) | +| `secrets.password` | Admin password (sensitive, read-only) | +| `resources` | UCP resource IDs for Service and StatefulSet | --- -## Manual Testing +## Recipe Description + +This Terraform recipe creates: + +1. A Kubernetes **Secret** for MongoDB credentials. +2. An optional **PersistentVolumeClaim** if `persistence=true`. +3. A **ClusterIP Service** for MongoDB. +4. A **StatefulSet** running the specified MongoDB version, replicas, and resources. +5. Optional dynamic volume mounts and PVCs. +6. Outputs exposing connection info and secrets for downstream usage. + +--- + +## Usage Instructions + +### Manual Testing 1. Apply Terraform: ```bash diff --git a/recipes/kubernetes/mongodb/main.tf b/recipes/kubernetes/mongodb/main.tf index ed4698aa..31bfbfdb 100644 --- a/recipes/kubernetes/mongodb/main.tf +++ b/recipes/kubernetes/mongodb/main.tf @@ -2,11 +2,20 @@ provider "kubernetes" { config_path = "~/.kube/config" } +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.0" + } + } +} + # Secret for credentials resource "kubernetes_secret" "mongodb_credentials" { metadata { name = "${var.name}-credentials" - namespace = "default" + namespace = var.context.runtime.kubernetes.namespace } data = { username = base64encode(var.username) @@ -20,7 +29,7 @@ resource "kubernetes_persistent_volume_claim" "mongodb" { metadata { name = "${var.name}-pvc" - namespace = "default" + namespace = var.context.runtime.kubernetes.namespace } spec { @@ -38,7 +47,7 @@ resource "kubernetes_persistent_volume_claim" "mongodb" { resource "kubernetes_service" "mongodb" { metadata { name = "${var.name}-svc" - namespace = "default" + namespace = var.context.runtime.kubernetes.namespace } spec { @@ -57,7 +66,7 @@ resource "kubernetes_service" "mongodb" { resource "kubernetes_stateful_set" "mongodb" { metadata { name = var.name - namespace = "default" + namespace = var.context.runtime.kubernetes.namespace labels = { app = var.name } @@ -66,7 +75,6 @@ resource "kubernetes_stateful_set" "mongodb" { spec { service_name = "${var.name}-svc" replicas = var.replicas - selector { match_labels = { app = var.name @@ -90,20 +98,20 @@ resource "kubernetes_stateful_set" "mongodb" { } env { - name = "MONGO_INITDB_ROOT_USERNAME" + name = "MONGO_INITDB_ROOT_USERNAME" value_from { secret_key_ref { - name = kubernetes_secret.mongodb_credentials.metadata[0].name + name = kubernetes_secret.mongodb_credentials.metadata.name key = "username" } } } env { - name = "MONGO_INITDB_ROOT_PASSWORD" + name = "MONGO_INITDB_ROOT_PASSWORD" value_from { secret_key_ref { - name = kubernetes_secret.mongodb_credentials.metadata[0].name + name = kubernetes_secret.mongodb_credentials.metadata.name key = "password" } } @@ -122,21 +130,53 @@ resource "kubernetes_stateful_set" "mongodb" { } } } + dynamic "volume" { for_each = var.persistence ? [1] : [] content { name = "data" persistent_volume_claim { - claim_name = kubernetes_persistent_volume_claim.mongodb[0].metadata[0].name + claim_name = kubernetes_persistent_volume_claim.mongodb[0].metadata.name } } } } } + + # Optional: Grace period + termination_grace_period_seconds = 30 } timeouts { create = "40m" } } + +output "result" { + value = { + values = { + host = "${kubernetes_service.mongodb.metadata[0].name}.${kubernetes_service.mongodb.metadata[0].namespace}.svc.cluster.local" + port = kubernetes_service.mongodb.spec[0].port[0].port + username = var.username + } + secrets = { + password = var.password + } + # UCP resource IDs + resources = [ + "/planes/kubernetes/local/namespaces/${kubernetes_service.mongodb.metadata[0].namespace}/providers/core/Service/${kubernetes_service.mongodb.metadata[0].name}", + "/planes/kubernetes/local/namespaces/${kubernetes_stateful_set.mongodb.metadata[0].namespace}/providers/apps/StatefulSet/${kubernetes_stateful_set.mongodb.metadata[0].name}" + ] + } + description = < Date: Fri, 3 Oct 2025 12:51:55 +0300 Subject: [PATCH 14/15] Apply restructuring after PR review (#21) --- {recipes/kubernetes/mongodb => Data/mongoDatabases}/README.md | 0 {schemas/databases => Data/mongoDatabases}/mongodb.yaml | 0 .../mongoDatabases/recipes/kubernetes/terraform}/main.tf | 0 .../mongoDatabases/recipes/kubernetes/terraform}/variables.tf | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {recipes/kubernetes/mongodb => Data/mongoDatabases}/README.md (100%) rename {schemas/databases => Data/mongoDatabases}/mongodb.yaml (100%) rename {recipes/kubernetes/mongodb => Data/mongoDatabases/recipes/kubernetes/terraform}/main.tf (100%) rename {recipes/kubernetes/mongodb => Data/mongoDatabases/recipes/kubernetes/terraform}/variables.tf (100%) diff --git a/recipes/kubernetes/mongodb/README.md b/Data/mongoDatabases/README.md similarity index 100% rename from recipes/kubernetes/mongodb/README.md rename to Data/mongoDatabases/README.md diff --git a/schemas/databases/mongodb.yaml b/Data/mongoDatabases/mongodb.yaml similarity index 100% rename from schemas/databases/mongodb.yaml rename to Data/mongoDatabases/mongodb.yaml diff --git a/recipes/kubernetes/mongodb/main.tf b/Data/mongoDatabases/recipes/kubernetes/terraform/main.tf similarity index 100% rename from recipes/kubernetes/mongodb/main.tf rename to Data/mongoDatabases/recipes/kubernetes/terraform/main.tf diff --git a/recipes/kubernetes/mongodb/variables.tf b/Data/mongoDatabases/recipes/kubernetes/terraform/variables.tf similarity index 100% rename from recipes/kubernetes/mongodb/variables.tf rename to Data/mongoDatabases/recipes/kubernetes/terraform/variables.tf From 35b106049f7269b204fa9dbb48670981f54b0ef8 Mon Sep 17 00:00:00 2001 From: Panagiotis Bellias Date: Tue, 7 Oct 2025 15:46:23 +0300 Subject: [PATCH 15/15] Apply PR review's comments (#21) --- Data/mongoDatabases/mongoDatabases.yaml | 102 +++++++++++++++++ Data/mongoDatabases/mongodb.yaml | 141 ------------------------ 2 files changed, 102 insertions(+), 141 deletions(-) create mode 100644 Data/mongoDatabases/mongoDatabases.yaml delete mode 100644 Data/mongoDatabases/mongodb.yaml diff --git a/Data/mongoDatabases/mongoDatabases.yaml b/Data/mongoDatabases/mongoDatabases.yaml new file mode 100644 index 00000000..a1ecc565 --- /dev/null +++ b/Data/mongoDatabases/mongoDatabases.yaml @@ -0,0 +1,102 @@ +namespace: Radius.Data +types: + mongoDatabases: + description: | + The Radius.Data/mongoDatabases Resource Type provisions a MongoDB database instance on Kubernetes using Terraform. + + Start by adding a mongoDatabases resource to your application definition Bicep file: + + resource mongo 'Radius.Data/mongoDatabases@2025-10-01-preview' = { + name: 'mongo' + properties: { + name: 'myMongoDb' + version: '6.0' + size: 'M' + credentials: { + username: 'admin' + password: 'MySecurePassword123' + } + } + } + + Then connect a container to the database: + + resource myContainer 'Radius.Compute/containers@2025-10-01-preview' = { + name: 'myContainer' + properties: { + connections: { + mongo: { + source: mongo.id + } + } + } + } + + The connection automatically injects environment variables into the container for all properties from the database. + The environment variables are named `CONNECTION__`. + In this example, the connection name is `mongo`, so the environment variables will be: + + CONNECTION_MONGO_NAME + CONNECTION_MONGO_VERSION + CONNECTION_MONGO_USERNAME + CONNECTION_MONGO_PASSWORD + CONNECTION_MONGO_HOST + CONNECTION_MONGO_PORT + + These variables expose the connection details and credentials of the MongoDB instance for use by your application. + + > ⚠️ **Security note:** The `CONNECTION_MONGO_PASSWORD` variable contains sensitive data and should be handled carefully. + Avoid logging or exposing it in application outputs. + + apiVersions: + '2025-10-03-preview': + schema: + type: object + properties: + name: + type: string + description: The name of the MongoDB database instance. + pattern: '^[a-zA-Z0-9\-]+$' + version: + type: string + description: MongoDB server version to deploy. + default: "6.0" + size: + type: string + enum: ['S', 'M', 'L'] + description: | + The deployment size profile for the MongoDB instance. + The Recipe implementation defines replicas, resource limits, and storage class for each size. + + - `S`: Small — development and testing + - `M`: Medium — staging or moderate workloads + - `L`: Large — production or high-availability + default: "S" + credentials: + type: object + description: Database credentials for the admin user. + properties: + username: + type: string + description: Admin username. + default: "admin" + password: + type: string + description: Admin password. + minLength: 8 + required: + - username + - password + host: + type: string + description: "(Read-only) The host name used to connect to the MongoDB database." + readOnly: true + port: + type: integer + description: "(Read-only) The port number used to connect to the MongoDB database." + readOnly: true + required: + - name + - version + - size + - credentials diff --git a/Data/mongoDatabases/mongodb.yaml b/Data/mongoDatabases/mongodb.yaml deleted file mode 100644 index a318e42e..00000000 --- a/Data/mongoDatabases/mongodb.yaml +++ /dev/null @@ -1,141 +0,0 @@ -namespace: Radius.Data -types: - mongoDatabases: - description: | - The Radius.Data/mongoDatabases Resource Type provisions a MongoDB database instance on Kubernetes using Terraform. - - Start by adding a mongoDatabases resource to your application definition Bicep file: - - resource mongo 'Radius.Data/mongoDatabases@2025-10-01-preview' = { - name: 'mongo' - properties: { - name: 'myMongoDb' - version: '6.0' - replicas: 1 - storage: { - size: '10Gi' - storageClass: 'standard' - } - credentials: { - username: 'admin' - password: 'MySecurePassword123' - } - persistence: true - } - } - - Then add a connection from a Container resource to the MongoDB resource: - - resource myContainer 'Radius.Compute/containers@2025-10-01-preview' = { - name: 'myContainer' - properties: { ... } - connections: { - mongo: { - source: mongo.id - } - } - } - apiVersions: - '2025-10-03-preview': - schema: - type: object - properties: - name: - type: string - description: The name of the MongoDB database instance. - pattern: '^[a-zA-Z0-9\-]+$' - version: - type: string - description: MongoDB server version to deploy. - default: "6.0" - replicas: - type: integer - description: Number of MongoDB replicas. - minimum: 1 - default: 1 - storage: - type: object - description: Storage configuration for MongoDB. - properties: - size: - type: string - description: Size of the persistent volume claim. - pattern: '^[0-9]+Gi$' - default: "10Gi" - storageClass: - type: string - description: Kubernetes storage class to use. - default: "standard" - required: - - size - credentials: - type: object - description: Database credentials for the admin user. - properties: - username: - type: string - description: Admin username. - default: "admin" - password: - type: string - description: Admin password. - minLength: 8 - required: - - username - - password - persistence: - type: boolean - description: Whether to persist data using PVCs. - default: true - backup: - type: object - description: Backup configuration for MongoDB. - properties: - enabled: - type: boolean - description: Enable/disable backups. - default: false - schedule: - type: string - description: Cron expression for backup schedule. - pattern: '^(@(yearly|annually|monthly|weekly|daily|hourly)|(@every .+)|((\*|[0-9]+)(/|-)?)+ .+)$' - resources: - type: object - description: Resource limits and requests. - properties: - requests: - type: object - properties: - cpu: - type: string - description: Requested CPU. - default: "250m" - memory: - type: string - description: Requested memory. - default: "512Mi" - limits: - type: object - properties: - cpu: - type: string - description: CPU limit. - default: "500m" - memory: - type: string - description: Memory limit. - default: "1Gi" - host: - type: string - description: Connection host - readOnly: true - port: - type: integer - description: Connection port - readOnly: true - required: - - name - - version - - replicas - - storage - - credentials