From ca1980c45e575ff56227c71407bfd3e68839885f Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 2 Sep 2026 21:34:26 +0200 Subject: [PATCH 1/2] feat: added terraform deployment configuration for docker providier --- terraform/docker/aquila.tf | 34 ++++ terraform/docker/config_generator.tf | 21 +++ terraform/docker/gateway.tf | 29 ++++ terraform/docker/main.tf | 14 ++ terraform/docker/nats.tf | 16 ++ terraform/docker/network.tf | 15 ++ terraform/docker/nginx.tf | 66 +++++++ terraform/docker/postgres.tf | 32 ++++ terraform/docker/sagittarius.tf | 132 ++++++++++++++ terraform/docker/sculptor.tf | 38 +++++ terraform/docker/secret.tf | 44 +++++ terraform/docker/taurus.tf | 29 ++++ terraform/docker/variables.tf | 246 +++++++++++++++++++++++++++ terraform/docker/velorum.tf | 42 +++++ 14 files changed, 758 insertions(+) create mode 100644 terraform/docker/aquila.tf create mode 100644 terraform/docker/config_generator.tf create mode 100644 terraform/docker/gateway.tf create mode 100644 terraform/docker/main.tf create mode 100644 terraform/docker/nats.tf create mode 100644 terraform/docker/network.tf create mode 100644 terraform/docker/nginx.tf create mode 100644 terraform/docker/postgres.tf create mode 100644 terraform/docker/sagittarius.tf create mode 100644 terraform/docker/sculptor.tf create mode 100644 terraform/docker/secret.tf create mode 100644 terraform/docker/taurus.tf create mode 100644 terraform/docker/variables.tf create mode 100644 terraform/docker/velorum.tf diff --git a/terraform/docker/aquila.tf b/terraform/docker/aquila.tf new file mode 100644 index 0000000..d6687b7 --- /dev/null +++ b/terraform/docker/aquila.tf @@ -0,0 +1,34 @@ +resource "docker_image" "aquila" { + name = "${var.image_registry}/aquila:${var.image_tag}" +} + +resource "docker_container" "aquila" { + name = "${var.project_name}-aquila" + image = docker_image.aquila.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.nats, + ] + + networks_advanced { + name = docker_network.default.name + } + + networks_advanced { + name = docker_network.aquila.name + } + + env = [ + "AQUILA_CONFIG_PATH=/tmp/generated-configs/aquila.aquila.yml", + "AQUILA_SERVICE_CONFIG_PATH=/tmp/generated-configs/aquila.service.configuration.json", + ] + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + restart = "unless-stopped" +} diff --git a/terraform/docker/config_generator.tf b/terraform/docker/config_generator.tf new file mode 100644 index 0000000..f2d6c1f --- /dev/null +++ b/terraform/docker/config_generator.tf @@ -0,0 +1,21 @@ +resource "docker_image" "config_generator" { + name = "${var.image_registry}/config-generator:${var.image_tag}" +} + +resource "docker_container" "config_generator" { + name = "${var.project_name}-config-generator" + image = docker_image.config_generator.image_id + + networks_advanced { + name = docker_network.default.name + } + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/generated-configs" + } + + env = local.config_generator_env + + restart = "no" +} diff --git a/terraform/docker/gateway.tf b/terraform/docker/gateway.tf new file mode 100644 index 0000000..fe205b4 --- /dev/null +++ b/terraform/docker/gateway.tf @@ -0,0 +1,29 @@ +resource "docker_image" "sagittarius_gateway" { + name = "${var.image_registry}/sagittarius-gateway:${var.image_tag}" +} + +resource "docker_container" "sagittarius_gateway" { + name = "${var.project_name}-sagittarius-gateway" + image = docker_image.sagittarius_gateway.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.sagittarius_grpc, + ] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "GATEWAY_CONFIG_PATH=/tmp/generated-configs/sagittarius-gateway.gateway.yml", + ] + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + restart = "unless-stopped" +} diff --git a/terraform/docker/main.tf b/terraform/docker/main.tf new file mode 100644 index 0000000..2074d71 --- /dev/null +++ b/terraform/docker/main.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.5.0" + + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "~> 4.2.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.6" + } + } +} diff --git a/terraform/docker/nats.tf b/terraform/docker/nats.tf new file mode 100644 index 0000000..2ed5638 --- /dev/null +++ b/terraform/docker/nats.tf @@ -0,0 +1,16 @@ +resource "docker_image" "nats" { + name = "nats:2.14.4" +} + +resource "docker_container" "nats" { + name = "${var.project_name}-nats" + image = docker_image.nats.image_id + command = ["-js"] + + networks_advanced { + name = docker_network.default.name + } + + restart = "unless-stopped" +} + diff --git a/terraform/docker/network.tf b/terraform/docker/network.tf new file mode 100644 index 0000000..69519bb --- /dev/null +++ b/terraform/docker/network.tf @@ -0,0 +1,15 @@ +resource "docker_network" "default" { + name = "${var.project_name}-default" +} + +resource "docker_network" "aquila" { + name = "${var.project_name}-aquila" +} + +resource "docker_volume" "generated_configs" { + name = "${var.project_name}-generated-configs" +} + +resource "docker_volume" "postgres_data" { + name = "${var.project_name}-postgres-data" +} diff --git a/terraform/docker/nginx.tf b/terraform/docker/nginx.tf new file mode 100644 index 0000000..04a5563 --- /dev/null +++ b/terraform/docker/nginx.tf @@ -0,0 +1,66 @@ +resource "docker_image" "nginx" { + name = "nginx:1.31.3-alpine-otel" +} + +resource "docker_container" "nginx" { + name = "${var.project_name}-nginx" + image = docker_image.nginx.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.sagittarius_rails_web, + docker_container.sagittarius_rails_cable, + docker_container.sagittarius_gateway, + docker_container.sculptor, + ] + + networks_advanced { + name = docker_network.default.name + } + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + dynamic "upload" { + for_each = var.tls_key != null ? [var.tls_key] : [] + content { + file = "/etc/nginx/certs/tls.key" + content = upload.value + } + } + dynamic "upload" { + for_each = var.tls_cert != null ? [var.tls_cert] : [] + content { + file = "/etc/nginx/certs/tls.crt" + content = upload.value + } + } + + entrypoint = [ + "sh", "-c", + <<-EOT + cp /tmp/generated-configs/nginx.default.conf /etc/nginx/conf.d/default.conf + if [ -s /tmp/generated-configs/nginx.otel.conf ]; then + sed -i '1i load_module modules/ngx_otel_module.so;' /etc/nginx/nginx.conf + cp /tmp/generated-configs/nginx.otel.conf /etc/nginx/conf.d/otel.conf + fi + nginx -t + exec nginx -g 'daemon off;' + EOT + ] + + ports { + internal = 80 + external = var.http_port + } + + ports { + internal = 443 + external = var.https_port + } + + restart = "unless-stopped" +} diff --git a/terraform/docker/postgres.tf b/terraform/docker/postgres.tf new file mode 100644 index 0000000..d3ce068 --- /dev/null +++ b/terraform/docker/postgres.tf @@ -0,0 +1,32 @@ +resource "docker_image" "postgres" { + name = "postgres:18.3" +} + +resource "docker_container" "postgres" { + name = "${var.project_name}-postgres" + image = docker_image.postgres.image_id + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "POSTGRES_DB=${var.postgres_db}", + "POSTGRES_USER=${var.postgres_user}", + "POSTGRES_PASSWORD=${random_password.postgres_password.result}", + ] + + volumes { + volume_name = docker_volume.postgres_data.name + container_path = "/var/lib/postgresql" + } + + healthcheck { + test = ["CMD-SHELL", "pg_isready -U ${var.postgres_user} -d ${var.postgres_db}"] + interval = "10s" + timeout = "5s" + retries = 5 + } + + restart = "unless-stopped" +} diff --git a/terraform/docker/sagittarius.tf b/terraform/docker/sagittarius.tf new file mode 100644 index 0000000..27123aa --- /dev/null +++ b/terraform/docker/sagittarius.tf @@ -0,0 +1,132 @@ +resource "docker_image" "sagittarius" { + name = "${var.image_registry}/sagittarius:${var.image_tag}-${var.image_edition}" +} + +resource "docker_container" "sagittarius_rails_web" { + name = "${var.project_name}-sagittarius-rails-web" + image = docker_image.sagittarius.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.postgres, + ] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "INITIAL_ROOT_PASSWORD=${var.initial_root_password}", + "INITIAL_ROOT_MAIL=${var.initial_root_mail}", + "INITIAL_RUNTIME_TOKEN=${random_password.initial_runtime_token.result}", + "SAGITTARIUS_CONFIG_FILES=${join(",", [ + "/tmp/generated-configs/sagittarius.sagittarius.yml", + "/tmp/generated-configs/sagittarius.sagittarius-web.yml", + ])}", + ] + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + healthcheck { + test = ["CMD-SHELL", "curl --fail http://localhost:3000/health/liveness"] + interval = "10s" + timeout = "5s" + retries = 5 + } + + restart = "unless-stopped" +} + +resource "docker_container" "sagittarius_rails_background" { + name = "${var.project_name}-sagittarius-rails-background" + image = docker_image.sagittarius.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.sagittarius_rails_web, + ] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "SAGITTARIUS_CONFIG_FILES=${join(",", [ + "/tmp/generated-configs/sagittarius.sagittarius.yml", + "/tmp/generated-configs/sagittarius.sagittarius-background.yml", + ])}", + ] + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + command = ["bundle", "exec", "good_job"] + restart = "unless-stopped" +} + +resource "docker_container" "sagittarius_grpc" { + name = "${var.project_name}-sagittarius-grpc" + image = docker_image.sagittarius.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.sagittarius_rails_web, + ] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "SAGITTARIUS_CONFIG_FILES=${join(",", [ + "/tmp/generated-configs/sagittarius.sagittarius.yml", + "/tmp/generated-configs/sagittarius.sagittarius-grpc.yml", + ])}", + ] + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + command = ["bin/grpc_server"] + restart = "unless-stopped" +} + +resource "docker_container" "sagittarius_rails_cable" { + name = "${var.project_name}-sagittarius-rails-cable" + image = docker_image.sagittarius.image_id + + depends_on = [ + docker_container.config_generator, + docker_container.sagittarius_rails_web, + ] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "SAGITTARIUS_CONFIG_FILES=${join(",", [ + "/tmp/generated-configs/sagittarius.sagittarius.yml", + "/tmp/generated-configs/sagittarius.sagittarius-cable.yml", + ])}", + ] + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + command = ["bundle", "exec", "puma", "config.cable.ru"] + restart = "unless-stopped" +} diff --git a/terraform/docker/sculptor.tf b/terraform/docker/sculptor.tf new file mode 100644 index 0000000..fe2999e --- /dev/null +++ b/terraform/docker/sculptor.tf @@ -0,0 +1,38 @@ +resource "docker_image" "sculptor" { + name = "${var.image_registry}/sculptor:${var.image_tag}-${var.image_edition}" +} + +resource "docker_container" "sculptor" { + name = "${var.project_name}-sculptor" + image = docker_image.sculptor.image_id + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "OPENTELEMETRY_ENABLED=${var.opentelemetry_enabled}", + "OTEL_SERVICE_NAME=${var.otel_service_name_sculptor}", + "OTEL_LOGS_ENDPOINT=${var.otel_logs_http_endpoint}", + "OTEL_METRICS_ENDPOINT=${var.otel_metrics_http_endpoint}", + "OTEL_TRACES_ENDPOINT=${var.otel_traces_http_endpoint}", + "NEXT_PUBLIC_OTEL_SERVICE_NAME=${var.otel_service_name_sculptor_clientside}", + "NEXT_PUBLIC_OTEL_LOGS_ENDPOINT=${var.otel_logs_clientside_http_endpoint}", + "NEXT_PUBLIC_OTEL_METRICS_ENDPOINT=${var.otel_metrics_clientside_http_endpoint}", + "NEXT_PUBLIC_OTEL_TRACES_ENDPOINT=${var.otel_traces_clientside_http_endpoint}", + ] + + entrypoint = [ + "sh", "-c", + <<-EOT + if [ "$OPENTELEMETRY_ENABLED" != 'true' ]; then + echo 'UNSET OTEL' + unset OTEL_SERVICE_NAME OTEL_LOGS_ENDPOINT OTEL_METRICS_ENDPOINT OTEL_TRACES_ENDPOINT + unset NEXT_PUBLIC_OTEL_SERVICE_NAME NEXT_PUBLIC_OTEL_LOGS_ENDPOINT NEXT_PUBLIC_OTEL_METRICS_ENDPOINT NEXT_PUBLIC_OTEL_TRACES_ENDPOINT + fi + exec npm run start + EOT + ] + + restart = "unless-stopped" +} diff --git a/terraform/docker/secret.tf b/terraform/docker/secret.tf new file mode 100644 index 0000000..a63129c --- /dev/null +++ b/terraform/docker/secret.tf @@ -0,0 +1,44 @@ +resource "random_password" "initial_runtime_token" { + length = 32 + special = false +} + +resource "random_password" "taurus_aquila_token" { + length = 32 + special = false +} + +resource "random_password" "sagittarius_db_encryption_primary_key" { + length = 32 + special = false +} + +resource "random_password" "sagittarius_db_encryption_deterministic_key" { + length = 32 + special = false +} + +resource "random_password" "sagittarius_db_encryption_key_derivation_salt" { + length = 32 + special = false +} + +resource "random_password" "sagittarius_rails_secret_key_base" { + length = 32 + special = false +} + +resource "random_password" "sagittarius_gateway_jwt_secret" { + length = 32 + special = false +} + +resource "random_password" "velorum_jwt_secret" { + length = 32 + special = false +} + +resource "random_password" "postgres_password" { + length = 32 + special = false +} diff --git a/terraform/docker/taurus.tf b/terraform/docker/taurus.tf new file mode 100644 index 0000000..f1951f8 --- /dev/null +++ b/terraform/docker/taurus.tf @@ -0,0 +1,29 @@ +resource "docker_image" "taurus" { + name = "${var.image_registry}/taurus:${var.image_tag}" +} + +resource "docker_container" "taurus" { + name = "${var.project_name}-taurus" + image = docker_image.taurus.image_id + + depends_on = [ + docker_container.nats, + docker_container.aquila, + ] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "MODE=dynamic", + "AQUILA_URL=http://${docker_container.aquila.name}:8081", + "NATS_URL=nats://${docker_container.nats.name}:4222", + "AQUILA_TOKEN=${random_password.taurus_aquila_token.result}", + "AQUILA_GRPC_CONNECT_TIMEOUT_SECS=${var.aquila_grpc_connect_timeout_secs}", + "AQUILA_GRPC_REQUEST_TIMEOUT_SECS=${var.aquila_grpc_request_timeout_secs}", + "ENVIRONMENT=DEVELOPMENT" + ] + + restart = "unless-stopped" +} diff --git a/terraform/docker/variables.tf b/terraform/docker/variables.tf new file mode 100644 index 0000000..da97c38 --- /dev/null +++ b/terraform/docker/variables.tf @@ -0,0 +1,246 @@ +variable "project_name" { + description = "Prefix used for container, network and volume names (mirrors the compose 'name:' key)." + type = string + default = "codezero" +} + +variable "image_registry" { + description = "Registry host that application images are pulled from." + type = string +} + +variable "image_tag" { + description = "Tag applied to sagittarius/gateway/sculptor/velorum/aquila/taurus images." + type = string +} + +variable "image_edition" { + description = "Edition suffix appended to the sagittarius/sculptor image tags (e.g. 'ce', 'ee')." + type = string +} + +variable "postgres_db" { + type = string + default = "sagittarius_production" +} + +variable "postgres_user" { + type = string + default = "sagittarius" +} + +variable "initial_root_password" { + type = string + sensitive = true +} + +variable "initial_root_mail" { + type = string +} + +variable "aquila_grpc_connect_timeout_secs" { + type = string + default = "5" +} + +variable "aquila_grpc_request_timeout_secs" { + type = string + default = "30" +} + +variable "hostname" { + type = string + default = "localhost" +} + +variable "http_port" { + type = number + default = 80 +} + +variable "https_port" { + type = number + default = 443 +} + +variable "opentelemetry_enabled" { + type = bool + default = false +} + +variable "ssl_enabled" { + type = bool + default = false +} + +variable "tls_key" { + description = "Key Value for the nginx (not the path, the real value)" + type = string + default = null +} + +variable "tls_cert" { + description = "Cert Value for the nginx (not the path, the real value)" + type = string + default = null +} + +variable "enable_velorum" { + description = "Whether to start the velorum container (compose's 'ide_velorum' profile, off by default)." + type = bool + default = false +} + +variable "few_shots_external_config_path" { + description = "Absolute host path to velorum.few_shots_external.configuration.json." + type = string + default = "{}" +} + +variable "otel_service_name_sculptor" { + type = string + default = "" +} + +variable "otel_logs_http_endpoint" { + type = string + default = "" +} + +variable "otel_metrics_http_endpoint" { + type = string + default = "" +} + +variable "otel_traces_http_endpoint" { + type = string + default = "" +} + +variable "otel_service_name_sculptor_clientside" { + type = string + default = "" +} + +variable "otel_logs_clientside_http_endpoint" { + type = string + default = "" +} + +variable "otel_metrics_clientside_http_endpoint" { + type = string + default = "" +} + +variable "otel_traces_clientside_http_endpoint" { + type = string + default = "" +} + +variable "config_generator_env" { + description = <<-EOT + Full replacement for compose's `env_file: .env` on the config-generator + container. List every KEY=value pair it needs to render the generated + configs (sagittarius.*.yml, aquila.*.yml, nginx.*.conf, etc). + EOT + type = list(string) + sensitive = true + default = [] +} + +locals { + default_config_generator_env = [ + "HOSTNAME=${var.hostname}", + "HTTP_PORT=${var.http_port}", + "HTTPS_PORT=${var.https_port}", + "SSL_ENABLED=${var.ssl_enabled}", + "SSL_CERT_FILE=", + "SSL_KEY_FILE=", + + "INITIAL_ROOT_PASSWORD=${var.initial_root_password}", + "INITIAL_ROOT_MAIL=${var.initial_root_mail}", + "INITIAL_RUNTIME_TOKEN=${random_password.initial_runtime_token.result}", + + "AQUILA_LOG_LEVEL=info", + "AQUILA_NATS_URL=nats://${var.project_name}-nats:4222", + "AQUILA_NATS_BUCKET=flow_store", + "AQUILA_BACKEND_URL=http://${var.project_name}-nginx:80", + "AQUILA_BACKEND_TOKEN=${random_password.initial_runtime_token.result}", + "AQUILA_BACKEND_UNARY_TIMEOUT_SECS=10", + "AQUILA_GRPC_HOST=0.0.0.0", + "AQUILA_GRPC_PORT=8081", + "AQUILA_GRPC_HEALTH_SERVICE=false", + + "TAURUS_AQUILA_TOKEN=${random_password.taurus_aquila_token.result}", + + "AQUILA_GRPC_CONNECT_TIMEOUT_SECS=${var.aquila_grpc_connect_timeout_secs}", + "AQUILA_GRPC_REQUEST_TIMEOUT_SECS=${var.aquila_grpc_request_timeout_secs}", + + "VELORUM_ENABLED=${var.enable_velorum}", + + "IMAGE_REGISTRY=${var.image_registry}", + "IMAGE_TAG=${var.image_tag}", + "IMAGE_EDITION=${var.image_edition}", + + "SAGITTARIUS_DB_ENCRYPTION_PRIMARY_KEY=${random_password.sagittarius_db_encryption_primary_key.result}", + "SAGITTARIUS_DB_ENCRYPTION_DETERMINISTIC_KEY=${random_password.sagittarius_db_encryption_deterministic_key.result}", + "SAGITTARIUS_DB_ENCRYPTION_KEY_DERIVATION_SALT=${random_password.sagittarius_db_encryption_key_derivation_salt.result}", + "SAGITTARIUS_RAILS_SECRET_KEY_BASE=${random_password.sagittarius_rails_secret_key_base.result}", + + "SAGITTARIUS_GATEWAY_LOG_LEVEL=info", + "SAGITTARIUS_GATEWAY_JWT_SECRET=${random_password.sagittarius_gateway_jwt_secret.result}", + "SAGITTARIUS_GATEWAY_JWT_TTL_SECONDS=300", + + "VELORUM_HOST=${var.project_name}-velorum", + "VELORUM_PORT=50051", + "VELORUM_JWT_SECRET=${random_password.velorum_jwt_secret.result}", + + "OPENTELEMETRY_ENABLED=${var.opentelemetry_enabled}", + "OPENTELEMETRY_GRPC_HOST=http://localhost:4317", + "OPENTELEMETRY_LOGS_HTTP_ENDPOINT=${var.otel_logs_http_endpoint}", + "OPENTELEMETRY_METRICS_HTTP_ENDPOINT=${var.otel_metrics_http_endpoint}", + "OPENTELEMETRY_TRACES_HTTP_ENDPOINT=${var.otel_traces_http_endpoint}", + "OPENTELEMETRY_LOGS_CLIENTSIDE_HTTP_ENDPOINT=${var.otel_logs_clientside_http_endpoint}", + "OPENTELEMETRY_METRICS_CLIENTSIDE_HTTP_ENDPOINT=${var.otel_metrics_clientside_http_endpoint}", + "OPENTELEMETRY_TRACES_CLIENTSIDE_HTTP_ENDPOINT=${var.otel_traces_clientside_http_endpoint}", + + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_WEB=sagittarius-web", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_CABLE=sagittarius-cable", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_GRPC=sagittarius-grpc", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_BACKGROUND=sagittarius-background", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_GATEWAY=sagittarius-gateway", + "OPENTELEMETRY_SERVICE_NAME_NGINX=nginx", + "OPENTELEMETRY_SERVICE_NAME_SCULPTOR=${var.otel_service_name_sculptor}", + "OPENTELEMETRY_SERVICE_NAME_SCULPTOR_CLIENTSIDE=${var.otel_service_name_sculptor_clientside}", + + "SAGITTARIUS_RAILS_HOST=${var.project_name}-sagittarius-rails-web", + "SAGITTARIUS_RAILS_PORT=3000", + "SAGITTARIUS_CABLE_HOST=${var.project_name}-sagittarius-rails-cable", + "SAGITTARIUS_CABLE_PORT=3000", + "SAGITTARIUS_GRPC_HOST=${var.project_name}-sagittarius-grpc", + "SAGITTARIUS_GRPC_PORT=50051", + "SAGITTARIUS_GATEWAY_HOST=${var.project_name}-sagittarius-gateway", + "SAGITTARIUS_GATEWAY_PORT=50051", + "SAGITTARIUS_LOG_LEVEL=info", + "SAGITTARIUS_RAILS_WEB_THREADS=3", + "SAGITTARIUS_RAILS_GRPC_THREADS=6", + "SAGITTARIUS_DB_POOL_SIZE=8", + + "SCULPTOR_HOST=${var.project_name}-sculptor", + "SCULPTOR_PORT=3000", + + "POSTGRES_HOST=${var.project_name}-postgres", + "POSTGRES_PORT=5432", + "POSTGRES_DB=${var.postgres_db}", + "POSTGRES_USER=${var.postgres_user}", + "POSTGRES_PASSWORD=${random_password.postgres_password.result}", + ] + + default_keys = [for line in local.default_config_generator_env : split("=", line)[0]] + override_keys = [for line in var.config_generator_env : split("=", line)[0]] + default_unset = [ + for i, line in local.default_config_generator_env : + line if !contains(local.override_keys, local.default_keys[i]) + ] + config_generator_env = concat(local.default_unset, var.config_generator_env) +} diff --git a/terraform/docker/velorum.tf b/terraform/docker/velorum.tf new file mode 100644 index 0000000..1b06c89 --- /dev/null +++ b/terraform/docker/velorum.tf @@ -0,0 +1,42 @@ +resource "docker_image" "velorum" { + count = var.enable_velorum ? 1 : 0 + name = "${var.image_registry}/velorum:${var.image_tag}-${var.image_edition}" +} + +resource "docker_container" "velorum" { + count = var.enable_velorum ? 1 : 0 + + name = "${var.project_name}-velorum" + image = docker_image.velorum[0].image_id + + depends_on = [docker_container.config_generator] + + networks_advanced { + name = docker_network.default.name + } + + env = [ + "SECURITY_TOKEN=${random_password.velorum_jwt_secret.result}", + ] + + upload { + file = "/velorum/few_shots_external.configuration.json" + content = var.few_shots_external_config_path + } + + volumes { + volume_name = docker_volume.generated_configs.name + container_path = "/tmp/generated-configs" + read_only = true + } + + entrypoint = [ + "sh", "-c", + <<-EOT + cp /tmp/generated-configs/velorum.models.configuration.json models.configuration.json + exec uv run main.py + EOT + ] + + restart = "unless-stopped" +} From 161d4aba28edbbfd795a7135a004bc43ea59432b Mon Sep 17 00:00:00 2001 From: Niklas van Schrick Date: Sat, 5 Sep 2026 18:13:47 +0200 Subject: [PATCH 2/2] Improve configurability of terraform module and use registry image datasources --- terraform/docker/aquila.tf | 15 +- terraform/docker/config_generator.tf | 10 +- terraform/docker/gateway.tf | 13 +- terraform/docker/main.tf | 20 ++- terraform/docker/nats.tf | 12 +- terraform/docker/network.tf | 15 -- terraform/docker/nginx.tf | 48 +++++-- terraform/docker/postgres.tf | 15 +- terraform/docker/sagittarius.tf | 25 +++- terraform/docker/sculptor.tf | 15 +- terraform/docker/taurus.tf | 17 ++- terraform/docker/variables.tf | 204 +++++++++++++++++++++++---- terraform/docker/velorum.tf | 16 ++- 13 files changed, 340 insertions(+), 85 deletions(-) delete mode 100644 terraform/docker/network.tf diff --git a/terraform/docker/aquila.tf b/terraform/docker/aquila.tf index d6687b7..84fc36d 100644 --- a/terraform/docker/aquila.tf +++ b/terraform/docker/aquila.tf @@ -1,10 +1,19 @@ +data "docker_registry_image" "aquila" { + count = local.runtime_enabled ? 1 : 0 + name = "${var.image_registry}/aquila:${var.image_tag}" +} + resource "docker_image" "aquila" { - name = "${var.image_registry}/aquila:${var.image_tag}" + count = local.runtime_enabled ? 1 : 0 + name = data.docker_registry_image.aquila[0].name + pull_triggers = [data.docker_registry_image.aquila[0].sha256_digest] } resource "docker_container" "aquila" { + count = local.runtime_enabled ? 1 : 0 + name = "${var.project_name}-aquila" - image = docker_image.aquila.image_id + image = docker_image.aquila[0].image_id depends_on = [ docker_container.config_generator, @@ -16,7 +25,7 @@ resource "docker_container" "aquila" { } networks_advanced { - name = docker_network.aquila.name + name = docker_network.aquila[0].name } env = [ diff --git a/terraform/docker/config_generator.tf b/terraform/docker/config_generator.tf index f2d6c1f..a482de5 100644 --- a/terraform/docker/config_generator.tf +++ b/terraform/docker/config_generator.tf @@ -1,7 +1,12 @@ -resource "docker_image" "config_generator" { +data "docker_registry_image" "config_generator" { name = "${var.image_registry}/config-generator:${var.image_tag}" } +resource "docker_image" "config_generator" { + name = data.docker_registry_image.config_generator.name + pull_triggers = [data.docker_registry_image.config_generator.sha256_digest] +} + resource "docker_container" "config_generator" { name = "${var.project_name}-config-generator" image = docker_image.config_generator.image_id @@ -17,5 +22,6 @@ resource "docker_container" "config_generator" { env = local.config_generator_env - restart = "no" + restart = "no" + must_run = false } diff --git a/terraform/docker/gateway.tf b/terraform/docker/gateway.tf index fe205b4..0b36d10 100644 --- a/terraform/docker/gateway.tf +++ b/terraform/docker/gateway.tf @@ -1,10 +1,19 @@ +data "docker_registry_image" "sagittarius_gateway" { + count = local.ide_enabled ? 1 : 0 + name = "${var.image_registry}/sagittarius-gateway:${var.image_tag}" +} + resource "docker_image" "sagittarius_gateway" { - name = "${var.image_registry}/sagittarius-gateway:${var.image_tag}" + count = local.ide_enabled ? 1 : 0 + name = data.docker_registry_image.sagittarius_gateway[0].name + pull_triggers = [data.docker_registry_image.sagittarius_gateway[0].sha256_digest] } resource "docker_container" "sagittarius_gateway" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-sagittarius-gateway" - image = docker_image.sagittarius_gateway.image_id + image = docker_image.sagittarius_gateway[0].image_id depends_on = [ docker_container.config_generator, diff --git a/terraform/docker/main.tf b/terraform/docker/main.tf index 2074d71..8f0fad1 100644 --- a/terraform/docker/main.tf +++ b/terraform/docker/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { docker = { source = "kreuzwerker/docker" - version = "~> 4.2.0" + version = "~> 4.2" } random = { source = "hashicorp/random" @@ -12,3 +12,21 @@ terraform { } } } + +resource "docker_network" "default" { + name = "${var.project_name}-default" +} + +resource "docker_network" "aquila" { + count = local.runtime_enabled ? 1 : 0 + name = "${var.project_name}-aquila" +} + +resource "docker_volume" "generated_configs" { + name = "${var.project_name}-generated-configs" +} + +resource "docker_volume" "postgres_data" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-postgres-data" +} diff --git a/terraform/docker/nats.tf b/terraform/docker/nats.tf index 2ed5638..00ac45a 100644 --- a/terraform/docker/nats.tf +++ b/terraform/docker/nats.tf @@ -1,10 +1,18 @@ +data "docker_registry_image" "nats" { + count = local.runtime_enabled ? 1 : 0 + name = "nats:2.14.4" +} + resource "docker_image" "nats" { - name = "nats:2.14.4" + count = local.runtime_enabled ? 1 : 0 + name = data.docker_registry_image.nats[0].name + pull_triggers = [data.docker_registry_image.nats[0].sha256_digest] } resource "docker_container" "nats" { + count = local.runtime_enabled ? 1 : 0 name = "${var.project_name}-nats" - image = docker_image.nats.image_id + image = docker_image.nats[0].image_id command = ["-js"] networks_advanced { diff --git a/terraform/docker/network.tf b/terraform/docker/network.tf deleted file mode 100644 index 69519bb..0000000 --- a/terraform/docker/network.tf +++ /dev/null @@ -1,15 +0,0 @@ -resource "docker_network" "default" { - name = "${var.project_name}-default" -} - -resource "docker_network" "aquila" { - name = "${var.project_name}-aquila" -} - -resource "docker_volume" "generated_configs" { - name = "${var.project_name}-generated-configs" -} - -resource "docker_volume" "postgres_data" { - name = "${var.project_name}-postgres-data" -} diff --git a/terraform/docker/nginx.tf b/terraform/docker/nginx.tf index 04a5563..75a06c3 100644 --- a/terraform/docker/nginx.tf +++ b/terraform/docker/nginx.tf @@ -1,10 +1,21 @@ +data "docker_registry_image" "nginx" { + count = local.ide_enabled ? 1 : 0 + name = "nginx:1.31.3-alpine-otel" +} + resource "docker_image" "nginx" { - name = "nginx:1.31.3-alpine-otel" + count = local.ide_enabled ? 1 : 0 + name = data.docker_registry_image.nginx[0].name + pull_triggers = [data.docker_registry_image.nginx[0].sha256_digest] } resource "docker_container" "nginx" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-nginx" - image = docker_image.nginx.image_id + image = docker_image.nginx[0].image_id + + env = var.nginx_env depends_on = [ docker_container.config_generator, @@ -18,23 +29,30 @@ resource "docker_container" "nginx" { name = docker_network.default.name } + dynamic "networks_advanced" { + for_each = var.nginx_additional_network != null ? [var.nginx_additional_network] : [] + content { + name = networks_advanced.value + } + } + volumes { volume_name = docker_volume.generated_configs.name container_path = "/tmp/generated-configs" read_only = true } - + dynamic "upload" { for_each = var.tls_key != null ? [var.tls_key] : [] content { - file = "/etc/nginx/certs/tls.key" + file = "/etc/nginx/certs/tls.key" content = upload.value } } dynamic "upload" { for_each = var.tls_cert != null ? [var.tls_cert] : [] content { - file = "/etc/nginx/certs/tls.crt" + file = "/etc/nginx/certs/tls.crt" content = upload.value } } @@ -52,14 +70,22 @@ resource "docker_container" "nginx" { EOT ] - ports { - internal = 80 - external = var.http_port + dynamic "ports" { + for_each = var.http_port != null ? [var.http_port] : [] + content { + internal = 80 + external = ports.value + ip = var.nginx_bind_ip + } } - ports { - internal = 443 - external = var.https_port + dynamic "ports" { + for_each = var.https_port != null ? [var.https_port] : [] + content { + internal = 443 + external = ports.value + ip = var.nginx_bind_ip + } } restart = "unless-stopped" diff --git a/terraform/docker/postgres.tf b/terraform/docker/postgres.tf index d3ce068..68218fa 100644 --- a/terraform/docker/postgres.tf +++ b/terraform/docker/postgres.tf @@ -1,10 +1,19 @@ +data "docker_registry_image" "postgres" { + count = local.ide_enabled ? 1 : 0 + name = "postgres:18.3" +} + resource "docker_image" "postgres" { - name = "postgres:18.3" + count = local.ide_enabled ? 1 : 0 + name = data.docker_registry_image.postgres[0].name + pull_triggers = [data.docker_registry_image.postgres[0].sha256_digest] } resource "docker_container" "postgres" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-postgres" - image = docker_image.postgres.image_id + image = docker_image.postgres[0].image_id networks_advanced { name = docker_network.default.name @@ -17,7 +26,7 @@ resource "docker_container" "postgres" { ] volumes { - volume_name = docker_volume.postgres_data.name + volume_name = docker_volume.postgres_data[0].name container_path = "/var/lib/postgresql" } diff --git a/terraform/docker/sagittarius.tf b/terraform/docker/sagittarius.tf index 27123aa..032c6c3 100644 --- a/terraform/docker/sagittarius.tf +++ b/terraform/docker/sagittarius.tf @@ -1,10 +1,19 @@ +data "docker_registry_image" "sagittarius" { + count = local.ide_enabled ? 1 : 0 + name = "${var.image_registry}/sagittarius:${var.image_tag}-${var.image_edition}" +} + resource "docker_image" "sagittarius" { - name = "${var.image_registry}/sagittarius:${var.image_tag}-${var.image_edition}" + count = local.ide_enabled ? 1 : 0 + name = data.docker_registry_image.sagittarius[0].name + pull_triggers = [data.docker_registry_image.sagittarius[0].sha256_digest] } resource "docker_container" "sagittarius_rails_web" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-sagittarius-rails-web" - image = docker_image.sagittarius.image_id + image = docker_image.sagittarius[0].image_id depends_on = [ docker_container.config_generator, @@ -42,8 +51,10 @@ resource "docker_container" "sagittarius_rails_web" { } resource "docker_container" "sagittarius_rails_background" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-sagittarius-rails-background" - image = docker_image.sagittarius.image_id + image = docker_image.sagittarius[0].image_id depends_on = [ docker_container.config_generator, @@ -72,8 +83,10 @@ resource "docker_container" "sagittarius_rails_background" { } resource "docker_container" "sagittarius_grpc" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-sagittarius-grpc" - image = docker_image.sagittarius.image_id + image = docker_image.sagittarius[0].image_id depends_on = [ docker_container.config_generator, @@ -102,8 +115,10 @@ resource "docker_container" "sagittarius_grpc" { } resource "docker_container" "sagittarius_rails_cable" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-sagittarius-rails-cable" - image = docker_image.sagittarius.image_id + image = docker_image.sagittarius[0].image_id depends_on = [ docker_container.config_generator, diff --git a/terraform/docker/sculptor.tf b/terraform/docker/sculptor.tf index fe2999e..f6f5a9b 100644 --- a/terraform/docker/sculptor.tf +++ b/terraform/docker/sculptor.tf @@ -1,10 +1,19 @@ +data "docker_registry_image" "sculptor" { + count = local.ide_enabled ? 1 : 0 + name = "${var.image_registry}/sculptor:${var.image_tag}-${var.image_edition}" +} + resource "docker_image" "sculptor" { - name = "${var.image_registry}/sculptor:${var.image_tag}-${var.image_edition}" + count = local.ide_enabled ? 1 : 0 + name = data.docker_registry_image.sculptor[0].name + pull_triggers = [data.docker_registry_image.sculptor[0].sha256_digest] } resource "docker_container" "sculptor" { + count = local.ide_enabled ? 1 : 0 + name = "${var.project_name}-sculptor" - image = docker_image.sculptor.image_id + image = docker_image.sculptor[0].image_id networks_advanced { name = docker_network.default.name @@ -22,7 +31,7 @@ resource "docker_container" "sculptor" { "NEXT_PUBLIC_OTEL_TRACES_ENDPOINT=${var.otel_traces_clientside_http_endpoint}", ] - entrypoint = [ + entrypoint = [ "sh", "-c", <<-EOT if [ "$OPENTELEMETRY_ENABLED" != 'true' ]; then diff --git a/terraform/docker/taurus.tf b/terraform/docker/taurus.tf index f1951f8..79e2415 100644 --- a/terraform/docker/taurus.tf +++ b/terraform/docker/taurus.tf @@ -1,10 +1,19 @@ +data "docker_registry_image" "taurus" { + count = local.runtime_enabled ? 1 : 0 + name = "${var.image_registry}/taurus:${var.image_tag}" +} + resource "docker_image" "taurus" { - name = "${var.image_registry}/taurus:${var.image_tag}" + count = local.runtime_enabled ? 1 : 0 + name = data.docker_registry_image.taurus[0].name + pull_triggers = [data.docker_registry_image.taurus[0].sha256_digest] } resource "docker_container" "taurus" { + count = local.runtime_enabled ? 1 : 0 + name = "${var.project_name}-taurus" - image = docker_image.taurus.image_id + image = docker_image.taurus[0].image_id depends_on = [ docker_container.nats, @@ -17,8 +26,8 @@ resource "docker_container" "taurus" { env = [ "MODE=dynamic", - "AQUILA_URL=http://${docker_container.aquila.name}:8081", - "NATS_URL=nats://${docker_container.nats.name}:4222", + "AQUILA_URL=http://${docker_container.aquila[0].name}:8081", + "NATS_URL=nats://${docker_container.nats[0].name}:4222", "AQUILA_TOKEN=${random_password.taurus_aquila_token.result}", "AQUILA_GRPC_CONNECT_TIMEOUT_SECS=${var.aquila_grpc_connect_timeout_secs}", "AQUILA_GRPC_REQUEST_TIMEOUT_SECS=${var.aquila_grpc_request_timeout_secs}", diff --git a/terraform/docker/variables.tf b/terraform/docker/variables.tf index da97c38..8512260 100644 --- a/terraform/docker/variables.tf +++ b/terraform/docker/variables.tf @@ -7,6 +7,7 @@ variable "project_name" { variable "image_registry" { description = "Registry host that application images are pulled from." type = string + default = "registry.gitlab.com/code0-tech/packages" } variable "image_tag" { @@ -49,18 +50,54 @@ variable "aquila_grpc_request_timeout_secs" { } variable "hostname" { - type = string - default = "localhost" + type = string + default = "localhost" } variable "http_port" { - type = number - default = 80 + description = "Host port mapped to nginx's internal port 80. Set to null to not publish HTTP." + type = number + default = 80 } variable "https_port" { - type = number - default = 443 + description = "Host port mapped to nginx's internal port 443. Set to null to not publish HTTPS." + type = number + default = 443 +} + +variable "nginx_bind_ip" { + description = <<-EOT + Host IP address to bind the published nginx ports to. Defaults to null, + which binds on all interfaces (0.0.0.0). Set to "127.0.0.1" to expose the + ports on localhost only (e.g. when running behind an external reverse + proxy). + EOT + type = string + default = null +} + +variable "nginx_env" { + description = <<-EOT + Additional environment variables to set on the nginx container, as a list of + "KEY=value" strings. Useful when running behind a reverse proxy such as + nginx-proxy (e.g. ["VIRTUAL_HOST=example.com", "VIRTUAL_PORT=80"]). + Empty by default. + EOT + type = list(string) + default = [] +} + +variable "nginx_additional_network" { + description = <<-EOT + Name of an optional additional (externally managed) Docker network to + attach the nginx container to, in addition to the module's default network. + Useful for joining a reverse-proxy network such as nginx-proxy. The network + must already exist; it is not created by this module. Defaults to null (no + additional network). + EOT + type = string + default = null } variable "opentelemetry_enabled" { @@ -85,10 +122,26 @@ variable "tls_cert" { default = null } -variable "enable_velorum" { - description = "Whether to start the velorum container (compose's 'ide_velorum' profile, off by default)." - type = bool - default = false +variable "enabled_profiles" { + description = <<-EOT + Which service profiles to start. Valid values: + - "ide": sculptor, sagittarius (web/background/grpc/cable/gateway), postgres, nginx + - "runtime": aquila, taurus, nats + - "ide_velorum": velorum (requires "ide") + Defaults to ["ide", "runtime"] (previous behaviour with velorum off). + EOT + type = list(string) + default = ["ide", "runtime"] + + validation { + condition = length(setsubtract(toset(var.enabled_profiles), toset(["ide", "runtime", "ide_velorum"]))) == 0 + error_message = "enabled_profiles may only contain: \"ide\", \"runtime\", \"ide_velorum\"." + } + + validation { + condition = !contains(var.enabled_profiles, "ide_velorum") || contains(var.enabled_profiles, "ide") + error_message = "Profile \"ide_velorum\" requires \"ide\" to also be enabled." + } } variable "few_shots_external_config_path" { @@ -99,7 +152,42 @@ variable "few_shots_external_config_path" { variable "otel_service_name_sculptor" { type = string - default = "" + default = "sculptor" +} + +variable "otel_service_name_sagittarius_web" { + type = string + default = "sagittarius-web" +} + +variable "otel_service_name_sagittarius_cable" { + type = string + default = "sagittarius-cable" +} + +variable "otel_service_name_sagittarius_grpc" { + type = string + default = "sagittarius-grpc" +} + +variable "otel_service_name_sagittarius_background" { + type = string + default = "sagittarius-background" +} + +variable "otel_service_name_sagittarius_gateway" { + type = string + default = "sagittarius-gateway" +} + +variable "otel_service_name_nginx" { + type = string + default = "nginx" +} + +variable "otel_service_name_aquila" { + type = string + default = "aquila" } variable "otel_logs_http_endpoint" { @@ -119,7 +207,7 @@ variable "otel_traces_http_endpoint" { variable "otel_service_name_sculptor_clientside" { type = string - default = "" + default = "sculptor-clientside" } variable "otel_logs_clientside_http_endpoint" { @@ -138,24 +226,55 @@ variable "otel_traces_clientside_http_endpoint" { } variable "config_generator_env" { - description = <<-EOT - Full replacement for compose's `env_file: .env` on the config-generator - container. List every KEY=value pair it needs to render the generated - configs (sagittarius.*.yml, aquila.*.yml, nginx.*.conf, etc). - EOT + description = "Overrides of predefined config generator variables" type = list(string) sensitive = true default = [] } +variable "aquila_actions" { + description = <<-EOT + Aquila actions to register, keyed by a short name (letters/digits, no + underscores). Each entry is rendered by the config-generator into + aquila.service.configuration.json via AQUILA_ACTION__* env vars. + EOT + type = map(object({ + identifier = string + token = string + })) + default = {} +} + +variable "velorum_models" { + description = <<-EOT + Velorum models to register, keyed by a short name (letters/digits, no + underscores). Each entry is rendered by the config-generator into + velorum.models.configuration.json via VELORUM_MODEL__* env vars. + EOT + type = map(object({ + identifier = string + name = string + capabilities = list(string) + provider = string + api = string + auth = string + token_cost = number + })) + default = {} +} + locals { + ide_enabled = contains(var.enabled_profiles, "ide") + runtime_enabled = contains(var.enabled_profiles, "runtime") + velorum_enabled = contains(var.enabled_profiles, "ide_velorum") + default_config_generator_env = [ "HOSTNAME=${var.hostname}", - "HTTP_PORT=${var.http_port}", - "HTTPS_PORT=${var.https_port}", + "HTTP_PORT=${coalesce(var.http_port, 80)}", + "HTTPS_PORT=${coalesce(var.https_port, 443)}", "SSL_ENABLED=${var.ssl_enabled}", - "SSL_CERT_FILE=", - "SSL_KEY_FILE=", + "SSL_CERT_FILE=/etc/nginx/certs/tls.crt", + "SSL_KEY_FILE=/etc/nginx/certs/tls.key", "INITIAL_ROOT_PASSWORD=${var.initial_root_password}", "INITIAL_ROOT_MAIL=${var.initial_root_mail}", @@ -176,7 +295,7 @@ locals { "AQUILA_GRPC_CONNECT_TIMEOUT_SECS=${var.aquila_grpc_connect_timeout_secs}", "AQUILA_GRPC_REQUEST_TIMEOUT_SECS=${var.aquila_grpc_request_timeout_secs}", - "VELORUM_ENABLED=${var.enable_velorum}", + "VELORUM_ENABLED=${local.velorum_enabled}", "IMAGE_REGISTRY=${var.image_registry}", "IMAGE_TAG=${var.image_tag}", @@ -204,12 +323,13 @@ locals { "OPENTELEMETRY_METRICS_CLIENTSIDE_HTTP_ENDPOINT=${var.otel_metrics_clientside_http_endpoint}", "OPENTELEMETRY_TRACES_CLIENTSIDE_HTTP_ENDPOINT=${var.otel_traces_clientside_http_endpoint}", - "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_WEB=sagittarius-web", - "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_CABLE=sagittarius-cable", - "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_GRPC=sagittarius-grpc", - "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_BACKGROUND=sagittarius-background", - "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_GATEWAY=sagittarius-gateway", - "OPENTELEMETRY_SERVICE_NAME_NGINX=nginx", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_WEB=${var.otel_service_name_sagittarius_web}", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_CABLE=${var.otel_service_name_sagittarius_cable}", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_GRPC=${var.otel_service_name_sagittarius_grpc}", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_BACKGROUND=${var.otel_service_name_sagittarius_background}", + "OPENTELEMETRY_SERVICE_NAME_SAGITTARIUS_GATEWAY=${var.otel_service_name_sagittarius_gateway}", + "OPENTELEMETRY_SERVICE_NAME_NGINX=${var.otel_service_name_nginx}", + "OPENTELEMETRY_SERVICE_NAME_AQUILA=${var.otel_service_name_aquila}", "OPENTELEMETRY_SERVICE_NAME_SCULPTOR=${var.otel_service_name_sculptor}", "OPENTELEMETRY_SERVICE_NAME_SCULPTOR_CLIENTSIDE=${var.otel_service_name_sculptor_clientside}", @@ -236,11 +356,37 @@ locals { "POSTGRES_PASSWORD=${random_password.postgres_password.result}", ] + # Flatten aquila_actions into AQUILA_ACTION__* env lines. + aquila_action_env = flatten([ + for k, a in var.aquila_actions : [ + "AQUILA_ACTION_${upper(k)}_IDENTIFIER=${a.identifier}", + "AQUILA_ACTION_${upper(k)}_TOKEN=${a.token}", + ] + ]) + + # Flatten velorum_models into VELORUM_MODEL__* env lines. + velorum_model_env = flatten([ + for k, m in var.velorum_models : [ + "VELORUM_MODEL_${upper(k)}_IDENTIFIER=${m.identifier}", + "VELORUM_MODEL_${upper(k)}_NAME=${m.name}", + "VELORUM_MODEL_${upper(k)}_CAPABILITIES=${join(",", m.capabilities)}", + "VELORUM_MODEL_${upper(k)}_PROVIDER=${m.provider}", + "VELORUM_MODEL_${upper(k)}_API=${m.api}", + "VELORUM_MODEL_${upper(k)}_AUTH=${m.auth}", + "VELORUM_MODEL_${upper(k)}_TOKEN_COST=${m.token_cost}", + ] + ]) + default_keys = [for line in local.default_config_generator_env : split("=", line)[0]] override_keys = [for line in var.config_generator_env : split("=", line)[0]] default_unset = [ for i, line in local.default_config_generator_env : line if !contains(local.override_keys, local.default_keys[i]) ] - config_generator_env = concat(local.default_unset, var.config_generator_env) + config_generator_env = concat( + local.default_unset, + local.aquila_action_env, + local.velorum_model_env, + var.config_generator_env, + ) } diff --git a/terraform/docker/velorum.tf b/terraform/docker/velorum.tf index 1b06c89..b9fafb5 100644 --- a/terraform/docker/velorum.tf +++ b/terraform/docker/velorum.tf @@ -1,10 +1,16 @@ -resource "docker_image" "velorum" { - count = var.enable_velorum ? 1 : 0 +data "docker_registry_image" "velorum" { + count = local.velorum_enabled ? 1 : 0 name = "${var.image_registry}/velorum:${var.image_tag}-${var.image_edition}" } +resource "docker_image" "velorum" { + count = local.velorum_enabled ? 1 : 0 + name = data.docker_registry_image.velorum[0].name + pull_triggers = [data.docker_registry_image.velorum[0].sha256_digest] +} + resource "docker_container" "velorum" { - count = var.enable_velorum ? 1 : 0 + count = local.velorum_enabled ? 1 : 0 name = "${var.project_name}-velorum" image = docker_image.velorum[0].image_id @@ -20,8 +26,8 @@ resource "docker_container" "velorum" { ] upload { - file = "/velorum/few_shots_external.configuration.json" - content = var.few_shots_external_config_path + file = "/velorum/few_shots_external.configuration.json" + content = var.few_shots_external_config_path } volumes {