478 lines
No EOL
11 KiB
HCL
478 lines
No EOL
11 KiB
HCL
terraform {
|
|
required_version = ">= 1.0"
|
|
required_providers {
|
|
google = {
|
|
source = "hashicorp/google"
|
|
version = "~> 5.0"
|
|
}
|
|
}
|
|
}
|
|
|
|
provider "google" {
|
|
project = var.project_id
|
|
region = var.region
|
|
}
|
|
|
|
# Variables
|
|
variable "project_id" {
|
|
description = "Google Cloud Project ID"
|
|
type = string
|
|
}
|
|
|
|
variable "region" {
|
|
description = "Google Cloud Region"
|
|
type = string
|
|
default = "us-central1"
|
|
}
|
|
|
|
variable "environment" {
|
|
description = "Environment (dev, staging, prod)"
|
|
type = string
|
|
default = "prod"
|
|
}
|
|
|
|
# Enable required APIs
|
|
resource "google_project_service" "required_apis" {
|
|
for_each = toset([
|
|
"cloudbuild.googleapis.com",
|
|
"run.googleapis.com",
|
|
"containerregistry.googleapis.com",
|
|
"secretmanager.googleapis.com",
|
|
"cloudtrace.googleapis.com",
|
|
"monitoring.googleapis.com",
|
|
"translate.googleapis.com",
|
|
"texttospeech.googleapis.com",
|
|
"storage.googleapis.com",
|
|
"aiplatform.googleapis.com"
|
|
])
|
|
|
|
service = each.value
|
|
disable_on_destroy = false
|
|
}
|
|
|
|
# Service Accounts
|
|
resource "google_service_account" "api_service_account" {
|
|
account_id = "accessible-video-api"
|
|
display_name = "Accessible Video API Service Account"
|
|
description = "Service account for the API server"
|
|
}
|
|
|
|
resource "google_service_account" "worker_service_account" {
|
|
account_id = "accessible-video-worker"
|
|
display_name = "Accessible Video Worker Service Account"
|
|
description = "Service account for Celery workers"
|
|
}
|
|
|
|
# IAM bindings for API service account
|
|
resource "google_project_iam_member" "api_secret_accessor" {
|
|
project = var.project_id
|
|
role = "roles/secretmanager.secretAccessor"
|
|
member = "serviceAccount:${google_service_account.api_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "api_storage_admin" {
|
|
project = var.project_id
|
|
role = "roles/storage.objectAdmin"
|
|
member = "serviceAccount:${google_service_account.api_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "api_trace_agent" {
|
|
project = var.project_id
|
|
role = "roles/cloudtrace.agent"
|
|
member = "serviceAccount:${google_service_account.api_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "api_monitoring_writer" {
|
|
project = var.project_id
|
|
role = "roles/monitoring.metricWriter"
|
|
member = "serviceAccount:${google_service_account.api_service_account.email}"
|
|
}
|
|
|
|
# IAM bindings for Worker service account
|
|
resource "google_project_iam_member" "worker_secret_accessor" {
|
|
project = var.project_id
|
|
role = "roles/secretmanager.secretAccessor"
|
|
member = "serviceAccount:${google_service_account.worker_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "worker_storage_admin" {
|
|
project = var.project_id
|
|
role = "roles/storage.objectAdmin"
|
|
member = "serviceAccount:${google_service_account.worker_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "worker_trace_agent" {
|
|
project = var.project_id
|
|
role = "roles/cloudtrace.agent"
|
|
member = "serviceAccount:${google_service_account.worker_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "worker_monitoring_writer" {
|
|
project = var.project_id
|
|
role = "roles/monitoring.metricWriter"
|
|
member = "serviceAccount:${google_service_account.worker_service_account.email}"
|
|
}
|
|
|
|
resource "google_project_iam_member" "worker_ai_user" {
|
|
project = var.project_id
|
|
role = "roles/aiplatform.user"
|
|
member = "serviceAccount:${google_service_account.worker_service_account.email}"
|
|
}
|
|
|
|
# GCS Bucket for video storage
|
|
resource "google_storage_bucket" "video_storage" {
|
|
name = "accessible-video-${var.project_id}"
|
|
location = var.region
|
|
storage_class = "STANDARD"
|
|
|
|
uniform_bucket_level_access = true
|
|
|
|
cors {
|
|
origin = ["https://your-frontend-domain.com", "http://localhost:5173"]
|
|
method = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
|
|
response_header = ["Content-Type", "Authorization", "Range"]
|
|
max_age_seconds = 3600
|
|
}
|
|
|
|
lifecycle_rule {
|
|
condition {
|
|
age = 90
|
|
}
|
|
action {
|
|
type = "Delete"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Cloud Run API Service
|
|
resource "google_cloud_run_v2_service" "api_service" {
|
|
name = "accessible-video-api"
|
|
location = var.region
|
|
|
|
depends_on = [google_project_service.required_apis]
|
|
|
|
template {
|
|
service_account = google_service_account.api_service_account.email
|
|
|
|
scaling {
|
|
min_instance_count = 1
|
|
max_instance_count = 10
|
|
}
|
|
|
|
containers {
|
|
image = "gcr.io/${var.project_id}/accessible-video-api:latest"
|
|
|
|
ports {
|
|
container_port = 8000
|
|
}
|
|
|
|
resources {
|
|
limits = {
|
|
memory = "2Gi"
|
|
cpu = "2000m"
|
|
}
|
|
cpu_idle = false
|
|
}
|
|
|
|
env {
|
|
name = "APP_ENV"
|
|
value = var.environment
|
|
}
|
|
|
|
env {
|
|
name = "PYTHONPATH"
|
|
value = "/app"
|
|
}
|
|
|
|
env {
|
|
name = "PYTHONUNBUFFERED"
|
|
value = "1"
|
|
}
|
|
|
|
env {
|
|
name = "GCS_BUCKET_NAME"
|
|
value = google_storage_bucket.video_storage.name
|
|
}
|
|
|
|
env {
|
|
name = "GOOGLE_CLOUD_PROJECT"
|
|
value = var.project_id
|
|
}
|
|
|
|
env {
|
|
name = "OTEL_SERVICE_NAME"
|
|
value = "accessible-video-api"
|
|
}
|
|
|
|
env {
|
|
name = "OTEL_TRACES_EXPORTER"
|
|
value = "gcp_trace"
|
|
}
|
|
|
|
env {
|
|
name = "SENTRY_ENVIRONMENT"
|
|
value = var.environment
|
|
}
|
|
|
|
# Secret environment variables
|
|
env {
|
|
name = "MONGODB_URL"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "mongodb-url"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "REDIS_URL"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "redis-url"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "JWT_SECRET_KEY"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "jwt-secret"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "GEMINI_API_KEY"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "gemini-api-key"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "SENDGRID_API_KEY"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "sendgrid-api-key"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "ELEVENLABS_API_KEY"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "elevenlabs-api-key"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "SENTRY_DSN"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "sentry-dsn"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
liveness_probe {
|
|
http_get {
|
|
path = "/health"
|
|
port = 8000
|
|
}
|
|
initial_delay_seconds = 30
|
|
timeout_seconds = 10
|
|
period_seconds = 60
|
|
}
|
|
|
|
startup_probe {
|
|
http_get {
|
|
path = "/health"
|
|
port = 8000
|
|
}
|
|
initial_delay_seconds = 10
|
|
timeout_seconds = 5
|
|
period_seconds = 30
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Cloud Run Worker Service
|
|
resource "google_cloud_run_v2_service" "worker_service" {
|
|
name = "accessible-video-worker"
|
|
location = var.region
|
|
|
|
depends_on = [google_project_service.required_apis]
|
|
|
|
template {
|
|
service_account = google_service_account.worker_service_account.email
|
|
|
|
scaling {
|
|
min_instance_count = 0
|
|
max_instance_count = 5
|
|
}
|
|
|
|
containers {
|
|
image = "gcr.io/${var.project_id}/accessible-video-worker:latest"
|
|
|
|
resources {
|
|
limits = {
|
|
memory = "4Gi"
|
|
cpu = "4000m"
|
|
}
|
|
cpu_idle = false
|
|
}
|
|
|
|
env {
|
|
name = "APP_ENV"
|
|
value = var.environment
|
|
}
|
|
|
|
env {
|
|
name = "PYTHONPATH"
|
|
value = "/app"
|
|
}
|
|
|
|
env {
|
|
name = "PYTHONUNBUFFERED"
|
|
value = "1"
|
|
}
|
|
|
|
env {
|
|
name = "C_FORCE_ROOT"
|
|
value = "1"
|
|
}
|
|
|
|
env {
|
|
name = "GCS_BUCKET_NAME"
|
|
value = google_storage_bucket.video_storage.name
|
|
}
|
|
|
|
env {
|
|
name = "GOOGLE_CLOUD_PROJECT"
|
|
value = var.project_id
|
|
}
|
|
|
|
env {
|
|
name = "OTEL_SERVICE_NAME"
|
|
value = "accessible-video-worker"
|
|
}
|
|
|
|
env {
|
|
name = "OTEL_TRACES_EXPORTER"
|
|
value = "gcp_trace"
|
|
}
|
|
|
|
env {
|
|
name = "SENTRY_ENVIRONMENT"
|
|
value = var.environment
|
|
}
|
|
|
|
# Secret environment variables
|
|
env {
|
|
name = "MONGODB_URL"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "mongodb-url"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "REDIS_URL"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "redis-url"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "CELERY_BROKER_URL"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "redis-url"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "CELERY_RESULT_BACKEND"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "redis-url"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "GEMINI_API_KEY"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "gemini-api-key"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "ELEVENLABS_API_KEY"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "elevenlabs-api-key"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
|
|
env {
|
|
name = "SENTRY_DSN"
|
|
value_source {
|
|
secret_key_ref {
|
|
secret = "sentry-dsn"
|
|
version = "latest"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# IAM for public access to API
|
|
resource "google_cloud_run_service_iam_binding" "api_public_access" {
|
|
location = google_cloud_run_v2_service.api_service.location
|
|
service = google_cloud_run_v2_service.api_service.name
|
|
role = "roles/run.invoker"
|
|
members = ["allUsers"]
|
|
}
|
|
|
|
# Outputs
|
|
output "api_service_url" {
|
|
description = "URL of the deployed API service"
|
|
value = google_cloud_run_v2_service.api_service.uri
|
|
}
|
|
|
|
output "worker_service_url" {
|
|
description = "URL of the deployed worker service"
|
|
value = google_cloud_run_v2_service.worker_service.uri
|
|
}
|
|
|
|
output "storage_bucket_name" {
|
|
description = "Name of the GCS bucket for video storage"
|
|
value = google_storage_bucket.video_storage.name
|
|
} |