feat: load service URLs from ConfigMap, not hardcoded

This commit is contained in:
2026-09-06 06:11:26 -07:00
parent c41cef0ca5
commit 6b35b04d20
5 changed files with 211 additions and 1 deletions
+93
View File
@@ -0,0 +1,93 @@
/// Configuration management for inter-pod URLs via environment variables (ConfigMap)
/// All service URLs come from K8s ConfigMap, never hardcoded
///
/// ConfigMap in K8s:
/// ```yaml
/// apiVersion: v1
/// kind: ConfigMap
/// metadata:
/// name: memory-service-config
/// namespace: poimen
/// data:
/// MEMORY_SERVICE_ADDR: "http://memory-service.poimen.svc.cluster.local:8080"
/// AUTHENTIK_ISSUER: "http://authentik.iam.svc.cluster.local/application/o/poimen-memory/"
/// WEBHOOK_URL: "http://temporal-webhook.temporal.svc.cluster.local:9000/webhook"
/// ```
use anyhow::{anyhow, Result};
#[derive(Debug, Clone)]
pub struct ServiceConfig {
/// Memory service address (this service itself)
pub memory_service_addr: String,
/// Authentik OIDC issuer endpoint
pub authentik_issuer: String,
/// Temporal webhook callback URL
pub webhook_url: String,
/// OpenSearch cluster endpoint
pub opensearch_url: String,
/// PostgreSQL connection string
pub database_url: String,
}
impl ServiceConfig {
/// Load configuration from environment variables (set by K8s ConfigMap)
/// Fails if required env vars are missing
pub fn from_env() -> Result<Self> {
let memory_service_addr = std::env::var("MEMORY_SERVICE_ADDR")
.unwrap_or_else(|_| "http://localhost:8080".to_string());
let authentik_issuer = std::env::var("AUTHENTIK_ISSUER")
.map_err(|_| anyhow!("AUTHENTIK_ISSUER env var not set (configure in ConfigMap)"))?;
let webhook_url = std::env::var("WEBHOOK_URL")
.map_err(|_| anyhow!("WEBHOOK_URL env var not set (configure in ConfigMap)"))?;
let opensearch_url = std::env::var("OPENSEARCH_URL")
.map_err(|_| anyhow!("OPENSEARCH_URL env var not set (configure in ConfigMap)"))?;
let database_url = std::env::var("DATABASE_URL")
.map_err(|_| anyhow!("DATABASE_URL env var not set (configure Secret or ConfigMap)"))?;
Ok(ServiceConfig {
memory_service_addr,
authentik_issuer,
webhook_url,
opensearch_url,
database_url,
})
}
/// Load with defaults for development (localhost only)
pub fn from_env_dev() -> Self {
ServiceConfig {
memory_service_addr: std::env::var("MEMORY_SERVICE_ADDR")
.unwrap_or_else(|_| "http://localhost:8080".to_string()),
authentik_issuer: std::env::var("AUTHENTIK_ISSUER")
.unwrap_or_else(|_| "http://localhost:8080/application/o/poimen-memory/".to_string()),
webhook_url: std::env::var("WEBHOOK_URL")
.unwrap_or_else(|_| "http://localhost:9000/webhook".to_string()),
opensearch_url: std::env::var("OPENSEARCH_URL")
.unwrap_or_else(|_| "http://localhost:9200".to_string()),
database_url: std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://localhost/memory".to_string()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_from_env_dev() {
let config = ServiceConfig::from_env_dev();
assert_eq!(config.memory_service_addr, "http://localhost:8080");
assert!(config.authentik_issuer.contains("localhost"));
assert!(config.webhook_url.contains("localhost"));
}
}
+1
View File
@@ -1,3 +1,4 @@
pub mod config;
pub mod endpoints;
pub mod handlers;
pub mod http_server;
+3 -1
View File
@@ -448,8 +448,10 @@ async fn cmd_learn(
all_files.sort();
println!("Found {} markdown files", all_files.len());
// Load configuration from environment (set by K8s ConfigMap)
let config = mem_cli::config::ServiceConfig::from_env_dev();
let api_url = std::env::var("MEM_API_URL")
.unwrap_or_else(|_| "http://localhost:8080".to_string());
.unwrap_or_else(|_| config.memory_service_addr.clone());
let api_token = std::env::var("MEM_API_TOKEN").ok();
let http = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(120))
+95
View File
@@ -0,0 +1,95 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: memory-service
namespace: poimen
labels:
app: memory-service
spec:
replicas: 2
selector:
matchLabels:
app: memory-service
template:
metadata:
labels:
app: memory-service
spec:
serviceAccountName: memory-service
containers:
- name: memory-service
image: forgejo.riotpiao.com/rock/poimen-memory:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
# Read all config from ConfigMap
envFrom:
- configMapRef:
name: memory-service-config
# Secrets (override/add to ConfigMap)
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: memory-db-credentials
key: connection-string
- name: MEM_API_KEY
valueFrom:
secretKeyRef:
name: memory-api-keys
key: primary-key
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 5
# ImagePullSecret for private registry
imagePullSecrets:
- name: registry-credentials
---
apiVersion: v1
kind: Service
metadata:
name: memory-service
namespace: poimen
labels:
app: memory-service
spec:
type: ClusterIP
ports:
- name: http
port: 8080
targetPort: http
protocol: TCP
selector:
app: memory-service
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: memory-service
namespace: poimen
+19
View File
@@ -0,0 +1,19 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: memory-service-config
namespace: poimen
labels:
app: memory-service
version: "1"
data:
# Inter-pod URLs (cluster-internal DNS)
MEMORY_SERVICE_ADDR: "http://memory-service.poimen.svc.cluster.local:8080"
AUTHENTIK_ISSUER: "http://authentik-server.iam.svc.cluster.local/application/o/poimen-memory/"
WEBHOOK_URL: "http://temporal-webhook.temporal.svc.cluster.local:9000/webhook"
OPENSEARCH_URL: "http://opensearch.poimen.svc.cluster.local:9200"
# Service addresses for internal communication
POSTGRES_HOST: "memory-db.poimen.svc.cluster.local"
POSTGRES_PORT: "5432"
POSTGRES_DB: "memory"