Files
SnapOtter/tests/benchmark/perf-stack.compose.yml
T

139 lines
4.2 KiB
YAML
Raw Normal View History

# Isolated stack for the non-functional performance, load and recovery lane.
#
# It mirrors the *shipped* `docker/docker-compose.yml` resource envelope on
# purpose: mem_limit 6g / cpus 4 / pids_limit 512 on the app, 1g/2cpu on
# Postgres and Redis. The whole point of this lane is to find out whether the
# shipped 6 GB app ceiling survives concurrent load, so the ceiling has to be
# real. Only three things deviate from the shipped file, each deliberate:
#
# 1. RATE_LIMIT_PER_MIN is lifted. The shipped 1000/min would throttle a
# 20-client tier and the resulting number would measure the limiter, not
# the processing engine.
# 2. PROCESSING_TIMEOUT_S is pinned to a finite 600 so a wedged job fails
# loudly instead of hanging the harness.
# 3. Names, ports and volumes are prefixed so this stack can never collide
# with an operator install or another QA lane on the same host.
#
# PERF_IMAGE must be an image reference that already resolves locally; the
# harness proves the running container's image ID before it records anything.
#
# PERF_IMAGE=snapotter-qa-f4c2bde9:arm64-20260726 \
# docker compose -p snapotter-qa-perf -f tests/benchmark/perf-stack.compose.yml up -d
name: ${PERF_PROJECT:-snapotter-qa-perf}
services:
app:
image: ${PERF_IMAGE:?PERF_IMAGE must name the image under test}
container_name: ${PERF_PROJECT:-snapotter-qa-perf}-app
ports:
- "127.0.0.1:${PERF_APP_PORT:-13496}:1349"
volumes:
- perf-data:/data
- perf-workspace:/tmp/workspace
environment:
- AUTH_ENABLED=true
- DEFAULT_USERNAME=admin
- DEFAULT_PASSWORD=${PERF_ADMIN_PASSWORD:?PERF_ADMIN_PASSWORD must be set}
- SKIP_MUST_CHANGE_PASSWORD=true
- RATE_LIMIT_PER_MIN=${PERF_RATE_LIMIT:-100000}
- PROCESSING_TIMEOUT_S=600
- MAX_UPLOAD_SIZE_MB=0
- MAX_BATCH_SIZE=0
- MAX_MEGAPIXELS=0
- CONCURRENT_JOBS=0
- MAX_WORKER_THREADS=0
- MAX_PIPELINE_STEPS=50
- ANALYTICS_ENABLED=false
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
- REDIS_URL=redis://:snapotter@redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
# Shipped envelope, verbatim.
mem_limit: ${PERF_APP_MEM:-6g}
memswap_limit: ${PERF_APP_MEM:-6g}
cpus: ${PERF_APP_CPUS:-4}
pids_limit: 512
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
- DAC_OVERRIDE
- FOWNER
- KILL
security_opt:
- no-new-privileges:true
shm_size: "2gb"
healthcheck:
test: ["CMD", "curl", "-sf", "--max-time", "5", "http://localhost:1349/api/v1/health"]
interval: 15s
timeout: 5s
start_period: 90s
retries: 5
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
postgres:
image: postgres:17-alpine@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193
container_name: ${PERF_PROJECT:-snapotter-qa-perf}-postgres
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_DB: snapotter
volumes:
- perf-pgdata:/var/lib/postgresql/data
mem_limit: 1g
memswap_limit: 1g
cpus: 2
pids_limit: 256
healthcheck:
test: ["CMD-SHELL", "pg_isready -U snapotter"]
interval: 10s
timeout: 5s
retries: 12
start_period: 15s
restart: unless-stopped
redis:
image: redis:8-alpine@sha256:9d317178eceac8454a2284a9e6df2466b93c745529947f0cd42a0fa9609d7005
container_name: ${PERF_PROJECT:-snapotter-qa-perf}-redis
command:
[
"redis-server",
"--maxmemory-policy",
"noeviction",
"--maxmemory",
"512mb",
"--appendonly",
"yes",
"--requirepass",
"snapotter",
]
volumes:
- perf-redisdata:/data
mem_limit: 1g
memswap_limit: 1g
cpus: 2
pids_limit: 256
healthcheck:
test: ["CMD", "redis-cli", "-a", "snapotter", "--no-auth-warning", "ping"]
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
restart: unless-stopped
volumes:
perf-data:
perf-workspace:
perf-pgdata:
perf-redisdata: