diff --git a/modules/20-services-apps/nocodb/.env.example b/modules/20-services-apps/nocodb/.env.example new file mode 100644 index 0000000..a9df4cf --- /dev/null +++ b/modules/20-services-apps/nocodb/.env.example @@ -0,0 +1,4 @@ +# Database Configuration +DB_USERNAME=postgres +DB_PASSWORD=change_this_password +DB_DATABASE=root_db \ No newline at end of file diff --git a/modules/20-services-apps/nocodb/README.md b/modules/20-services-apps/nocodb/README.md new file mode 100644 index 0000000..8760ebf --- /dev/null +++ b/modules/20-services-apps/nocodb/README.md @@ -0,0 +1,106 @@ +# NocoDB Module + +This module deploys [NocoDB](https://www.nocodb.com/), an open-source no-code database platform that transforms PostgreSQL into a smart spreadsheet interface, as Docker containers in the homelab environment. + +## Overview + +The NocoDB module: + +- Deploys two Docker containers: + - `nocodb`: The main NocoDB application server + - `nocodb-postgres`: A PostgreSQL database backend +- Creates a dedicated Docker network (`nocodb-network`) for container communication +- Persists data to volumes on the host +- Provides service definition for integration with networking modules + +## Usage + +```hcl +module "nocodb" { + source = "./modules/20-services-apps/nocodb" + volume_path = "/path/to/volumes" + networks = ["homelab-network"] + postgres_user = "postgres" + postgres_password = "your_secure_password" + postgres_db = "root_db" +} +``` + +## Variables + +| Variable | Description | Type | Default | +| ------------------- | -------------------------------------------------------------- | -------------- | ---------------------- | +| `image_tag` | Tag of the NocoDB image to use | `string` | `"latest"` | +| `postgres_image_tag`| Tag of the PostgreSQL image to use | `string` | `"16.6"` | +| `volume_path` | Host path for NocoDB and database data volumes | `string` | - | +| `networks` | List of networks to which NocoDB should be attached | `list(string)` | `[]` | + +## Outputs + +| Output | Description | +| -------------------- | ---------------------------------------------------------- | +| `service_definition` | Service definition for integration with networking modules | + +## Service Definition + +This module outputs a service definition that is used by the networking modules to expose the service. + +```hcl +{ + name = "nocodb" + primary_port = 8080 + endpoint = "http://nocodb:8080" + subdomains = ["nocodb"] + publish_via = "tunnel" # Only publish through Cloudflare tunnel +} +``` + +## Environment Variables + +NocoDB requires several environment variables to function properly. These are stored in a `.env` file in the module directory and read using the `dotenv` Terraform provider: + +- Database configuration: + + - `DB_USERNAME`: PostgreSQL user + - `DB_PASSWORD`: PostgreSQL password + - `DB_DATABASE`: Database name (defaults to "root_db") + +## Data Persistence + +NocoDB stores its data in two main volumes: + +1. NocoDB application data: `/usr/app/data` in the container, mapped to `${volume_path}/nocodb/data` on the host +2. PostgreSQL data: `/var/lib/postgresql/data` in the container, mapped to `${volume_path}/nocodb/postgres/data` on the host + +## Networking + +The module creates a dedicated Docker network named `nocodb-network` for communication between the NocoDB components. The NocoDB server container is also attached to any additional networks specified in the `networks` variable, allowing it to communicate with other services in the homelab. + +## Dependencies + +The NocoDB container depends on PostgreSQL, which includes a healthcheck to ensure it's ready before NocoDB starts. + +## Integration with Networking Modules + +This service is configured to be exposed through a Cloudflare tunnel for secure remote access, set by `publish_via = "tunnel"`. + +## Example Integration in Main Configuration + +```hcl +module "nocodb" { + source = "./modules/20-services-apps/nocodb" + volume_path = module.system_globals.volume_host + networks = [module.services.homelab_docker_network_name] + postgres_password = "your_secure_password" +} + +# The service definition is automatically included in the services output +module "services" { + source = "./modules/services" + # ... + service_definitions = [ + module.nocodb.service_definition, + # Other service definitions + ] +} +``` diff --git a/modules/20-services-apps/nocodb/main.tf b/modules/20-services-apps/nocodb/main.tf new file mode 100644 index 0000000..35214d3 --- /dev/null +++ b/modules/20-services-apps/nocodb/main.tf @@ -0,0 +1,129 @@ +terraform { + required_providers { + dotenv = { + source = "germanbrew/dotenv" + } + } +} + +variable "image_tag" { + description = "Tag of the NocoDB image to use" + type = string + default = "latest" +} + +variable "postgres_image_tag" { + description = "Tag of the Postgres image to use" + type = string + default = "16.6" +} + +variable "volume_path" { + description = "Host path for NocoDB data volumes" + type = string +} + +variable "networks" { + description = "List of networks to which the containers should be attached" + type = list(string) + default = [] +} + +locals { + container_name = "nocodb" + postgres_name = "nocodb-postgres" + nocodb_image = "nocodb/nocodb" + postgres_image = "postgres" + nocodb_tag = var.image_tag + postgres_tag = var.postgres_image_tag + monitoring = true + nocodb_internal_port = 8080 + env_file = "${path.module}/.env" + postgres_user = provider::dotenv::get_by_key("DB_USERNAME", local.env_file) + postgres_password = provider::dotenv::get_by_key("DB_PASSWORD", local.env_file) + postgres_db = provider::dotenv::get_by_key("DB_DATABASE", local.env_file) + + # Define volumes + nocodb_volumes = [ + { + host_path = "${var.volume_path}/nocodb/data" + container_path = "/usr/app/data" + read_only = false + } + ] + + postgres_volumes = [ + { + host_path = "${var.volume_path}/nocodb/postgres/data" + container_path = "/var/lib/postgresql/data" + read_only = false + } + ] + + # Environment variables for postgres + postgres_env_vars = { + POSTGRES_USER = local.postgres_user + POSTGRES_PASSWORD = local.postgres_password + POSTGRES_DB = local.postgres_db + POSTGRES_INITDB_ARGS = "--data-checksums" + POSTGRES_HOST_AUTH_METHOD = "trust" + } + + # Environment variables for NocoDB + nocodb_env_vars = { + NC_DB = "pg://${local.postgres_name}:5432?u=${local.postgres_user}&p=${local.postgres_password}&d=${local.postgres_db}" + } + + # Healthcheck configuration for Postgres + postgres_healthcheck = { + test = ["CMD", "pg_isready", "-U", local.postgres_user, "-d", local.postgres_db] + interval = "10s" + timeout = "2s" + retries = 10 + start_period = "5s" + } +} + +module "nocodb_network" { + source = "../../01-networking/docker-network" + name = "nocodb-network" + subnet = "11.101.0.0/16" + driver = "bridge" +} + +# Create the PostgreSQL container +module "postgres" { + source = "../../10-services-generic/docker-service" + container_name = local.postgres_name + image = local.postgres_image + tag = local.postgres_tag + volumes = local.postgres_volumes + env_vars = local.postgres_env_vars + networks = [module.nocodb_network.name] + monitoring = local.monitoring + healthcheck = local.postgres_healthcheck +} + +# Create the NocoDB container +module "nocodb" { + source = "../../10-services-generic/docker-service" + container_name = local.container_name + image = local.nocodb_image + tag = local.nocodb_tag + volumes = local.nocodb_volumes + env_vars = local.nocodb_env_vars + networks = concat([module.nocodb_network.name], var.networks) + monitoring = local.monitoring + depends_on = [module.postgres] +} + +output "service_definition" { + description = "General service definition with optional ingress configuration" + value = { + name = local.container_name + primary_port = local.nocodb_internal_port + endpoint = "http://${local.container_name}:${local.nocodb_internal_port}" + subdomains = ["db"] + publish_via = "tunnel" + } +} diff --git a/services/main.tf b/services/main.tf index caad2a3..2aa4620 100644 --- a/services/main.tf +++ b/services/main.tf @@ -53,6 +53,12 @@ module "linkwarden" { networks = [module.homelab_docker_network.name] } +module "nocodb" { + source = "${local.module_dir}/20-services-apps/nocodb" + volume_path = "${local.volume_host}/nocodb" + networks = [module.homelab_docker_network.name] +} + module "ntfy" { source = "${local.module_dir}/20-services-apps/ntfy" volume_path = "${local.volume_host}/ntfy" diff --git a/services/outputs.tf b/services/outputs.tf index 4187415..25ff714 100644 --- a/services/outputs.tf +++ b/services/outputs.tf @@ -10,6 +10,7 @@ output "service_definitions" { module.emulatorjs.service_definition, module.glance.service_definition, module.linkwarden.service_definition, + module.nocodb.service_definition, module.ntfy.service_definition, module.pterodactyl_wings.service_definition, module.pterodactyl_panel.service_definition,