Add AFFiNE visual canvas for storytelling
- Deploy AFFiNE as self-hosted visual canvas tool - Uses shared PostgreSQL and Redis from cluster - NFS storage for uploads and configuration - Email configured via mailserver.viktorbarzin.me - Ingress at affine.viktorbarzin.me [ci skip]
This commit is contained in:
parent
5ded70c1ab
commit
e85c0365cd
3 changed files with 250 additions and 5 deletions
10
main.tf
10
main.tf
|
|
@ -139,6 +139,10 @@ variable "freedify_credentials" { type = map(any) }
|
|||
variable "mcaptcha_postgresql_password" { type = string }
|
||||
variable "mcaptcha_cookie_secret" { type = string }
|
||||
variable "mcaptcha_captcha_salt" { type = string }
|
||||
variable "openrouter_api_key" { type = string }
|
||||
variable "slack_bot_token" { type = string }
|
||||
variable "slack_channel" { type = string }
|
||||
variable "affine_postgresql_password" { type = string }
|
||||
|
||||
provider "kubernetes" {
|
||||
config_path = var.prod ? "" : "~/.kube/config"
|
||||
|
|
@ -570,6 +574,12 @@ module "kubernetes_cluster" {
|
|||
mcaptcha_postgresql_password = var.mcaptcha_postgresql_password
|
||||
mcaptcha_cookie_secret = var.mcaptcha_cookie_secret
|
||||
mcaptcha_captcha_salt = var.mcaptcha_captcha_salt
|
||||
|
||||
openrouter_api_key = var.openrouter_api_key
|
||||
slack_bot_token = var.slack_bot_token
|
||||
slack_channel = var.slack_channel
|
||||
|
||||
affine_postgresql_password = var.affine_postgresql_password
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
217
modules/kubernetes/affine/main.tf
Normal file
217
modules/kubernetes/affine/main.tf
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
variable "tls_secret_name" {}
|
||||
variable "tier" { type = string }
|
||||
variable "postgresql_password" {}
|
||||
variable "smtp_password" { type = string }
|
||||
|
||||
resource "kubernetes_namespace" "affine" {
|
||||
metadata {
|
||||
name = "affine"
|
||||
}
|
||||
}
|
||||
|
||||
module "tls_secret" {
|
||||
source = "../setup_tls_secret"
|
||||
namespace = kubernetes_namespace.affine.metadata[0].name
|
||||
tls_secret_name = var.tls_secret_name
|
||||
}
|
||||
|
||||
locals {
|
||||
common_env = [
|
||||
{
|
||||
name = "DATABASE_URL"
|
||||
value = "postgresql://affine:${var.postgresql_password}@postgresql.dbaas.svc.cluster.local:5432/affine"
|
||||
},
|
||||
{
|
||||
name = "REDIS_SERVER_HOST"
|
||||
value = "redis.redis.svc.cluster.local"
|
||||
},
|
||||
{
|
||||
name = "AFFINE_INDEXER_ENABLED"
|
||||
value = "false"
|
||||
},
|
||||
{
|
||||
name = "NODE_OPTIONS"
|
||||
value = "--max-old-space-size=4096"
|
||||
},
|
||||
# Server URL configuration
|
||||
{
|
||||
name = "AFFINE_SERVER_EXTERNAL_URL"
|
||||
value = "https://affine.viktorbarzin.me"
|
||||
},
|
||||
{
|
||||
name = "AFFINE_SERVER_HTTPS"
|
||||
value = "true"
|
||||
},
|
||||
# Email/SMTP configuration
|
||||
{
|
||||
name = "MAILER_HOST"
|
||||
value = "mailserver.viktorbarzin.me"
|
||||
},
|
||||
{
|
||||
name = "MAILER_PORT"
|
||||
value = "587"
|
||||
},
|
||||
{
|
||||
name = "MAILER_USER"
|
||||
value = "info@viktorbarzin.me"
|
||||
},
|
||||
{
|
||||
name = "MAILER_PASSWORD"
|
||||
value = var.smtp_password
|
||||
},
|
||||
{
|
||||
name = "MAILER_SENDER"
|
||||
value = "AFFiNE <info@viktorbarzin.me>"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "affine" {
|
||||
metadata {
|
||||
name = "affine"
|
||||
namespace = kubernetes_namespace.affine.metadata[0].name
|
||||
labels = {
|
||||
app = "affine"
|
||||
tier = var.tier
|
||||
}
|
||||
}
|
||||
spec {
|
||||
replicas = 1
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "affine"
|
||||
}
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "affine"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
# Init container to run database migrations
|
||||
init_container {
|
||||
name = "migration"
|
||||
image = "ghcr.io/toeverything/affine:stable"
|
||||
command = ["sh", "-c", "node ./scripts/self-host-predeploy.js"]
|
||||
|
||||
dynamic "env" {
|
||||
for_each = local.common_env
|
||||
content {
|
||||
name = env.value.name
|
||||
value = env.value.value
|
||||
}
|
||||
}
|
||||
|
||||
volume_mount {
|
||||
name = "data"
|
||||
mount_path = "/root/.affine/storage"
|
||||
sub_path = "storage"
|
||||
}
|
||||
volume_mount {
|
||||
name = "data"
|
||||
mount_path = "/root/.affine/config"
|
||||
sub_path = "config"
|
||||
}
|
||||
}
|
||||
|
||||
container {
|
||||
name = "affine"
|
||||
image = "ghcr.io/toeverything/affine:stable"
|
||||
|
||||
port {
|
||||
container_port = 3010
|
||||
}
|
||||
|
||||
dynamic "env" {
|
||||
for_each = local.common_env
|
||||
content {
|
||||
name = env.value.name
|
||||
value = env.value.value
|
||||
}
|
||||
}
|
||||
|
||||
volume_mount {
|
||||
name = "data"
|
||||
mount_path = "/root/.affine/storage"
|
||||
sub_path = "storage"
|
||||
}
|
||||
volume_mount {
|
||||
name = "data"
|
||||
mount_path = "/root/.affine/config"
|
||||
sub_path = "config"
|
||||
}
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "512Mi"
|
||||
cpu = "100m"
|
||||
}
|
||||
limits = {
|
||||
memory = "4Gi"
|
||||
cpu = "2"
|
||||
}
|
||||
}
|
||||
|
||||
liveness_probe {
|
||||
http_get {
|
||||
path = "/info"
|
||||
port = 3010
|
||||
}
|
||||
initial_delay_seconds = 120
|
||||
period_seconds = 30
|
||||
timeout_seconds = 10
|
||||
}
|
||||
readiness_probe {
|
||||
http_get {
|
||||
path = "/info"
|
||||
port = 3010
|
||||
}
|
||||
initial_delay_seconds = 60
|
||||
period_seconds = 10
|
||||
timeout_seconds = 5
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "data"
|
||||
nfs {
|
||||
server = "10.0.10.15"
|
||||
path = "/mnt/main/affine"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service" "affine" {
|
||||
metadata {
|
||||
name = "affine"
|
||||
namespace = kubernetes_namespace.affine.metadata[0].name
|
||||
labels = {
|
||||
app = "affine"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
selector = {
|
||||
app = "affine"
|
||||
}
|
||||
port {
|
||||
name = "http"
|
||||
port = 80
|
||||
target_port = 3010
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "ingress" {
|
||||
source = "../ingress_factory"
|
||||
namespace = kubernetes_namespace.affine.metadata[0].name
|
||||
name = "affine"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
max_body_size = "500m"
|
||||
extra_annotations = {
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" : "500m"
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +118,10 @@ variable "freedify_credentials" { type = map(any) }
|
|||
variable "mcaptcha_postgresql_password" { type = string }
|
||||
variable "mcaptcha_cookie_secret" { type = string }
|
||||
variable "mcaptcha_captcha_salt" { type = string }
|
||||
variable "openrouter_api_key" { type = string }
|
||||
variable "slack_bot_token" { type = string }
|
||||
variable "slack_channel" { type = string }
|
||||
variable "affine_postgresql_password" { type = string }
|
||||
|
||||
|
||||
variable "defcon_level" {
|
||||
|
|
@ -143,7 +147,7 @@ locals {
|
|||
"url", "excalidraw", "travel_blog", "dashy", "send", "ytdlp", "wealthfolio", "rybbit", "stirling-pdf",
|
||||
"networking-toolbox", "navidrome", "freshrss", "forgejo", "tor-proxy", "real-estate-crawler", "n8n",
|
||||
"changedetection", "linkwarden", "matrix", "homepage", "meshcentral", "diun", "cyberchef", "ntfy", "ollama",
|
||||
"servarr", "jsoncrack", "paperless-ngx", "frigate", "audiobookshelf", "tandoor", "ebook2audiobook", "netbox", "speedtest", "resume", "freedify", "mcaptcha"
|
||||
"servarr", "jsoncrack", "paperless-ngx", "frigate", "audiobookshelf", "tandoor", "ebook2audiobook", "netbox", "speedtest", "resume", "freedify", "mcaptcha", "affine"
|
||||
],
|
||||
}
|
||||
active_modules = distinct(flatten([
|
||||
|
|
@ -539,10 +543,13 @@ module "redis" {
|
|||
}
|
||||
|
||||
module "ytdlp" {
|
||||
source = "./youtube_dl"
|
||||
for_each = contains(local.active_modules, "ytdlp") ? { ytdlp = true } : {}
|
||||
tls_secret_name = var.tls_secret_name
|
||||
tier = local.tiers.aux
|
||||
source = "./youtube_dl"
|
||||
for_each = contains(local.active_modules, "ytdlp") ? { ytdlp = true } : {}
|
||||
tls_secret_name = var.tls_secret_name
|
||||
tier = local.tiers.aux
|
||||
openrouter_api_key = var.openrouter_api_key
|
||||
slack_bot_token = var.slack_bot_token
|
||||
slack_channel = var.slack_channel
|
||||
|
||||
depends_on = [null_resource.core_services]
|
||||
}
|
||||
|
|
@ -1062,3 +1069,14 @@ module "freedify" {
|
|||
for_each = contains(local.active_modules, "freedify") ? { freedify = true } : {}
|
||||
additional_credentials = var.freedify_credentials
|
||||
}
|
||||
|
||||
module "affine" {
|
||||
source = "./affine"
|
||||
for_each = contains(local.active_modules, "affine") ? { affine = true } : {}
|
||||
tls_secret_name = var.tls_secret_name
|
||||
postgresql_password = var.affine_postgresql_password
|
||||
smtp_password = var.mailserver_accounts["info@viktorbarzin.me"]
|
||||
tier = local.tiers.aux
|
||||
|
||||
depends_on = [null_resource.core_services]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue