TrueNAS SCALE deployment: GHCR image publishing + pull-only compose
TrueNAS custom apps cannot build: the main compose's 'build: .' (plus relative .env/bind mounts) fails app 'up'. Added a GitHub Actions workflow publishing ghcr.io/fez5587/momentum-app on every master push, and deploy/docker/truenas-compose.yml — a pull-only variant with dataset host-paths, inline environment (secrets as <FILL-ME> placeholders, current validated strategy knobs pre-filled), and the same healthchecks. Validated with docker compose config. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
8ba4899108
commit
e563380f28
2 files changed
+149
No files matched your search
@@ -0,0 +1,34 @@
|
|||||||
|
name: docker-image
|
||||||
|
|
||||||
|
# Build + push the app image to GHCR on every master push, so pull-only
|
||||||
|
# hosts (TrueNAS SCALE custom apps) can deploy without a repo checkout.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- "Dockerfile"
|
||||||
|
- "requirements.txt"
|
||||||
|
- "**.py"
|
||||||
|
- ".github/workflows/docker.yml"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
ghcr.io/fez5587/momentum-app:latest
|
||||||
|
ghcr.io/fez5587/momentum-app:${{ github.sha }}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# Momentum stack for TrueNAS SCALE (Apps -> Discover Apps -> Custom App -> YAML).
|
||||||
|
#
|
||||||
|
# PULL-ONLY: TrueNAS custom apps cannot `build:` — the image comes from GHCR
|
||||||
|
# (published by .github/workflows/docker.yml on every master push). Make the
|
||||||
|
# ghcr.io/fez5587/momentum-app package PUBLIC once (GitHub -> Packages ->
|
||||||
|
# momentum-app -> Package settings -> Change visibility), or add registry
|
||||||
|
# credentials in TrueNAS (Apps -> Settings -> Manage Container Images).
|
||||||
|
#
|
||||||
|
# BEFORE DEPLOYING:
|
||||||
|
# 1. Create a dataset for the stack, e.g. /mnt/<pool>/apps/momentum
|
||||||
|
# with subdirs: data/ pgdata/
|
||||||
|
# 2. Replace /mnt/tank/apps/momentum below with your dataset path.
|
||||||
|
# 3. Fill every <FILL-ME> in the environment block (these are the secrets
|
||||||
|
# you wanted to manage from a protected space — TrueNAS stores the YAML
|
||||||
|
# server-side, or mount an env file from a restricted dataset instead).
|
||||||
|
#
|
||||||
|
# TZ is America/New_York: the loop's market clock thinks in ET.
|
||||||
|
|
||||||
|
x-app: &app
|
||||||
|
image: ghcr.io/fez5587/momentum-app:latest
|
||||||
|
environment: &app-env
|
||||||
|
TZ: America/New_York
|
||||||
|
# ---- infra
|
||||||
|
DATABASE_URL: postgresql://momentum:<FILL-ME-PG-PASSWORD>@postgres:5432/momentum
|
||||||
|
PG_SKIP_SCHEMA: "0"
|
||||||
|
OLLAMA_HOST: http://192.168.1.9:11434
|
||||||
|
ALPACA_DATA_FEED: sip
|
||||||
|
# ---- secrets
|
||||||
|
ALPACA_API_KEY: <FILL-ME>
|
||||||
|
ALPACA_SECRET_KEY: <FILL-ME>
|
||||||
|
ALPACA_BASE_URL: https://paper-api.alpaca.markets
|
||||||
|
TELEGRAM_BOT_TOKEN: <FILL-ME>
|
||||||
|
TELEGRAM_CHAT_ID: <FILL-ME>
|
||||||
|
YOUTUBE_API_KEY: <FILL-ME>
|
||||||
|
# ---- strategy knobs (current validated config, 2026-07-09; full
|
||||||
|
# inventory with comments: .env.example in the repo)
|
||||||
|
TRIGGER_GAP_MIN: "10.0"
|
||||||
|
TRIGGER_GAP_MAX: "35"
|
||||||
|
TRIGGER_GAP_SQUEEZE_MIN: "150"
|
||||||
|
TRIGGER_GAP_SQUEEZE_RVOL: "5.0"
|
||||||
|
TRADING_MIN_ENTRY_GAP_PCT: "0.10"
|
||||||
|
TRADING_MIN_DAY_VOLUME: "300000"
|
||||||
|
TRADING_PRICE_MIN: "2.0"
|
||||||
|
TRADING_PRICE_MAX: "20.0"
|
||||||
|
TRADING_MIN_QUALITY_SCORE: "0.60"
|
||||||
|
TRADING_MAX_FRESH_ENTRIES_PER_DAY: "10"
|
||||||
|
TRADING_ENTRY_CONFIRM_BY_MINUTE: "0"
|
||||||
|
volumes:
|
||||||
|
- /mnt/tank/apps/momentum/data:/app/data
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:18
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: momentum
|
||||||
|
POSTGRES_PASSWORD: <FILL-ME-PG-PASSWORD>
|
||||||
|
POSTGRES_DB: momentum
|
||||||
|
PGDATA: /var/lib/postgresql/data/pgdata
|
||||||
|
volumes:
|
||||||
|
- /mnt/tank/apps/momentum/pgdata:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U momentum -d momentum"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
loop:
|
||||||
|
<<: *app
|
||||||
|
command: ["python", "-u", "run_live_paper.py", "--no-dashboard"]
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "python", "-c", "import datetime,sys; from research.multi_schema import open_research_db; r=open_research_db('market').execute('SELECT max(timestamp) FROM events').fetchall()[0][0]; sys.exit(0 if r and (datetime.datetime.now()-r).total_seconds()<300 else 1)"]
|
||||||
|
interval: 60s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 5
|
||||||
|
start_period: 180s
|
||||||
|
|
||||||
|
dashboard:
|
||||||
|
<<: *app
|
||||||
|
command: ["python", "-u", "dashboard_api.py"]
|
||||||
|
environment:
|
||||||
|
<<: *app-env
|
||||||
|
DASHBOARD_HOST: "0.0.0.0"
|
||||||
|
DASHBOARD_PORT: "8765"
|
||||||
|
ports:
|
||||||
|
- "8765:8765"
|
||||||
|
|
||||||
|
qabot:
|
||||||
|
<<: *app
|
||||||
|
command: ["python", "-u", "telegram_bot.py"]
|
||||||
|
|
||||||
|
transcripts:
|
||||||
|
<<: *app
|
||||||
|
command: ["python", "-u", "-m", "youtube_claims.run", "run"]
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
<<: *app
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "[scheduler] up; fires 20:00 ET Mon-Fri"
|
||||||
|
while true; do
|
||||||
|
if [ "$$(date +%H:%M)" = "20:00" ] && [ "$$(date +%u)" -le 5 ]; then
|
||||||
|
python -m research.premarket_eval || echo "[scheduler] eval FAILED"
|
||||||
|
sleep 120
|
||||||
|
fi
|
||||||
|
sleep 20
|
||||||
|
done
|
||||||
Reference in new issue
Block a user