🧠 Add Agent Memory System with PostgreSQL + Qdrant + Cohere

Features:
- Three-tier memory architecture (short/mid/long-term)
- PostgreSQL schema for conversations, events, memories
- Qdrant vector database for semantic search
- Cohere embeddings (embed-multilingual-v3.0, 1024 dims)
- FastAPI Memory Service with full CRUD
- External Secrets integration with Vault
- Kubernetes deployment manifests

Components:
- infrastructure/database/agent-memory-schema.sql
- infrastructure/kubernetes/apps/qdrant/
- infrastructure/kubernetes/apps/memory-service/
- services/memory-service/ (FastAPI app)

Also includes:
- External Secrets Operator
- Traefik Ingress Controller
- Cert-Manager with Let's Encrypt
- ArgoCD for GitOps
This commit is contained in:
Apple
2026-01-10 07:52:32 -08:00
parent 12545a7c76
commit 90758facae
16 changed files with 2769 additions and 579 deletions

View File

@@ -0,0 +1,257 @@
# DAARION Network - PostgreSQL HA Setup
# Patroni + PgBouncer + pgBackRest + Monitoring
---
# =============================================================================
# POSTGRESQL HA WITH PATRONI
# =============================================================================
- name: Setup PostgreSQL HA Cluster
hosts: database_nodes
become: yes
vars:
# Patroni
patroni_version: "3.2.0"
patroni_scope: "daarion-cluster"
patroni_namespace: "/daarion"
# PostgreSQL
postgres_version: "16"
postgres_data_dir: "/var/lib/postgresql/{{ postgres_version }}/main"
postgres_config_dir: "/etc/postgresql/{{ postgres_version }}/main"
# PgBouncer
pgbouncer_port: 6432
pgbouncer_max_client_conn: 1000
pgbouncer_default_pool_size: 50
# Backup
pgbackrest_repo_path: "/var/lib/pgbackrest"
pgbackrest_s3_bucket: "daarion-backups"
# Consul for DCS
consul_host: "{{ hostvars[groups['masters'][0]].ansible_host }}"
tasks:
# =========================================================================
# PREREQUISITES
# =========================================================================
- name: Add PostgreSQL APT repository
shell: |
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/postgresql-keyring.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
args:
creates: /etc/apt/sources.list.d/pgdg.list
- name: Update apt cache
apt:
update_cache: yes
- name: Install PostgreSQL and dependencies
apt:
name:
- postgresql-{{ postgres_version }}
- postgresql-contrib-{{ postgres_version }}
- python3-pip
- python3-psycopg2
- python3-consul
- pgbouncer
- pgbackrest
state: present
# =========================================================================
# PATRONI INSTALLATION
# =========================================================================
- name: Install Patroni
pip:
name:
- patroni[consul]=={{ patroni_version }}
- python-consul
state: present
- name: Create Patroni directories
file:
path: "{{ item }}"
state: directory
owner: postgres
group: postgres
mode: '0750'
loop:
- /etc/patroni
- /var/log/patroni
- name: Configure Patroni
template:
src: templates/patroni.yml.j2
dest: /etc/patroni/patroni.yml
owner: postgres
group: postgres
mode: '0640'
notify: restart patroni
- name: Create Patroni systemd service
copy:
dest: /etc/systemd/system/patroni.service
content: |
[Unit]
Description=Patroni PostgreSQL Cluster Manager
After=network.target consul.service
[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=on-failure
[Install]
WantedBy=multi-user.target
notify:
- reload systemd
- restart patroni
# =========================================================================
# PGBOUNCER
# =========================================================================
- name: Configure PgBouncer
template:
src: templates/pgbouncer.ini.j2
dest: /etc/pgbouncer/pgbouncer.ini
owner: postgres
group: postgres
mode: '0640'
notify: restart pgbouncer
- name: Configure PgBouncer userlist
copy:
dest: /etc/pgbouncer/userlist.txt
content: |
"{{ postgres_user }}" "{{ postgres_password }}"
"pgbouncer" "{{ pgbouncer_password | default('pgbouncer_secret') }}"
owner: postgres
group: postgres
mode: '0600'
notify: restart pgbouncer
- name: Enable PgBouncer
service:
name: pgbouncer
enabled: yes
state: started
# =========================================================================
# PGBACKREST
# =========================================================================
- name: Create pgBackRest directories
file:
path: "{{ item }}"
state: directory
owner: postgres
group: postgres
mode: '0750'
loop:
- "{{ pgbackrest_repo_path }}"
- /var/log/pgbackrest
- name: Configure pgBackRest
template:
src: templates/pgbackrest.conf.j2
dest: /etc/pgbackrest.conf
owner: postgres
group: postgres
mode: '0640'
- name: Setup backup cron
cron:
name: "Daily PostgreSQL backup"
hour: "2"
minute: "0"
user: postgres
job: "pgbackrest --stanza={{ patroni_scope }} --type=diff backup >> /var/log/pgbackrest/backup.log 2>&1"
- name: Setup weekly full backup
cron:
name: "Weekly full PostgreSQL backup"
weekday: "0"
hour: "3"
minute: "0"
user: postgres
job: "pgbackrest --stanza={{ patroni_scope }} --type=full backup >> /var/log/pgbackrest/backup.log 2>&1"
# =========================================================================
# MONITORING
# =========================================================================
- name: Install postgres_exporter
shell: |
curl -sL https://github.com/prometheus-community/postgres_exporter/releases/download/v0.15.0/postgres_exporter-0.15.0.linux-amd64.tar.gz | tar xz
mv postgres_exporter-0.15.0.linux-amd64/postgres_exporter /usr/local/bin/
rm -rf postgres_exporter-0.15.0.linux-amd64
args:
creates: /usr/local/bin/postgres_exporter
- name: Create postgres_exporter systemd service
copy:
dest: /etc/systemd/system/postgres_exporter.service
content: |
[Unit]
Description=Prometheus PostgreSQL Exporter
After=network.target postgresql.service
[Service]
Type=simple
User=postgres
Environment="DATA_SOURCE_NAME=postgresql://{{ postgres_user }}:{{ postgres_password }}@localhost:5432/{{ postgres_db }}?sslmode=disable"
ExecStart=/usr/local/bin/postgres_exporter --web.listen-address=:9187
Restart=on-failure
[Install]
WantedBy=multi-user.target
notify:
- reload systemd
- restart postgres_exporter
- name: Enable postgres_exporter
service:
name: postgres_exporter
enabled: yes
state: started
# =========================================================================
# VERIFICATION
# =========================================================================
- name: Show PostgreSQL HA status
debug:
msg: |
PostgreSQL HA Setup Complete!
Components:
- Patroni: Cluster management
- PgBouncer: Connection pooling (port {{ pgbouncer_port }})
- pgBackRest: Backups
- postgres_exporter: Metrics (port 9187)
Connection strings:
- Direct: postgresql://{{ postgres_user }}@{{ ansible_host }}:5432/{{ postgres_db }}
- Pooled: postgresql://{{ postgres_user }}@{{ ansible_host }}:{{ pgbouncer_port }}/{{ postgres_db }}
handlers:
- name: reload systemd
systemd:
daemon_reload: yes
- name: restart patroni
service:
name: patroni
state: restarted
- name: restart pgbouncer
service:
name: pgbouncer
state: restarted
- name: restart postgres_exporter
service:
name: postgres_exporter
state: restarted

View File

@@ -0,0 +1,120 @@
# Patroni Configuration for {{ inventory_hostname }}
# Generated by Ansible
scope: {{ patroni_scope }}
namespace: {{ patroni_namespace }}
name: {{ inventory_hostname }}
restapi:
listen: 0.0.0.0:8008
connect_address: {{ ansible_host }}:8008
consul:
host: {{ consul_host }}:8500
register_service: true
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
# Performance
max_connections: 200
shared_buffers: 256MB
effective_cache_size: 768MB
maintenance_work_mem: 64MB
checkpoint_completion_target: 0.9
wal_buffers: 16MB
default_statistics_target: 100
random_page_cost: 1.1
effective_io_concurrency: 200
work_mem: 2621kB
huge_pages: off
min_wal_size: 1GB
max_wal_size: 4GB
max_worker_processes: 4
max_parallel_workers_per_gather: 2
max_parallel_workers: 4
max_parallel_maintenance_workers: 2
# Replication
wal_level: replica
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
hot_standby_feedback: "on"
# Logging
log_destination: 'stderr'
logging_collector: 'on'
log_directory: 'log'
log_filename: 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age: '1d'
log_rotation_size: '100MB'
log_min_duration_statement: 1000
log_checkpoints: 'on'
log_connections: 'on'
log_disconnections: 'on'
log_lock_waits: 'on'
# Archive (for pgBackRest)
archive_mode: "on"
archive_command: 'pgbackrest --stanza={{ patroni_scope }} archive-push %p'
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 0.0.0.0/0 scram-sha-256
- host all all 0.0.0.0/0 scram-sha-256
users:
{{ postgres_user }}:
password: {{ postgres_password }}
options:
- createrole
- createdb
replicator:
password: {{ replicator_password | default('replicator_secret') }}
options:
- replication
postgresql:
listen: 0.0.0.0:5432
connect_address: {{ ansible_host }}:5432
data_dir: {{ postgres_data_dir }}
bin_dir: /usr/lib/postgresql/{{ postgres_version }}/bin
config_dir: {{ postgres_config_dir }}
pgpass: /var/lib/postgresql/.pgpass
authentication:
replication:
username: replicator
password: {{ replicator_password | default('replicator_secret') }}
superuser:
username: postgres
password: {{ postgres_superuser_password | default('postgres_secret') }}
rewind:
username: rewind
password: {{ rewind_password | default('rewind_secret') }}
parameters:
unix_socket_directories: '/var/run/postgresql'
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 scram-sha-256
- host all all 0.0.0.0/0 scram-sha-256
- host replication replicator 0.0.0.0/0 scram-sha-256
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false

View File

@@ -0,0 +1,40 @@
# pgBackRest Configuration for {{ inventory_hostname }}
# Generated by Ansible
[global]
# Repository
repo1-path={{ pgbackrest_repo_path }}
repo1-retention-full=2
repo1-retention-diff=7
# S3 (optional - uncomment for cloud backups)
# repo2-type=s3
# repo2-path=/backup
# repo2-s3-bucket={{ pgbackrest_s3_bucket }}
# repo2-s3-endpoint=s3.eu-central-1.amazonaws.com
# repo2-s3-region=eu-central-1
# repo2-s3-key={{ pgbackrest_s3_key | default('') }}
# repo2-s3-key-secret={{ pgbackrest_s3_secret | default('') }}
# repo2-retention-full=4
# repo2-retention-diff=14
# Compression
compress-type=zst
compress-level=3
# Parallel
process-max=4
# Logging
log-level-console=info
log-level-file=detail
log-path=/var/log/pgbackrest
# Archive
archive-async=y
archive-push-queue-max=4GB
[{{ patroni_scope }}]
pg1-path={{ postgres_data_dir }}
pg1-port=5432
pg1-user=postgres

View File

@@ -0,0 +1,44 @@
# PgBouncer Configuration for {{ inventory_hostname }}
# Generated by Ansible
[databases]
{{ postgres_db }} = host=127.0.0.1 port=5432 dbname={{ postgres_db }}
* = host=127.0.0.1 port=5432
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = {{ pgbouncer_port }}
unix_socket_dir = /var/run/postgresql
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
# Pool settings
pool_mode = transaction
max_client_conn = {{ pgbouncer_max_client_conn }}
default_pool_size = {{ pgbouncer_default_pool_size }}
min_pool_size = 10
reserve_pool_size = 5
reserve_pool_timeout = 3
# Timeouts
server_connect_timeout = 15
server_idle_timeout = 600
server_lifetime = 3600
client_idle_timeout = 0
client_login_timeout = 60
query_timeout = 0
query_wait_timeout = 120
# Logging
log_connections = 1
log_disconnections = 1
log_pooler_errors = 1
stats_period = 60
# Admin
admin_users = pgbouncer,{{ postgres_user }}
stats_users = pgbouncer,{{ postgres_user }}
# Security
ignore_startup_parameters = extra_float_digits