trading-bot: revive K8s stack + add meet-kevin-watcher
Uncomment the trading-bot stack (disabled 2026-04-06 due to resource consumption) and add the new meet_kevin_watcher service container. Changes: - Uncomment the /* ... */ block enclosing the entire stack - Fix db_init job: add -d postgres to psql commands (root user has no root-named database — matches pattern used in claude-memory + others) - Remove 3 disabled containers from trading-bot-workers Pod spec: news-fetcher, sentiment-analyzer, trade-executor - Add new meet-kevin-watcher container (image viktorbarzin/trading-bot-service:latest, command python -m services.meet_kevin_watcher.main, mem 128Mi/256Mi) - Extend ExternalSecret with TRADING_OPENROUTER_API_KEY and TRADING_MEET_KEVIN_CHANNEL_ID keys (sourced from Vault secret/trading-bot) - Add 4 common_env entries for the Meet Kevin pipeline (poll interval, daily cost cap, model slug, prompt version) - Update lifecycle.ignore_changes to 4 image indices vault: re-enable pg-trading static role - Add pg-trading to vault_database_secret_backend_connection allowed_roles - Uncomment vault_database_secret_backend_static_role.pg_trading (was disabled 2026-04-06 with the rest of trading-bot stack) kyverno: add postgres* to trusted-registries allowlist - trading-bot db_init uses postgres:16-alpine (Docker Hub library image) - postgres* was not in the DockerHub bare-name allowlist (unlike mysql*, alpine*, nginx*, python* which were already there) Final workers Pod containers (in order): [0] signal-generator [1] learning-engine [2] market-data [3] meet-kevin-watcher (NEW) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d0a4876825
commit
854817e2e3
5 changed files with 84 additions and 145 deletions
|
|
@ -329,7 +329,7 @@ resource "kubectl_manifest" "policy_require_trusted_registries" {
|
|||
# Private
|
||||
"forgejo.viktorbarzin.me/*", "10.0.20.10*",
|
||||
# DockerHub library (bare image names without slash)
|
||||
"alpine*", "busybox*", "kong*", "mysql*", "nginx*", "python*",
|
||||
"alpine*", "busybox*", "kong*", "mysql*", "nginx*", "postgres*", "python*",
|
||||
# DockerHub user repos (no registry prefix, has slash) —
|
||||
# enumerated from current cluster state.
|
||||
"actualbudget/*", "afadil/*", "binwiederhier/*", "bitnami/*",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Generated by Terragrunt. Sig: nIlQXj57tbuaRZEa
|
||||
terraform {
|
||||
backend "pg" {
|
||||
conn_str = "postgres://terraform_state:ZCcWMOLCTqb0aV-XyTAZ@10.0.20.200:5432/terraform_state?sslmode=disable"
|
||||
conn_str = "postgres://terraform_state:LicuZK1nVl4ILE5HF-A9@10.0.20.200:5432/terraform_state?sslmode=disable"
|
||||
schema_name = "trading-bot"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
/*
|
||||
# TRADING-BOT STACK COMMENTED OUT - 2026-04-06
|
||||
# Deployments scaled to 0, infrastructure disabled to prevent re-creation on apply
|
||||
# To re-enable: uncomment this entire block
|
||||
|
||||
variable "tls_secret_name" {
|
||||
type = string
|
||||
sensitive = true
|
||||
|
|
@ -12,21 +7,25 @@ variable "postgresql_host" { type = string }
|
|||
variable "redis_host" { type = string }
|
||||
locals {
|
||||
common_env = {
|
||||
TRADING_REDIS_URL = "redis://${var.redis_host}:6379/4"
|
||||
TRADING_LOG_LEVEL = "INFO"
|
||||
TRADING_ALPACA_BASE_URL = "https://paper-api.alpaca.markets"
|
||||
TRADING_PAPER_TRADING = "true"
|
||||
TRADING_REDDIT_USER_AGENT = "trading-bot/0.1"
|
||||
TRADING_WATCHLIST = "[\"AAPL\",\"TSLA\",\"NVDA\",\"MSFT\",\"GOOGL\"]"
|
||||
TRADING_BAR_TIMEFRAME = "5Min"
|
||||
TRADING_POLL_INTERVAL_SECONDS = "60"
|
||||
TRADING_HISTORICAL_BARS = "100"
|
||||
TRADING_SNAPSHOT_INTERVAL_SECONDS = "60"
|
||||
TRADING_FUNDAMENTALS_CACHE_TTL_HOURS = "24"
|
||||
TRADING_RP_ID = "trading.viktorbarzin.me"
|
||||
TRADING_RP_NAME = "Trading Bot"
|
||||
TRADING_RP_ORIGIN = "https://trading.viktorbarzin.me"
|
||||
TRADING_CORS_ORIGINS = "[\"https://trading.viktorbarzin.me\"]"
|
||||
TRADING_REDIS_URL = "redis://${var.redis_host}:6379/4"
|
||||
TRADING_LOG_LEVEL = "INFO"
|
||||
TRADING_ALPACA_BASE_URL = "https://paper-api.alpaca.markets"
|
||||
TRADING_PAPER_TRADING = "true"
|
||||
TRADING_REDDIT_USER_AGENT = "trading-bot/0.1"
|
||||
TRADING_WATCHLIST = "[\"AAPL\",\"TSLA\",\"NVDA\",\"MSFT\",\"GOOGL\"]"
|
||||
TRADING_BAR_TIMEFRAME = "5Min"
|
||||
TRADING_POLL_INTERVAL_SECONDS = "60"
|
||||
TRADING_HISTORICAL_BARS = "100"
|
||||
TRADING_SNAPSHOT_INTERVAL_SECONDS = "60"
|
||||
TRADING_FUNDAMENTALS_CACHE_TTL_HOURS = "24"
|
||||
TRADING_RP_ID = "trading.viktorbarzin.me"
|
||||
TRADING_RP_NAME = "Trading Bot"
|
||||
TRADING_RP_ORIGIN = "https://trading.viktorbarzin.me"
|
||||
TRADING_CORS_ORIGINS = "[\"https://trading.viktorbarzin.me\"]"
|
||||
TRADING_MEET_KEVIN_POLL_INTERVAL_SECONDS = "10800"
|
||||
TRADING_MEET_KEVIN_DAILY_COST_CAP_USD = "5"
|
||||
TRADING_MEET_KEVIN_LLM_MODEL = "anthropic/claude-sonnet-4.5"
|
||||
TRADING_MEET_KEVIN_PROMPT_VERSION = "v1"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ resource "kubernetes_namespace" "trading-bot" {
|
|||
metadata {
|
||||
name = "trading-bot"
|
||||
labels = {
|
||||
tier = local.tiers.edge
|
||||
tier = local.tiers.edge
|
||||
"keel.sh/enrolled" = "true"
|
||||
}
|
||||
}
|
||||
|
|
@ -72,6 +71,8 @@ resource "kubernetes_manifest" "external_secret" {
|
|||
TRADING_ALPHA_VANTAGE_API_KEY = "{{ .alpha_vantage_api_key }}"
|
||||
TRADING_FMP_API_KEY = "{{ .fmp_api_key }}"
|
||||
DBAAS_ROOT_PASSWORD = "{{ .dbaas_root_password }}"
|
||||
TRADING_OPENROUTER_API_KEY = "{{ .openrouter_api_key }}"
|
||||
TRADING_MEET_KEVIN_CHANNEL_ID = "{{ .meet_kevin_channel_id }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +85,8 @@ resource "kubernetes_manifest" "external_secret" {
|
|||
{ secretKey = "alpha_vantage_api_key", remoteRef = { key = "trading-bot", property = "alpha_vantage_api_key" } },
|
||||
{ secretKey = "fmp_api_key", remoteRef = { key = "trading-bot", property = "fmp_api_key" } },
|
||||
{ secretKey = "dbaas_root_password", remoteRef = { key = "trading-bot", property = "dbaas_root_password" } },
|
||||
{ secretKey = "openrouter_api_key", remoteRef = { key = "trading-bot", property = "openrouter_api_key" } },
|
||||
{ secretKey = "meet_kevin_channel_id", remoteRef = { key = "trading-bot", property = "meet_kevin_channel_id" } },
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -143,14 +146,16 @@ resource "kubernetes_job" "db_init" {
|
|||
"sh", "-c",
|
||||
<<-EOT
|
||||
set -e
|
||||
# -d postgres: psql defaults database name to username; root user
|
||||
# doesn't have a root-named database, so be explicit.
|
||||
# Create role if not exists
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -tc "SELECT 1 FROM pg_roles WHERE rolname='trading'" | grep -q 1 || \
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -c "CREATE ROLE trading WITH LOGIN PASSWORD '$DB_PASSWORD'"
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -d postgres -tc "SELECT 1 FROM pg_roles WHERE rolname='trading'" | grep -q 1 || \
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -d postgres -c "CREATE ROLE trading WITH LOGIN PASSWORD '$DB_PASSWORD'"
|
||||
# Create database if not exists
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -tc "SELECT 1 FROM pg_database WHERE datname='trading'" | grep -q 1 || \
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -c "CREATE DATABASE trading OWNER trading"
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='trading'" | grep -q 1 || \
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -d postgres -c "CREATE DATABASE trading OWNER trading"
|
||||
# Grant privileges
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -c "GRANT ALL PRIVILEGES ON DATABASE trading TO trading"
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE trading TO trading"
|
||||
# Try to enable timescaledb (allow failure)
|
||||
PGPASSWORD="$DBAAS_ROOT_PASSWORD" psql -h ${var.postgresql_host} -U root -d trading -c "CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE" || true
|
||||
echo "Database init complete"
|
||||
|
|
@ -358,78 +363,6 @@ resource "kubernetes_deployment" "trading-bot-workers" {
|
|||
}
|
||||
}
|
||||
spec {
|
||||
container {
|
||||
name = "news-fetcher"
|
||||
image = "viktorbarzin/trading-bot-service:latest"
|
||||
image_pull_policy = "Always"
|
||||
command = ["python", "-m", "services.news_fetcher.main"]
|
||||
dynamic "env" {
|
||||
for_each = local.common_env
|
||||
content {
|
||||
name = env.key
|
||||
value = env.value
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "TRADING_OTEL_METRICS_PORT"
|
||||
value = "9091"
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-secrets"
|
||||
}
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-db-creds"
|
||||
}
|
||||
}
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "10m"
|
||||
memory = "128Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "256Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "sentiment-analyzer"
|
||||
image = "viktorbarzin/trading-bot-service:latest"
|
||||
image_pull_policy = "Always"
|
||||
command = ["python", "-m", "services.sentiment_analyzer.main"]
|
||||
dynamic "env" {
|
||||
for_each = local.common_env
|
||||
content {
|
||||
name = env.key
|
||||
value = env.value
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "TRADING_OTEL_METRICS_PORT"
|
||||
value = "9092"
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-secrets"
|
||||
}
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-db-creds"
|
||||
}
|
||||
}
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "100m"
|
||||
memory = "512Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "512Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "signal-generator"
|
||||
image = "viktorbarzin/trading-bot-service:latest"
|
||||
|
|
@ -466,42 +399,6 @@ resource "kubernetes_deployment" "trading-bot-workers" {
|
|||
}
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "trade-executor"
|
||||
image = "viktorbarzin/trading-bot-service:latest"
|
||||
image_pull_policy = "Always"
|
||||
command = ["python", "-m", "services.trade_executor.main"]
|
||||
dynamic "env" {
|
||||
for_each = local.common_env
|
||||
content {
|
||||
name = env.key
|
||||
value = env.value
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "TRADING_OTEL_METRICS_PORT"
|
||||
value = "9094"
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-secrets"
|
||||
}
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-db-creds"
|
||||
}
|
||||
}
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "10m"
|
||||
memory = "128Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "256Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "learning-engine"
|
||||
image = "viktorbarzin/trading-bot-service:latest"
|
||||
|
|
@ -574,18 +471,52 @@ resource "kubernetes_deployment" "trading-bot-workers" {
|
|||
}
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "meet-kevin-watcher"
|
||||
image = "viktorbarzin/trading-bot-service:latest"
|
||||
image_pull_policy = "Always"
|
||||
command = ["python", "-m", "services.meet_kevin_watcher.main"]
|
||||
dynamic "env" {
|
||||
for_each = local.common_env
|
||||
content {
|
||||
name = env.key
|
||||
value = env.value
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "TRADING_OTEL_METRICS_PORT"
|
||||
value = "9097"
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-secrets"
|
||||
}
|
||||
}
|
||||
env_from {
|
||||
secret_ref {
|
||||
name = "trading-bot-db-creds"
|
||||
}
|
||||
}
|
||||
resources {
|
||||
requests = {
|
||||
cpu = "10m"
|
||||
memory = "128Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "256Mi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycle {
|
||||
# DRIFT_WORKAROUND: CI pipeline owns image tags for all 6 worker containers. Reviewed 2026-04-18.
|
||||
# DRIFT_WORKAROUND: CI pipeline owns image tags for all 4 worker containers. Reviewed 2026-05-22.
|
||||
ignore_changes = [
|
||||
spec[0].template[0].spec[0].container[0].image,
|
||||
spec[0].template[0].spec[0].container[1].image,
|
||||
spec[0].template[0].spec[0].container[2].image,
|
||||
spec[0].template[0].spec[0].container[3].image,
|
||||
spec[0].template[0].spec[0].container[4].image,
|
||||
spec[0].template[0].spec[0].container[5].image,
|
||||
spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1: Kyverno admission webhook mutates dns_config with ndots=2
|
||||
]
|
||||
}
|
||||
|
|
@ -618,7 +549,7 @@ module "ingress" {
|
|||
name = "trading"
|
||||
service_name = "trading-bot-frontend"
|
||||
tls_secret_name = var.tls_secret_name
|
||||
auth = "required"
|
||||
auth = "required"
|
||||
extra_annotations = {
|
||||
"gethomepage.dev/enabled" = "true"
|
||||
"gethomepage.dev/name" = "Trading Bot"
|
||||
|
|
@ -628,6 +559,5 @@ module "ingress" {
|
|||
"gethomepage.dev/pod-selector" = ""
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
# CI retrigger v6 2026-05-16T23:18:58Z
|
||||
|
|
|
|||
|
|
@ -13,6 +13,13 @@ terraform {
|
|||
source = "goauthentik/authentik"
|
||||
version = "~> 2024.10"
|
||||
}
|
||||
# kubectl (gavinbunney) — workaround for hashicorp/kubernetes
|
||||
# `kubernetes_manifest` panics on Kyverno CRDs. See beads code-e2dp.
|
||||
# Declared for all stacks but only used where opted-in.
|
||||
kubectl = {
|
||||
source = "gavinbunney/kubectl"
|
||||
version = "~> 1.14"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,3 +42,8 @@ provider "vault" {
|
|||
address = "https://vault.viktorbarzin.me"
|
||||
skip_child_token = true
|
||||
}
|
||||
|
||||
provider "kubectl" {
|
||||
config_path = var.kube_config_path
|
||||
load_config_file = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -610,7 +610,7 @@ resource "vault_database_secret_backend_connection" "postgresql" {
|
|||
backend = vault_mount.database.path
|
||||
name = "postgresql"
|
||||
allowed_roles = [
|
||||
# "pg-trading", # Commented out 2026-04-06 - trading-bot disabled
|
||||
"pg-trading",
|
||||
"pg-health", "pg-linkwarden",
|
||||
"pg-affine", "pg-woodpecker", "pg-claude-memory",
|
||||
"pg-terraform-state", "pg-payslip-ingest", "pg-job-hunter",
|
||||
|
|
@ -696,8 +696,6 @@ resource "vault_database_secret_backend_static_role" "mysql_phpipam" {
|
|||
|
||||
# --- PostgreSQL Static Roles ---
|
||||
|
||||
/*
|
||||
# Commented out 2026-04-06 - trading-bot disabled
|
||||
resource "vault_database_secret_backend_static_role" "pg_trading" {
|
||||
backend = vault_mount.database.path
|
||||
db_name = vault_database_secret_backend_connection.postgresql.name
|
||||
|
|
@ -705,7 +703,6 @@ resource "vault_database_secret_backend_static_role" "pg_trading" {
|
|||
username = "trading"
|
||||
rotation_period = 604800
|
||||
}
|
||||
*/
|
||||
|
||||
resource "vault_database_secret_backend_static_role" "pg_health" {
|
||||
backend = vault_mount.database.path
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue