mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-25 09:24:54 +10:00
initial commit of v5
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
FROM postgres:latest
|
||||
|
||||
COPY ./postgresql.conf /etc/postgresql/postgresql.conf
|
||||
|
||||
COPY ./init.sql /docker-entrypoint-initdb.d/
|
||||
|
||||
RUN chown postgres:postgres /etc/postgresql/postgresql.conf && \
|
||||
chmod 644 /etc/postgresql/postgresql.conf
|
||||
|
||||
EXPOSE 5432
|
||||
|
||||
CMD ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]
|
||||
@@ -0,0 +1,46 @@
|
||||
-- Enable pg_stat_statements extension
|
||||
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
|
||||
|
||||
-- Enable other useful extensions
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID generation
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Cryptographic functions
|
||||
CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- GIN indexes for btree types
|
||||
CREATE EXTENSION IF NOT EXISTS "btree_gist"; -- GIST indexes for btree types
|
||||
|
||||
-- Create a function to reset pg_stat_statements (useful for debugging)
|
||||
CREATE OR REPLACE FUNCTION reset_query_stats()
|
||||
RETURNS void AS $$
|
||||
BEGIN
|
||||
PERFORM pg_stat_statements_reset();
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Create a view for easier query analysis
|
||||
CREATE OR REPLACE VIEW slow_queries AS
|
||||
SELECT
|
||||
query,
|
||||
calls,
|
||||
ROUND(total_exec_time::numeric, 2) AS total_time_ms,
|
||||
ROUND(mean_exec_time::numeric, 2) AS mean_time_ms,
|
||||
ROUND(max_exec_time::numeric, 2) AS max_time_ms,
|
||||
ROUND((100 * total_exec_time / SUM(total_exec_time) OVER ())::numeric, 2) AS percentage,
|
||||
rows
|
||||
FROM pg_stat_statements
|
||||
ORDER BY total_exec_time DESC;
|
||||
|
||||
-- Create a view for most frequent queries
|
||||
CREATE OR REPLACE VIEW frequent_queries AS
|
||||
SELECT
|
||||
query,
|
||||
calls,
|
||||
ROUND(mean_exec_time::numeric, 2) AS mean_time_ms,
|
||||
ROUND(total_exec_time::numeric, 2) AS total_time_ms,
|
||||
rows
|
||||
FROM pg_stat_statements
|
||||
ORDER BY calls DESC;
|
||||
|
||||
-- Notification for successful initialization
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'Database initialized with pg_stat_statements and helper views';
|
||||
END $$;
|
||||
@@ -0,0 +1,122 @@
|
||||
# -----------------------------
|
||||
# PostgreSQL 18 configuration file
|
||||
# Optimized for: 8GB RAM, 6 vCPU, KVM Virtual Machine
|
||||
# -----------------------------
|
||||
|
||||
# CONNECTIONS AND AUTHENTICATION
|
||||
listen_addresses = '*'
|
||||
max_connections = 100
|
||||
superuser_reserved_connections = 3
|
||||
|
||||
# MEMORY SETTINGS
|
||||
shared_buffers = 2GB
|
||||
huge_pages = try
|
||||
effective_cache_size = 6GB
|
||||
maintenance_work_mem = 512MB
|
||||
work_mem = 20MB
|
||||
|
||||
# QUERY TUNING
|
||||
random_page_cost = 1.1
|
||||
effective_io_concurrency = 200
|
||||
default_statistics_target = 100
|
||||
|
||||
# WRITE AHEAD LOG (WAL)
|
||||
wal_level = replica
|
||||
wal_buffers = 16MB
|
||||
min_wal_size = 1GB
|
||||
max_wal_size = 4GB
|
||||
wal_compression = on
|
||||
checkpoint_completion_target = 0.9
|
||||
checkpoint_timeout = 15min
|
||||
|
||||
# BACKGROUND WRITER
|
||||
bgwriter_delay = 200ms
|
||||
bgwriter_lru_maxpages = 100
|
||||
bgwriter_lru_multiplier = 2.0
|
||||
|
||||
# AUTOVACUUM
|
||||
autovacuum = on
|
||||
autovacuum_max_workers = 3
|
||||
autovacuum_naptime = 1min
|
||||
autovacuum_vacuum_threshold = 50
|
||||
autovacuum_vacuum_scale_factor = 0.1
|
||||
autovacuum_analyze_threshold = 50
|
||||
autovacuum_analyze_scale_factor = 0.05
|
||||
autovacuum_vacuum_cost_delay = 2ms
|
||||
autovacuum_vacuum_cost_limit = 200
|
||||
|
||||
# MONITORING AND STATISTICS
|
||||
track_activities = on
|
||||
track_counts = on
|
||||
track_io_timing = on
|
||||
track_functions = all
|
||||
track_wal_io_timing = on
|
||||
compute_query_id = on
|
||||
|
||||
# pg_stat_statements configuration
|
||||
pg_stat_statements.track = all
|
||||
pg_stat_statements.max = 10000
|
||||
pg_stat_statements.track_utility = on
|
||||
pg_stat_statements.save = on
|
||||
|
||||
# LOGGING
|
||||
log_destination = 'stderr'
|
||||
logging_collector = on
|
||||
log_directory = 'log'
|
||||
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
|
||||
log_file_mode = 0600
|
||||
log_rotation_age = 1d
|
||||
log_rotation_size = 100MB
|
||||
log_truncate_on_rotation = on
|
||||
|
||||
# What to log
|
||||
log_min_duration_statement = 1000
|
||||
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
|
||||
log_checkpoints = on
|
||||
log_connections = on
|
||||
log_disconnections = on
|
||||
log_duration = off
|
||||
log_lock_waits = on
|
||||
log_statement = 'none'
|
||||
log_temp_files = 0
|
||||
log_timezone = 'UTC'
|
||||
|
||||
# LOCALE AND FORMATTING
|
||||
datestyle = 'iso, mdy'
|
||||
timezone = 'UTC'
|
||||
lc_messages = 'en_US.utf8'
|
||||
lc_monetary = 'en_US.utf8'
|
||||
lc_numeric = 'en_US.utf8'
|
||||
lc_time = 'en_US.utf8'
|
||||
default_text_search_config = 'pg_catalog.english'
|
||||
|
||||
# LOCK MANAGEMENT
|
||||
deadlock_timeout = 1s
|
||||
max_locks_per_transaction = 64
|
||||
max_pred_locks_per_transaction = 64
|
||||
|
||||
# CLIENT CONNECTION DEFAULTS
|
||||
search_path = '"$user", public'
|
||||
idle_in_transaction_session_timeout = 600000
|
||||
statement_timeout = 0
|
||||
|
||||
# PARALLEL QUERY EXECUTION
|
||||
max_worker_processes = 6
|
||||
max_parallel_workers_per_gather = 3
|
||||
max_parallel_workers = 6
|
||||
max_parallel_maintenance_workers = 3
|
||||
parallel_leader_participation = on
|
||||
|
||||
# INCREMENTAL BACKUP
|
||||
summarize_wal = on
|
||||
|
||||
# VACUUM OPTIMIZATION
|
||||
vacuum_buffer_usage_limit = 256kB
|
||||
|
||||
# VECTOR EXTENSION SETTINGS
|
||||
maintenance_work_mem = 512MB
|
||||
max_parallel_maintenance_workers = 3
|
||||
work_mem = 32MB
|
||||
|
||||
# EXTENSIONS
|
||||
shared_preload_libraries = 'pg_stat_statements'
|
||||
@@ -0,0 +1,206 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:18
|
||||
command: postgres -c config_file=/etc/postgresql.conf
|
||||
networks:
|
||||
- reactive_resume_network
|
||||
volumes:
|
||||
- reactive_resume_postgres_data:/var/lib/postgresql
|
||||
environment:
|
||||
- POSTGRES_DB=$POSTGRES_DB
|
||||
- POSTGRES_USER=$POSTGRES_USER
|
||||
- POSTGRES_PASSWORD=$POSTGRES_PASSWORD
|
||||
configs:
|
||||
- source: reactive_resume_postgres_config
|
||||
target: /etc/postgresql.conf
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
window: 120s
|
||||
|
||||
gotenberg:
|
||||
image: gotenberg/gotenberg:8
|
||||
networks:
|
||||
- reactive_resume_network
|
||||
environment:
|
||||
- WEBHOOK_DISABLE=true
|
||||
- CHROMIUM_AUTO_START=true
|
||||
- API_ENABLE_BASIC_AUTH=true
|
||||
- PROMETHEUS_DISABLE_COLLECT=true
|
||||
- GOTENBERG_API_BASIC_AUTH_USERNAME=$GOTENBERG_USERNAME
|
||||
- GOTENBERG_API_BASIC_AUTH_PASSWORD=$GOTENBERG_PASSWORD
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 2
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
window: 120s
|
||||
|
||||
seaweedfs:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
command: server -s3 -filer -dir=/data -ip=0.0.0.0
|
||||
networks:
|
||||
- reactive_resume_network
|
||||
volumes:
|
||||
- reactive_resume_seaweedfs_data:/data
|
||||
environment:
|
||||
- AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
|
||||
- AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8888"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
window: 120s
|
||||
|
||||
seaweedfs_create_bucket:
|
||||
image: quay.io/minio/mc:latest
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
until mc alias set seaweedfs http://seaweedfs:8333 $S3_ACCESS_KEY_ID $S3_SECRET_ACCESS_KEY; do
|
||||
echo 'Waiting for SeaweedFS...';
|
||||
sleep 2;
|
||||
done;
|
||||
mc mb seaweedfs/$S3_BUCKET --ignore-existing;
|
||||
"
|
||||
networks:
|
||||
- reactive_resume_network
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 10s
|
||||
max_attempts: 5
|
||||
window: 120s
|
||||
|
||||
app:
|
||||
image: ghcr.io/amruthpillai/reactive-resume-test:latest
|
||||
networks:
|
||||
- traefik_network
|
||||
- reactive_resume_network
|
||||
volumes:
|
||||
- reactive_resume_app_data:/app/data
|
||||
environment:
|
||||
- APP_URL=$APP_URL
|
||||
- GOTENBERG_ENDPOINT=$GOTENBERG_ENDPOINT
|
||||
- GOTENBERG_USERNAME=$GOTENBERG_USERNAME
|
||||
- GOTENBERG_PASSWORD=$GOTENBERG_PASSWORD
|
||||
- DATABASE_URL=$DATABASE_URL
|
||||
- AUTH_SECRET=$AUTH_SECRET
|
||||
- GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID
|
||||
- GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET
|
||||
- GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID
|
||||
- GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET
|
||||
- SMTP_HOST=$SMTP_HOST
|
||||
- SMTP_PORT=$SMTP_PORT
|
||||
- SMTP_USER=$SMTP_USER
|
||||
- SMTP_PASS=$SMTP_PASS
|
||||
- SMTP_FROM=$SMTP_FROM
|
||||
- SMTP_SECURE=$SMTP_SECURE
|
||||
- S3_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
|
||||
- S3_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY
|
||||
- S3_REGION=$S3_REGION
|
||||
- S3_ENDPOINT=$S3_ENDPOINT
|
||||
- S3_BUCKET=$S3_BUCKET
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"node",
|
||||
"-e",
|
||||
"fetch('http://localhost:3000/api/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))",
|
||||
]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 2
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
window: 120s
|
||||
update_config:
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
failure_action: rollback
|
||||
order: start-first
|
||||
rollback_config:
|
||||
parallelism: 1
|
||||
delay: 10s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.app.rule=Host(`rxresu.me`)"
|
||||
- "traefik.http.routers.app.entrypoints=websecure"
|
||||
- "traefik.http.routers.app.tls=true"
|
||||
- "traefik.http.services.app.loadbalancer.server.port=3000"
|
||||
|
||||
configs:
|
||||
reactive_resume_postgres_config:
|
||||
name: reactive_resume_postgres_config
|
||||
external: true
|
||||
|
||||
networks:
|
||||
traefik_network:
|
||||
external: true
|
||||
reactive_resume_network:
|
||||
name: reactive_resume_network
|
||||
driver: overlay
|
||||
attachable: true
|
||||
|
||||
volumes:
|
||||
reactive_resume_postgres_data:
|
||||
name: reactive_resume_postgres_data
|
||||
reactive_resume_seaweedfs_data:
|
||||
name: reactive_resume_seaweedfs_data
|
||||
reactive_resume_app_data:
|
||||
name: reactive_resume_app_data
|
||||
Reference in New Issue
Block a user