diff --git a/servers/legion/apps/neuron-tim.yaml b/servers/legion/apps/neuron-tim.yaml new file mode 100644 index 0000000..ec75f14 --- /dev/null +++ b/servers/legion/apps/neuron-tim.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: neuron-tim + namespace: argocd +spec: + project: default + source: + repoURL: http://10.43.1.53:3000/will/infrastructure.git + targetRevision: main + path: servers/legion/k8s/neuron-technologies/tim + destination: + server: https://kubernetes.default.svc + namespace: neuron-tim + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/servers/legion/k8s/neuron-technologies/tim/configmap.yaml b/servers/legion/k8s/neuron-technologies/tim/configmap.yaml new file mode 100644 index 0000000..305b6a1 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: neuron-tim-config + namespace: neuron-tim +data: + SPRING_PROFILES_ACTIVE: "prod" + NEURON_DATA_DIR: "/data" + NEURON_DB_PATH: "/data/neuron.db" + NEURON_STORAGE_PATH: "/data" + SERVER_TOMCAT_ACCESSLOG_ENABLED: "true" + # Prod-equivalent: minimal surface — never expose internals + MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: "health,info" + MANAGEMENT_ENDPOINT_HEALTH_SHOW_DETAILS: "never" diff --git a/servers/legion/k8s/neuron-technologies/tim/externalsecret.yaml b/servers/legion/k8s/neuron-technologies/tim/externalsecret.yaml new file mode 100644 index 0000000..c567ad5 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/externalsecret.yaml @@ -0,0 +1,57 @@ +# ExternalSecret for Tim's Neuron instance. +# +# Before Tim's instance can start, populate these Vault paths: +# vault kv put secret/neuron-technologies/tim \ +# api_key= \ +# gitea_webhook_secret= +# +# Required Vault secrets: +# secret/data/neuron-technologies/tim: +# - api_key → NEURON_API_KEY +# - gitea_webhook_secret → NEURON_WEBHOOK_SECRET +# +# secret/data/neuron-technologies/license: +# - admin_token → NEURON_LICENSE_ADMIN_TOKEN (shared with prod) +# +# secret/data/neuron-technologies/unkey: +# - root_key → UNKEY_ROOT_KEY (shared with prod) +# - api_id → UNKEY_API_ID (shared with prod) +# +# Tim's instance-specific secrets that should be scoped under secret/neuron-technologies/tim: +# - anthropic_api_key (Tim's own Anthropic API key) +# - neuron_license_key (Tim's license key issued by the license server) +# - db_encryption_key (encryption key for Tim's SQLite DB) +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: neuron-tim-secrets + namespace: neuron-tim +spec: + refreshInterval: 1h + secretStoreRef: + name: vault + kind: ClusterSecretStore + target: + name: neuron-tim-secrets + creationPolicy: Owner + data: + - secretKey: NEURON_API_KEY + remoteRef: + key: secret/data/neuron-technologies/tim + property: api_key + - secretKey: NEURON_WEBHOOK_SECRET + remoteRef: + key: secret/data/neuron-technologies/tim + property: gitea_webhook_secret + - secretKey: NEURON_LICENSE_ADMIN_TOKEN + remoteRef: + key: secret/data/neuron-technologies/license + property: admin_token + - secretKey: UNKEY_ROOT_KEY + remoteRef: + key: secret/data/neuron-technologies/unkey + property: root_key + - secretKey: UNKEY_API_ID + remoteRef: + key: secret/data/neuron-technologies/unkey + property: api_id diff --git a/servers/legion/k8s/neuron-technologies/tim/ingress.yaml b/servers/legion/k8s/neuron-technologies/tim/ingress.yaml new file mode 100644 index 0000000..816d329 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/ingress.yaml @@ -0,0 +1,37 @@ +# TODO: Confirm subdomain for Tim's Neuron instance. +# Placeholder: tim.neurontechnologies.ai +# Alternatives to consider: neuron-tim.neuralplatform.ai +# Once confirmed, add a DNS CNAME record in dns-neurontechnologies.tf (or dns-neuralplatform.tf) +# pointing to ${var.cloudflare_tunnel_id}.cfargotunnel.com. +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: neuron-tim + namespace: neuron-tim + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + cert-manager.io/cluster-issuer: letsencrypt-prod +spec: + ingressClassName: traefik + tls: + - secretName: neuron-tim-tls + hosts: + - tim.neurontechnologies.ai + rules: + - host: tim.neurontechnologies.ai + http: + paths: + - path: /mcp + pathType: Prefix + backend: + service: + name: neuron-mcp + port: + number: 8080 + - path: / + pathType: Prefix + backend: + service: + name: neuron-rest + port: + number: 8081 diff --git a/servers/legion/k8s/neuron-technologies/tim/kustomization.yaml b/servers/legion/k8s/neuron-technologies/tim/kustomization.yaml new file mode 100644 index 0000000..4ea8ac1 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/kustomization.yaml @@ -0,0 +1,10 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - configmap.yaml + - pvc.yaml + - externalsecret.yaml + - mcp-deployment.yaml + - rest-deployment.yaml + - services.yaml + - ingress.yaml diff --git a/servers/legion/k8s/neuron-technologies/tim/mcp-deployment.yaml b/servers/legion/k8s/neuron-technologies/tim/mcp-deployment.yaml new file mode 100644 index 0000000..6834616 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/mcp-deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: neuron-mcp + namespace: neuron-tim + labels: + app: neuron-mcp + env: tim +spec: + replicas: 0 # Not yet deployed — Tim's imprint not set up + strategy: + type: Recreate + selector: + matchLabels: + app: neuron-mcp + template: + metadata: + labels: + app: neuron-mcp + env: tim + spec: + containers: + - name: neuron-mcp + image: registry.neuralplatform.ai/neuron-technologies/neuron-mcp:v0.6.1 + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + envFrom: + - configMapRef: + name: neuron-tim-config + - secretRef: + name: neuron-tim-secrets + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: 1000m + memory: 1Gi + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: http + initialDelaySeconds: 30 + periodSeconds: 30 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: http + initialDelaySeconds: 15 + periodSeconds: 10 + failureThreshold: 3 + volumes: + - name: data + persistentVolumeClaim: + claimName: neuron-tim-data diff --git a/servers/legion/k8s/neuron-technologies/tim/pvc.yaml b/servers/legion/k8s/neuron-technologies/tim/pvc.yaml new file mode 100644 index 0000000..892328b --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: neuron-tim-data + namespace: neuron-tim +spec: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/servers/legion/k8s/neuron-technologies/tim/rest-deployment.yaml b/servers/legion/k8s/neuron-technologies/tim/rest-deployment.yaml new file mode 100644 index 0000000..03e34f5 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/rest-deployment.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: neuron-rest + namespace: neuron-tim + labels: + app: neuron-rest + env: tim +spec: + replicas: 0 # Not yet deployed — Tim's imprint not set up + strategy: + type: Recreate + selector: + matchLabels: + app: neuron-rest + template: + metadata: + labels: + app: neuron-rest + env: tim + spec: + containers: + - name: neuron-rest + image: registry.neuralplatform.ai/neuron-technologies/neuron-rest:v0.6.1 + imagePullPolicy: Always + ports: + - name: http + containerPort: 8081 + envFrom: + - configMapRef: + name: neuron-tim-config + - secretRef: + name: neuron-tim-secrets + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: 1000m + memory: 1Gi + livenessProbe: + httpGet: + path: /actuator/health/liveness + port: http + initialDelaySeconds: 30 + periodSeconds: 30 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /actuator/health/readiness + port: http + initialDelaySeconds: 15 + periodSeconds: 10 + failureThreshold: 3 + volumes: + - name: data + persistentVolumeClaim: + claimName: neuron-tim-data diff --git a/servers/legion/k8s/neuron-technologies/tim/services.yaml b/servers/legion/k8s/neuron-technologies/tim/services.yaml new file mode 100644 index 0000000..4979a94 --- /dev/null +++ b/servers/legion/k8s/neuron-technologies/tim/services.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: Service +metadata: + name: neuron-mcp + namespace: neuron-tim + labels: + app: neuron-mcp +spec: + selector: + app: neuron-mcp + ports: + - name: http + port: 8080 + targetPort: 8080 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: neuron-rest + namespace: neuron-tim + labels: + app: neuron-rest +spec: + selector: + app: neuron-rest + ports: + - name: http + port: 8081 + targetPort: 8081 + type: ClusterIP diff --git a/servers/legion/neuron-technologies.tf b/servers/legion/neuron-technologies.tf index 8e6cba7..0587ad8 100644 --- a/servers/legion/neuron-technologies.tf +++ b/servers/legion/neuron-technologies.tf @@ -37,3 +37,16 @@ resource "kubernetes_namespace" "neuron_prod" { } } } + +resource "kubernetes_namespace" "neuron_tim" { + metadata { + name = "neuron-tim" + labels = { + managed-by = "terraform" + tier = "apps" + environment = "prod" + app = "neuron-technologies" + owner = "tim" + } + } +}