Add multi-service deployment stack for TRM platform
Initial pilot stack: redis + tcp-ingestion. Designed to grow as the platform's other services land (processor, postgres+timescale, directus, react-spa). - compose.yaml: services as image: references with env-var-driven tags and ports. Redis is internal-only (no host port). TCP port 5027 exposed for GPS device traffic. Persisted Redis volume. - .env.example: documents TCP_INGESTION_TAG, INSTANCE_ID, PORT, LOG_LEVEL. Compose has defaults so the stack starts with no env config. - README: Portainer Repository Stack instructions, manual deploy fallback, network model, planned-services list, why-separate-repo rationale. - .gitignore: ignore .env
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
# Copy to `.env` for local docker-compose runs, OR enter these values in
|
||||||
|
# Portainer's Stack → Environment variables UI.
|
||||||
|
#
|
||||||
|
# All variables have defaults baked into compose.yaml — this file is the
|
||||||
|
# documentation of what's configurable, not a hard requirement.
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# tcp-ingestion
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Image tag to pull. `main` auto-tracks the latest commit on the main branch.
|
||||||
|
# In production, pin to a specific commit SHA for reproducibility.
|
||||||
|
# Example: TCP_INGESTION_TAG=af06973
|
||||||
|
TCP_INGESTION_TAG=main
|
||||||
|
|
||||||
|
# Instance identifier — must be stable across the lifetime of the process.
|
||||||
|
# Phase 2's connection registry depends on this; keep it unique per deployed
|
||||||
|
# instance (e.g. `stage-1`, `stage-2`, `prod-eu-1`).
|
||||||
|
TCP_INGESTION_INSTANCE_ID=stage-1
|
||||||
|
|
||||||
|
# Host port that GPS devices connect to. The container always listens on 5027
|
||||||
|
# internally; this maps it to a host port. If multiple stacks run on one host,
|
||||||
|
# give each a distinct host port (e.g. 5028, 5029).
|
||||||
|
TCP_INGESTION_PORT=5027
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Shared
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
# pino log level: fatal | error | warn | info | debug | trace
|
||||||
|
LOG_LEVEL=info
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
*.log
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# TRM Deploy
|
||||||
|
|
||||||
|
Deployment configuration for the TRM platform. This repo holds the multi-service `compose.yaml` and per-environment overrides; service code lives in sibling repos under `git.dev.microservices.al/trm/`.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
deploy/
|
||||||
|
├── compose.yaml ← Portainer's Compose path
|
||||||
|
├── .env.example ← documented variables; copy to .env locally
|
||||||
|
├── .gitignore
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Services in the stack
|
||||||
|
|
||||||
|
Currently:
|
||||||
|
|
||||||
|
- **redis** — telemetry queue + future Phase 2 connection registry. Internal-only, persisted via named volume.
|
||||||
|
- **tcp-ingestion** — Teltonika telemetry TCP server. Image built by [`trm/tcp-ingestion`](https://git.dev.microservices.al/trm/tcp-ingestion)'s Gitea workflow.
|
||||||
|
|
||||||
|
Planned (will be added as they land):
|
||||||
|
|
||||||
|
- **processor** — consumes telemetry from Redis, writes to PostgreSQL/Timescale.
|
||||||
|
- **postgres** — with TimescaleDB extension.
|
||||||
|
- **directus** — business-plane API and admin UI.
|
||||||
|
- **react-spa** — front-end SPA (static bundle, served via reverse proxy).
|
||||||
|
|
||||||
|
See `../docs/wiki/` for the full architecture.
|
||||||
|
|
||||||
|
## Deploy via Portainer (Repository Stack)
|
||||||
|
|
||||||
|
1. **Stack → Add stack → Repository** in Portainer.
|
||||||
|
2. Repository URL: `https://git.dev.microservices.al/trm/deploy`
|
||||||
|
3. Branch: `main`
|
||||||
|
4. Compose path: `compose.yaml`
|
||||||
|
5. Environment variables: leave empty for defaults, or set per `.env.example`.
|
||||||
|
6. (Optional) Enable **Automatic updates** with a webhook. Portainer will poll or accept a webhook to redeploy when this repo's `main` changes.
|
||||||
|
|
||||||
|
Before the first deploy, the Portainer host must be authenticated to the Gitea registry:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker login git.dev.microservices.al
|
||||||
|
```
|
||||||
|
|
||||||
|
(Or configure registry credentials in Portainer's **Registries** UI — preferred.)
|
||||||
|
|
||||||
|
## Deploy without Portainer (manual)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.dev.microservices.al/trm/deploy
|
||||||
|
cd deploy
|
||||||
|
cp .env.example .env
|
||||||
|
# edit .env if you want to override defaults
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
When a service publishes a new image (Gitea workflow on push to `main`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Portainer with automatic updates does this automatically.
|
||||||
|
|
||||||
|
To pin a specific build for production, set the relevant `*_TAG` variable in `.env` (or in Portainer's stack environment) to a commit SHA — e.g. `TCP_INGESTION_TAG=af06973`.
|
||||||
|
|
||||||
|
## Network model
|
||||||
|
|
||||||
|
- One internal Compose network (`trm_default`).
|
||||||
|
- Redis is **not** bound to a host port — only reachable from other services in the stack via service-name DNS (`redis://redis:6379`).
|
||||||
|
- tcp-ingestion's TCP port (5027 by default) is bound to the host so devices can reach it.
|
||||||
|
- Other Redis instances on the same host can keep using port 6379 freely; this stack does not collide with them.
|
||||||
|
|
||||||
|
## Environment variables
|
||||||
|
|
||||||
|
See `.env.example` for the documented set with defaults and explanations.
|
||||||
|
|
||||||
|
## Why a separate repo
|
||||||
|
|
||||||
|
Compose covers multiple services; placing it inside any one service repo creates ownership ambiguity (which service "owns" the Postgres definition? the Redis volume?). Keeping deploy config in its own repo means:
|
||||||
|
|
||||||
|
- Compose changes are versioned independently of any service's code.
|
||||||
|
- Portainer's Repository stack tracks one source of truth.
|
||||||
|
- Per-environment overrides (e.g. `compose.stage.yaml`, `compose.prod.yaml`) can be added cleanly later.
|
||||||
|
- Adding a new service is a one-file change here, not a coordinated edit across repos.
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# TRM platform — deployment stack
|
||||||
|
#
|
||||||
|
# Deployed via Portainer Repository Stack:
|
||||||
|
# Repository: git.dev.microservices.al/trm/deploy
|
||||||
|
# Compose path: compose.yaml
|
||||||
|
# Branch: main
|
||||||
|
#
|
||||||
|
# Images are built and pushed by each service's own Gitea workflow.
|
||||||
|
# This file references them by tag and runs them as a coordinated stack.
|
||||||
|
#
|
||||||
|
# Before first deploy on the host: `docker login git.dev.microservices.al`
|
||||||
|
# (Portainer can store registry credentials in its UI; configure once.)
|
||||||
|
#
|
||||||
|
# Environment variables are populated from Portainer's stack environment
|
||||||
|
# config (or a `.env` file alongside this compose for non-Portainer hosts).
|
||||||
|
# Defaults are provided via `${VAR:-default}` so the stack starts with no
|
||||||
|
# explicit configuration on a fresh deploy.
|
||||||
|
|
||||||
|
name: trm
|
||||||
|
|
||||||
|
services:
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Redis — telemetry queue + (future) connection registry for Phase 2.
|
||||||
|
# Internal-only; no host port mapping.
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
expose:
|
||||||
|
- '6379'
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'redis-cli', 'ping']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# tcp-ingestion — Teltonika telemetry TCP server.
|
||||||
|
# Built by git.dev.microservices.al/trm/tcp-ingestion's Gitea workflow.
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
tcp-ingestion:
|
||||||
|
image: git.dev.microservices.al/trm/tcp-ingestion:${TCP_INGESTION_TAG:-main}
|
||||||
|
depends_on:
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
# Devices connect to this port. Use `${HOST_BIND_IP:-0.0.0.0}:5027:5027`
|
||||||
|
# if you want to restrict which host interface accepts connections.
|
||||||
|
- '${TCP_INGESTION_PORT:-5027}:5027'
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
INSTANCE_ID: ${TCP_INGESTION_INSTANCE_ID:-stage-1}
|
||||||
|
REDIS_URL: redis://redis:6379
|
||||||
|
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Future services land here:
|
||||||
|
# - processor: consumes telemetry from Redis, writes to DB
|
||||||
|
# - postgres: PostgreSQL with TimescaleDB extension
|
||||||
|
# - directus: business-plane API + admin UI
|
||||||
|
# - react-spa: front-end (static, served via nginx or Caddy)
|
||||||
|
# See ../docs/wiki/ for the platform architecture.
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis-data:
|
||||||
Reference in New Issue
Block a user