Restructure: servers/legion/ layout, rename repo to infrastructure

This commit is contained in:
Will Anderson
2026-03-23 07:38:42 -05:00
parent 7751eddd73
commit 0b4a236a88
22 changed files with 4 additions and 4 deletions
+343
View File
@@ -0,0 +1,343 @@
# Neuron — MCP server + Axon webhook hub
# MCP: https://neuron.nook.family (internal, Traefik)
# Webhooks: https://axon.neuralplatform.ai (external, Cloudflare tunnel)
#
# Image: registry.nook.family/neural-platform/neuron:latest
# Built by GitHub Actions runner on Legion — see neural-platform/neuron ci.yml
#
# TODO: Migrate SQLite → Postgres once neuron db migration is ready
# TODO: Wire Gmail OAuth credentials via k8s Secret (currently unauthenticated)
resource "kubernetes_namespace" "neuron" {
metadata {
name = "neuron"
labels = {
managed-by = "terraform"
tier = "platform"
}
}
}
resource "kubernetes_persistent_volume_claim" "neuron_data" {
metadata {
name = "neuron-data"
namespace = kubernetes_namespace.neuron.metadata[0].name
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = "5Gi"
}
}
}
}
resource "kubernetes_config_map" "neuron_config" {
metadata {
name = "neuron-config"
namespace = kubernetes_namespace.neuron.metadata[0].name
}
data = {
MCP_PORT = "8001"
MCP_HOST = "0.0.0.0"
WEBHOOK_PORT = "3847"
NEURON_DB_PATH = "/data/neuron.db"
AXON_DB_PATH = "/data/axon.db"
TUNNEL_NAME = "neural-platform"
"default.yaml" = <<-EOT
runtime:
name: neuron
version: 0.1.0
storage:
db_path: /data/neuron.db
cache:
max_l1_size: 1000
gc:
gen0_threshold: 3
gen1_threshold: 5
knowledge:
base_path: /data/knowledge
synapse:
path: /data/synapse
EOT
}
}
resource "kubernetes_secret" "neuron_secrets" {
metadata {
name = "neuron-secrets"
namespace = kubernetes_namespace.neuron.metadata[0].name
}
data = {
GITHUB_WEBHOOK_SECRET = var.github_webhook_secret
GITEA_WEBHOOK_SECRET = var.gitea_webhook_secret
SLACK_BOT_TOKEN = var.slack_bot_token
SLACK_SIGNING_SECRET = var.slack_signing_secret
}
}
resource "kubernetes_deployment" "neuron" {
metadata {
name = "neuron"
namespace = kubernetes_namespace.neuron.metadata[0].name
labels = {
app = "neuron"
}
}
spec {
replicas = 1
strategy {
type = "Recreate" # SQLite cannot handle concurrent writers
}
selector {
match_labels = {
app = "neuron"
}
}
template {
metadata {
labels = {
app = "neuron"
}
}
spec {
container {
name = "neuron"
image = "registry.nook.family/neural-platform/neuron:latest"
image_pull_policy = "Always"
command = [
"bash", "-c",
"mkdir -p /root/.neuron && ln -sf /data/neuron.db /root/.neuron/neuron.db && python -m synapse platform serve --mcp-host 0.0.0.0 --mcp-port 8001 --webhook-port 3847"
]
port {
name = "mcp"
container_port = 8001
}
port {
name = "webhook"
container_port = 3847
}
env_from {
config_map_ref {
name = kubernetes_config_map.neuron_config.metadata[0].name
}
}
env_from {
secret_ref {
name = kubernetes_secret.neuron_secrets.metadata[0].name
}
}
volume_mount {
name = "data"
mount_path = "/data"
}
volume_mount {
name = "app-config"
mount_path = "/app/config/default.yaml"
sub_path = "default.yaml"
}
resources {
requests = {
memory = "256Mi"
cpu = "100m"
}
limits = {
memory = "1Gi"
cpu = "500m"
}
}
liveness_probe {
http_get {
path = "/health"
port = "mcp"
}
initial_delay_seconds = 10
period_seconds = 30
}
readiness_probe {
http_get {
path = "/health"
port = "mcp"
}
initial_delay_seconds = 5
period_seconds = 10
}
}
volume {
name = "data"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.neuron_data.metadata[0].name
}
}
volume {
name = "app-config"
config_map {
name = kubernetes_config_map.neuron_config.metadata[0].name
items {
key = "default.yaml"
path = "default.yaml"
}
}
}
}
}
}
depends_on = [kubernetes_persistent_volume_claim.neuron_data]
}
resource "kubernetes_service" "neuron" {
metadata {
name = "neuron"
namespace = kubernetes_namespace.neuron.metadata[0].name
}
spec {
selector = {
app = "neuron"
}
port {
name = "mcp"
port = 8001
target_port = 8001
}
port {
name = "webhook"
port = 3847
target_port = 3847
}
type = "ClusterIP"
}
}
# Internal MCP ingress — accessible within nook.family network
resource "kubernetes_ingress_v1" "neuron" {
metadata {
name = "neuron"
namespace = kubernetes_namespace.neuron.metadata[0].name
annotations = {
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
}
}
spec {
ingress_class_name = "traefik"
tls {
secret_name = "neuron-tls"
hosts = ["neuron.${var.infra_domain}"]
}
rule {
host = "neuron.${var.infra_domain}"
http {
path {
path = "/"
path_type = "Prefix"
backend {
service {
name = kubernetes_service.neuron.metadata[0].name
port {
number = 8001
}
}
}
}
}
}
}
depends_on = [helm_release.cert_manager]
}
# cloudflared — Cloudflare tunnel for external access to Axon webhooks
# Routes: axon.neuralplatform.ai → neuron:3847
# webhooks.neuralplatform.ai → neuron:3847
resource "kubernetes_deployment" "cloudflared" {
metadata {
name = "cloudflared"
namespace = kubernetes_namespace.neuron.metadata[0].name
labels = {
app = "cloudflared"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "cloudflared"
}
}
template {
metadata {
labels = {
app = "cloudflared"
}
}
spec {
container {
name = "cloudflared"
image = "cloudflare/cloudflared:latest"
args = ["tunnel", "--no-autoupdate", "run"]
env {
name = "TUNNEL_TOKEN"
value = var.cloudflared_tunnel_token
}
resources {
requests = {
memory = "64Mi"
cpu = "50m"
}
limits = {
memory = "128Mi"
cpu = "200m"
}
}
liveness_probe {
http_get {
path = "/ready"
port = 20241
}
initial_delay_seconds = 10
period_seconds = 30
}
}
}
}
}
depends_on = [kubernetes_deployment.neuron]
}