🧠 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:
257
infrastructure/ansible/playbooks/postgres-ha.yml
Normal file
257
infrastructure/ansible/playbooks/postgres-ha.yml
Normal 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
|
||||
120
infrastructure/ansible/templates/patroni.yml.j2
Normal file
120
infrastructure/ansible/templates/patroni.yml.j2
Normal 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
|
||||
40
infrastructure/ansible/templates/pgbackrest.conf.j2
Normal file
40
infrastructure/ansible/templates/pgbackrest.conf.j2
Normal 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
|
||||
44
infrastructure/ansible/templates/pgbouncer.ini.j2
Normal file
44
infrastructure/ansible/templates/pgbouncer.ini.j2
Normal 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
|
||||
Reference in New Issue
Block a user