Compare commits
31
Commits
6b494a34fe
..
1.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f1e227d50 | ||
|
|
0891606321 | ||
|
|
c6f28ff7af | ||
|
|
072a91961f | ||
|
|
7184240dd4 | ||
|
|
9cd0419c0c | ||
|
|
d3266f8feb | ||
|
|
b532507374 | ||
|
|
5c1a8cbe4f | ||
|
|
502fefff33 | ||
|
|
bc3a950d99 | ||
|
|
1af9e59a56 | ||
|
|
13d25a7ae0 | ||
|
|
fc799da000 | ||
|
|
2b091adce8 | ||
|
|
c54210434e | ||
|
|
fcb68cfd8d | ||
|
|
cdecdd2d4a | ||
|
|
47ffae5dea | ||
|
|
43c1a31660 | ||
|
|
afb9a41404 | ||
|
|
1f2082e0fb | ||
|
|
7ce6a24a77 | ||
|
|
450a93150c | ||
|
|
dc53bce6c9 | ||
|
|
32f2b7c7ab | ||
|
|
72422f4336 | ||
|
|
78508ed16e | ||
|
|
8fd80c1a4c | ||
|
|
5fc9bc6191 | ||
|
|
3c2b29ad26 |
No files matched your search
+6
-9
@@ -31,10 +31,12 @@ ADMIN_SESSION_TTL_HOURS=12
|
|||||||
# VITE_PUBLIC_HLS_URL=http://localhost/hls/playlist.m3u8
|
# VITE_PUBLIC_HLS_URL=http://localhost/hls/playlist.m3u8
|
||||||
|
|
||||||
# Gitea Container Registry (for self-hosted Docker images)
|
# Gitea Container Registry (for self-hosted Docker images)
|
||||||
GITEA_REGISTRY_URL=git.allucanget.biz
|
CI_REGISTRY_URL=git.allucanget.biz
|
||||||
GITEA_USERNAME=your-gitea-username
|
CI_REGISTRY_USER=your-gitea-username
|
||||||
GITEA_TOKEN=your-gitea-token
|
CI_REGISTRY_TOKEN=your-gitea-token
|
||||||
GITEA_REGISTRY_NAMESPACE=zwitschi/linearvoid
|
CI_REGISTRY_NAMESPACE=zwitschi/linearvoid
|
||||||
|
# Gitea API access (optional, for CI/release automation)
|
||||||
|
CI_SERVER_URL=https://git.allucanget.biz
|
||||||
|
|
||||||
# Chat / Application Database (compose-safe PostgreSQL by default, SQLite optional)
|
# Chat / Application Database (compose-safe PostgreSQL by default, SQLite optional)
|
||||||
DATABASE_URL=postgres://linearvoid:linearvoid@db:5432/linearvoid?sslmode=disable
|
DATABASE_URL=postgres://linearvoid:linearvoid@db:5432/linearvoid?sslmode=disable
|
||||||
@@ -62,8 +64,3 @@ GRAFANA_PORT=3001
|
|||||||
# Development flags
|
# Development flags
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
GO_ENV=development
|
GO_ENV=development
|
||||||
|
|
||||||
# Gitea Configuration
|
|
||||||
GITEA_SERVER_URL=https://git.allucanget.biz
|
|
||||||
GITEA_TOKEN=your-gitea-token
|
|
||||||
GITEA_USERNAME=your-gitea-username
|
|
||||||
+61
-12
@@ -1,13 +1,17 @@
|
|||||||
name: CD
|
name: CD
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_run:
|
||||||
|
workflows: ["CI"]
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
branches: [main]
|
branches: [main]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: [ubuntu-latest]
|
runs-on: [ubuntu-latest]
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
|
||||||
environment: production
|
environment: production
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -22,28 +26,73 @@ jobs:
|
|||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: git.allucanget.biz
|
registry: git.allucanget.biz
|
||||||
username: ${{ secrets.GITEA_USERNAME }}
|
username: ${{ secrets.CI_REGISTRY_USER }}
|
||||||
password: ${{ secrets.GITEA_TOKEN }}
|
password: ${{ secrets.CI_REGISTRY_TOKEN }}
|
||||||
|
|
||||||
- name: Pull latest images
|
- name: Prepare environment
|
||||||
run: |
|
run: |
|
||||||
docker pull git.allucanget.biz/zwitschi/linearvoid/playout:latest || true
|
cat > .env << 'EOF'
|
||||||
docker pull git.allucanget.biz/zwitschi/linearvoid/chat:latest || true
|
DATABASE_URL="${{ secrets.DATABASE_URL }}"
|
||||||
docker pull git.allucanget.biz/zwitschi/linearvoid/frontend:latest || true
|
REDIS_URL=redis://redis:6379/0
|
||||||
docker pull git.allucanget.biz/zwitschi/linearvoid/nginx:latest || true
|
PLAYLIST_PATH=/app/playlist/playlist.txt
|
||||||
|
HLS_SEGMENT_DURATION=6
|
||||||
|
HLS_WINDOW_SIZE=24
|
||||||
|
LOG_LEVEL=info
|
||||||
|
ADMIN_USERNAME="${{ secrets.ADMIN_USERNAME }}"
|
||||||
|
ADMIN_PASSWORD="${{ secrets.ADMIN_PASSWORD }}"
|
||||||
|
ADMIN_SESSION_TTL_HOURS=12
|
||||||
|
NGINX_PORT=80
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Seed Prometheus config
|
||||||
|
run: |
|
||||||
|
mkdir -p monitoring/prometheus
|
||||||
|
cat > monitoring/prometheus/prometheus.yml << 'EOF'
|
||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
evaluation_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: 'prometheus'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['localhost:9090']
|
||||||
|
|
||||||
|
- job_name: 'linearvoid'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['playout:8081', 'chat:3000', 'nginx:80']
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Deploy with docker-compose
|
- name: Deploy with docker-compose
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: tcp://192.168.88.40:2375
|
||||||
run: |
|
run: |
|
||||||
docker compose -f docker-compose.prod.yml pull
|
docker compose -f docker-compose.prod.yml pull
|
||||||
docker compose -f docker-compose.prod.yml up -d --remove-orphans
|
docker compose -f docker-compose.prod.yml up -d --remove-orphans
|
||||||
|
|
||||||
- name: Health check
|
- name: Health check
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: tcp://192.168.88.40:2375
|
||||||
run: |
|
run: |
|
||||||
sleep 10
|
# Wait for playout to stabilize (it may restart during init)
|
||||||
curl -f http://localhost:8080/health || exit 1
|
sleep 20
|
||||||
curl -f http://localhost:3000/health || exit 1
|
curl -f http://192.168.88.40:3000/health || exit 1
|
||||||
curl -f http://localhost:8081/health || exit 1
|
# Retry playout health check since it may still be initializing
|
||||||
|
for i in $(seq 1 6); do
|
||||||
|
if docker exec linearvoid-playout curl -sf http://localhost:8081/health; then
|
||||||
|
echo "Playout is healthy"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "Playout not ready yet (attempt $i/6), waiting 5s..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
echo "Playout failed to become healthy after 6 attempts"
|
||||||
|
docker logs linearvoid-playout --tail 50
|
||||||
|
exit 1
|
||||||
|
curl -f http://192.168.88.40:3000/health || exit 1
|
||||||
|
docker exec linearvoid-playout curl -sf http://localhost:8081/health || exit 1
|
||||||
|
|
||||||
- name: Cleanup old images
|
- name: Cleanup old images
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: tcp://192.168.88.40:2375
|
||||||
run: |
|
run: |
|
||||||
docker image prune -f --filter "until=24h"
|
docker image prune -f --filter "until=24h"
|
||||||
+23
-39
@@ -48,7 +48,7 @@ jobs:
|
|||||||
|
|
||||||
docker:
|
docker:
|
||||||
needs: test
|
needs: test
|
||||||
runs-on: [self-hosted, linux, docker]
|
runs-on: [ubuntu-latest]
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -63,8 +63,8 @@ jobs:
|
|||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: git.allucanget.biz
|
registry: git.allucanget.biz
|
||||||
username: ${{ secrets.GITEA_USERNAME }}
|
username: ${{ secrets.CI_REGISTRY_USER }}
|
||||||
password: ${{ secrets.GITEA_TOKEN }}
|
password: ${{ secrets.CI_REGISTRY_TOKEN }}
|
||||||
|
|
||||||
- name: Extract metadata for Playout
|
- name: Extract metadata for Playout
|
||||||
id: meta-playout
|
id: meta-playout
|
||||||
@@ -82,11 +82,10 @@ jobs:
|
|||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: ./backend/playout
|
context: ./backend/playout
|
||||||
|
file: ./backend/playout/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta-playout.outputs.tags }}
|
tags: ${{ steps.meta-playout.outputs.tags }}
|
||||||
labels: ${{ steps.meta-playout.outputs.labels }}
|
labels: ${{ steps.meta-playout.outputs.labels }}
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
||||||
- name: Extract metadata for Chat
|
- name: Extract metadata for Chat
|
||||||
id: meta-chat
|
id: meta-chat
|
||||||
@@ -107,30 +106,6 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta-chat.outputs.tags }}
|
tags: ${{ steps.meta-chat.outputs.tags }}
|
||||||
labels: ${{ steps.meta-chat.outputs.labels }}
|
labels: ${{ steps.meta-chat.outputs.labels }}
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
||||||
- name: Extract metadata for Frontend
|
|
||||||
id: meta-frontend
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: git.allucanget.biz/zwitschi/linearvoid/frontend
|
|
||||||
tags: |
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=pr
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest,enable={{is_default_branch}}
|
|
||||||
|
|
||||||
- name: Build and push Frontend image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: ./frontend
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta-frontend.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta-frontend.outputs.labels }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
||||||
- name: Extract metadata for Nginx
|
- name: Extract metadata for Nginx
|
||||||
id: meta-nginx
|
id: meta-nginx
|
||||||
@@ -145,18 +120,27 @@ jobs:
|
|||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push Nginx image
|
- name: Build and push Nginx image
|
||||||
uses: docker/build-push-action@v5
|
run: |
|
||||||
with:
|
TAGS="${{ steps.meta-nginx.outputs.tags }}"
|
||||||
context: ./infrastructure/nginx
|
LABELS="${{ steps.meta-nginx.outputs.labels }}"
|
||||||
push: true
|
TAG_ARGS=""
|
||||||
tags: ${{ steps.meta-nginx.outputs.tags }}
|
for tag in $TAGS; do
|
||||||
labels: ${{ steps.meta-nginx.outputs.labels }}
|
TAG_ARGS="$TAG_ARGS --tag $tag"
|
||||||
cache-from: type=gha
|
done
|
||||||
cache-to: type=gha,mode=max
|
LABEL_ARGS=""
|
||||||
|
while IFS= read -r label; do
|
||||||
|
[ -n "$label" ] && LABEL_ARGS="$LABEL_ARGS --label $label"
|
||||||
|
done <<< "$LABELS"
|
||||||
|
docker buildx build \
|
||||||
|
--push \
|
||||||
|
--file infrastructure/nginx/Dockerfile \
|
||||||
|
$TAG_ARGS \
|
||||||
|
$LABEL_ARGS \
|
||||||
|
.
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs: docker
|
needs: docker
|
||||||
runs-on: [self-hosted, linux, docker]
|
runs-on: [ubuntu-latest]
|
||||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -169,4 +153,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.CI_REGISTRY_TOKEN }}
|
||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.GITEA_TOKEN }}
|
token: ${{ secrets.CI_REGISTRY_TOKEN }}
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v5
|
uses: peter-evans/create-pull-request@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITEA_TOKEN }}
|
token: ${{ secrets.CI_REGISTRY_TOKEN }}
|
||||||
commit-message: "chore: update dependencies"
|
commit-message: "chore: update dependencies"
|
||||||
title: "chore: weekly dependency updates"
|
title: "chore: weekly dependency updates"
|
||||||
body: |
|
body: |
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ jobs:
|
|||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: git.allucanget.biz
|
registry: git.allucanget.biz
|
||||||
username: ${{ secrets.GITEA_USERNAME }}
|
username: ${{ secrets.CI_REGISTRY_USER }}
|
||||||
password: ${{ secrets.GITEA_TOKEN }}
|
password: ${{ secrets.CI_REGISTRY_TOKEN }}
|
||||||
|
|
||||||
- name: Extract version
|
- name: Extract version
|
||||||
id: version
|
id: version
|
||||||
@@ -75,24 +75,6 @@ jobs:
|
|||||||
tags: ${{ steps.meta-chat.outputs.tags }}
|
tags: ${{ steps.meta-chat.outputs.tags }}
|
||||||
labels: ${{ steps.meta-chat.outputs.labels }}
|
labels: ${{ steps.meta-chat.outputs.labels }}
|
||||||
|
|
||||||
- name: Extract metadata for Frontend
|
|
||||||
id: meta-frontend
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: git.allucanget.biz/zwitschi/linearvoid/frontend
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=raw,value=latest
|
|
||||||
|
|
||||||
- name: Build and push Frontend image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: ./frontend
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta-frontend.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta-frontend.outputs.labels }}
|
|
||||||
|
|
||||||
- name: Extract metadata for Nginx
|
- name: Extract metadata for Nginx
|
||||||
id: meta-nginx
|
id: meta-nginx
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -106,15 +88,15 @@ jobs:
|
|||||||
- name: Build and push Nginx image
|
- name: Build and push Nginx image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: ./infrastructure/nginx
|
context: .
|
||||||
|
file: infrastructure/nginx/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta-nginx.outputs.tags }}
|
tags: ${{ steps.meta-nginx.outputs.tags }}
|
||||||
labels: ${{ steps.meta-nginx.outputs.labels }}
|
labels: ${{ steps.meta-nginx.outputs.labels }}
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release on Gitea
|
||||||
uses: softprops/action-gh-release@v1
|
run: |
|
||||||
with:
|
curl -X POST "$CI_SERVER_URL/api/v1/repos/$CI_REPO_OWNER/$CI_REPO_NAME/releases" \
|
||||||
generate_release_notes: true
|
-H "Authorization: token ${{ secrets.CI_REGISTRY_TOKEN }}" \
|
||||||
tag_name: ${{ steps.version.outputs.version }}
|
-H "Content-Type: application/json" \
|
||||||
env:
|
-d "{\"tag_name\":\"${{ steps.version.outputs.version }}\",\"name\":\"${{ steps.version.outputs.version }}\",\"body\":\"Release ${{ steps.version.outputs.version }}\n\nSee [CHANGELOG.md](https://git.allucanget.biz/zwitschi/linearvoid/src/branch/main/CHANGELOG.md) for details.\",\"draft\":false,\"prerelease\":false}"
|
||||||
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
@@ -9,3 +9,13 @@ Agents instructions for the linearvoid project.
|
|||||||
- Update documentation first before implementing changes to ensure traceability of decisions.
|
- Update documentation first before implementing changes to ensure traceability of decisions.
|
||||||
- Plan any task in the `TODO.md` file with clear steps and mark them as completed when done. Move completed sections to DONE.md. Write entry in root `CHANGELOG.md` for any significant changes. Avoid using in-memory todo lists or update them frequently to sync from the `TODO.md` file.
|
- Plan any task in the `TODO.md` file with clear steps and mark them as completed when done. Move completed sections to DONE.md. Write entry in root `CHANGELOG.md` for any significant changes. Avoid using in-memory todo lists or update them frequently to sync from the `TODO.md` file.
|
||||||
- Before taking any action except for planning and writing `TODO.md`, always ask user for confirmation, accept `go`, `ok`, `yes`, `next`, or `continue` to proceed. If the user says `no`, `stop`, or `cancel`, abort the action and return to planning.
|
- Before taking any action except for planning and writing `TODO.md`, always ask user for confirmation, accept `go`, `ok`, `yes`, `next`, or `continue` to proceed. If the user says `no`, `stop`, or `cancel`, abort the action and return to planning.
|
||||||
|
|
||||||
|
## Security & Secrets Protection
|
||||||
|
|
||||||
|
- **Never commit raw secrets or credentials** to the repository.
|
||||||
|
- **Never print or log raw secrets** in terminal commands or output files.
|
||||||
|
- **Use Gitea Actions Secrets** for all production credentials and environment variables.
|
||||||
|
- **Avoid hardcoding sensitive values** in workflow files (`.yml`). Instead, reference them using `${{ secrets.SECRET_NAME }}`.
|
||||||
|
- **Do not use the `GITEA_` prefix** for custom secrets or environment variables in Gitea, as it is reserved internally and will be silently ignored or returned as empty. Use the `CI_` prefix instead (e.g., `CI_REGISTRY_USER`, `CI_REGISTRY_TOKEN`).
|
||||||
|
- **Keep `.env` gitignored** and use `.env.example` as the template for local development.
|
||||||
|
- **For CD deployments**, generate the `.env` file dynamically on the runner using a secure step that populates values from Gitea Actions Secrets.
|
||||||
+3
-4
@@ -50,6 +50,9 @@ data/
|
|||||||
*.sqlite
|
*.sqlite
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
|
|
||||||
|
# Demo data (tracked in backend/playout/demodata/ for out-of-the-box playout)
|
||||||
|
!backend/playout/demodata/
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
.dockerignore
|
.dockerignore
|
||||||
**/.dockerignore
|
**/.dockerignore
|
||||||
@@ -75,10 +78,6 @@ Thumbs.db
|
|||||||
*.tfstate.backup
|
*.tfstate.backup
|
||||||
.terraform/
|
.terraform/
|
||||||
|
|
||||||
# Monitoring & temp
|
|
||||||
prometheus/
|
|
||||||
grafana/
|
|
||||||
|
|
||||||
# Agent / Tool files
|
# Agent / Tool files
|
||||||
.github/instructions/TODO.md
|
.github/instructions/TODO.md
|
||||||
.github/instructions/DONE.md
|
.github/instructions/DONE.md
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ This guide covers prerequisites, environment setup, running the application loca
|
|||||||
- **Git**: For cloning and version control.
|
- **Git**: For cloning and version control.
|
||||||
- **Cloudflare Account**: For R2 storage and CDN (free tier sufficient for most use cases).
|
- **Cloudflare Account**: For R2 storage and CDN (free tier sufficient for most use cases).
|
||||||
- **Gitea Account**: Required if you want to push images to the self-hosted registry or use the repository's CI/CD flow.
|
- **Gitea Account**: Required if you want to push images to the self-hosted registry or use the repository's CI/CD flow.
|
||||||
|
- Set up the required Actions secrets in Gitea at: [https://git.allucanget.biz/zwitschi/linearvoid/settings/actions/secrets](https://git.allucanget.biz/zwitschi/linearvoid/settings/actions/secrets)
|
||||||
|
- Add the following secrets:
|
||||||
|
- `CI_REGISTRY_USER`: Your Gitea username (e.g., `zwitschi`)
|
||||||
|
- `CI_REGISTRY_TOKEN`: A Gitea Personal Access Token with `write:packages` scope
|
||||||
|
- `ADMIN_USERNAME`: The administrator username for the production admin panel (e.g., `admin`)
|
||||||
|
- `ADMIN_PASSWORD`: A strong password for the production admin panel
|
||||||
|
- `DATABASE_URL`: The production database connection string (e.g., `postgres://linearvoid:<password>@db:5432/linearvoid?sslmode=disable`)
|
||||||
- **Hetzner Cloud Account** (optional for production): For the US-East VPS (Ashburn, VA recommended per ADR-001).
|
- **Hetzner Cloud Account** (optional for production): For the US-East VPS (Ashburn, VA recommended per ADR-001).
|
||||||
|
|
||||||
## Development Prerequisites
|
## Development Prerequisites
|
||||||
@@ -70,10 +77,12 @@ This guide covers prerequisites, environment setup, running the application loca
|
|||||||
# VITE_PUBLIC_HLS_URL=http://localhost/hls/playlist.m3u8
|
# VITE_PUBLIC_HLS_URL=http://localhost/hls/playlist.m3u8
|
||||||
|
|
||||||
# Gitea Container Registry (for self-hosted Docker images)
|
# Gitea Container Registry (for self-hosted Docker images)
|
||||||
GITEA_REGISTRY_URL=git.allucanget.biz
|
CI_REGISTRY_URL=git.allucanget.biz
|
||||||
GITEA_USERNAME=your-gitea-username
|
CI_REGISTRY_USER=your-gitea-username
|
||||||
GITEA_TOKEN=your-gitea-token
|
CI_REGISTRY_TOKEN=your-gitea-token
|
||||||
GITEA_REGISTRY_NAMESPACE=zwitschi/linearvoid
|
CI_REGISTRY_NAMESPACE=zwitschi/linearvoid
|
||||||
|
# Gitea API access (optional, for CI/release automation)
|
||||||
|
CI_SERVER_URL=https://git.allucanget.biz
|
||||||
|
|
||||||
# Chat / Database
|
# Chat / Database
|
||||||
DATABASE_URL=postgres://linearvoid:linearvoid@db:5432/linearvoid?sslmode=disable
|
DATABASE_URL=postgres://linearvoid:linearvoid@db:5432/linearvoid?sslmode=disable
|
||||||
@@ -99,11 +108,6 @@ This guide covers prerequisites, environment setup, running the application loca
|
|||||||
# Development flags
|
# Development flags
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
GO_ENV=development
|
GO_ENV=development
|
||||||
|
|
||||||
# Gitea API access (optional, for CI/release automation)
|
|
||||||
GITEA_SERVER_URL=https://git.allucanget.biz
|
|
||||||
GITEA_TOKEN=your-gitea-token
|
|
||||||
GITEA_USERNAME=your-gitea-username
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Check local value overrides for Docker Compose**:
|
4. **Check local value overrides for Docker Compose**:
|
||||||
@@ -162,24 +166,33 @@ This guide covers prerequisites, environment setup, running the application loca
|
|||||||
|
|
||||||
2. **Create an access token**:
|
2. **Create an access token**:
|
||||||
- Generate a token with the scopes needed for package/registry access and, if applicable, repository automation.
|
- Generate a token with the scopes needed for package/registry access and, if applicable, repository automation.
|
||||||
- Store it as `GITEA_TOKEN` in `.env`.
|
- Store it as `CI_REGISTRY_TOKEN` in `.env`.
|
||||||
|
|
||||||
3. **Configure registry variables**:
|
3. **Configure Gitea Actions Secrets**:
|
||||||
- Set `GITEA_REGISTRY_URL` to the Gitea host.
|
- Go to the repository settings page: [https://git.allucanget.biz/zwitschi/linearvoid/settings/actions/secrets](https://git.allucanget.biz/zwitschi/linearvoid/settings/actions/secrets)
|
||||||
- Set `GITEA_REGISTRY_NAMESPACE` to the image namespace, for example `zwitschi/linearvoid`.
|
- Add the following secrets to enable automated CI/CD and production deployment:
|
||||||
- Set `GITEA_USERNAME` to the account that will push or pull images.
|
- `CI_REGISTRY_USER`: Your Gitea username (e.g., `zwitschi`).
|
||||||
|
- `CI_REGISTRY_TOKEN`: Your Gitea Personal Access Token with `write:packages` scope.
|
||||||
|
- `ADMIN_USERNAME`: The administrator username for the production admin panel (e.g., `admin`).
|
||||||
|
- `ADMIN_PASSWORD`: A strong password for the production admin panel.
|
||||||
|
- `DATABASE_URL`: The production database connection string (e.g., `postgres://linearvoid:<password>@db:5432/linearvoid?sslmode=disable`).
|
||||||
|
|
||||||
4. **Authenticate Docker to the registry**:
|
4. **Configure registry variables**:
|
||||||
|
- Set `CI_REGISTRY_URL` to the Gitea host.
|
||||||
|
- Set `CI_REGISTRY_NAMESPACE` to the image namespace, for example `zwitschi/linearvoid`.
|
||||||
|
- Set `CI_REGISTRY_USER` to the account that will push or pull images.
|
||||||
|
|
||||||
|
5. **Authenticate Docker to the registry**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker login git.allucanget.biz
|
docker login git.allucanget.biz
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Build and publish images when needed**:
|
6. **Build and publish images when needed**:
|
||||||
- Local development uses `docker-compose.yml`, which builds from source.
|
- Local development uses `docker-compose.yml`, which builds from source.
|
||||||
- Production uses `docker-compose.prod.yml`, which expects the `playout`, `chat`, and `nginx` images to exist in the configured Gitea registry namespace.
|
- Production uses `docker-compose.prod.yml`, which expects the `playout`, `chat`, and `nginx` images to exist in the configured Gitea registry namespace.
|
||||||
|
|
||||||
6. **Validate image availability**:
|
7. **Validate image availability**:
|
||||||
- Before a production rollout, verify that the expected `:latest` tags can be pulled from the registry on the target server.
|
- Before a production rollout, verify that the expected `:latest` tags can be pulled from the registry on the target server.
|
||||||
|
|
||||||
## Running the Application
|
## Running the Application
|
||||||
@@ -230,6 +243,104 @@ This guide covers prerequisites, environment setup, running the application loca
|
|||||||
docker compose down
|
docker compose down
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Local Test Environment Deployment (Remote Docker Host)
|
||||||
|
|
||||||
|
For testing deployments on a local network server without setting up a full production VPS, you can deploy directly to a remote Docker host (e.g., a home lab server or test machine) using Docker's TCP socket.
|
||||||
|
|
||||||
|
#### Test Environment Prerequisites
|
||||||
|
|
||||||
|
- A remote server running Docker at IP `192.168.88.40` (running Alpine Linux).
|
||||||
|
- Docker TCP socket enabled and listening on port `2375` on the remote server.
|
||||||
|
|
||||||
|
##### Enabling Docker TCP Socket on Alpine Linux
|
||||||
|
|
||||||
|
To allow the Gitea Actions runner (or your local machine) to deploy to the remote Alpine host, you must configure the Docker daemon to listen on the TCP socket:
|
||||||
|
|
||||||
|
1. Edit `/etc/conf.d/docker` on the Alpine host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vi /etc/conf.d/docker
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Update the `DOCKER_OPTS` line to include both the unix socket and the TCP socket:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Restart the Docker service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rc-service docker restart
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Verify that Docker is listening on port `2375`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
netstat -tlnp | grep 2375
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Ensure any firewall (like `awall` or `iptables`) on the Alpine host allows incoming traffic on port `2375` from your local network subnet (e.g., `192.168.88.0/24`).
|
||||||
|
|
||||||
|
#### Deployment Steps
|
||||||
|
|
||||||
|
1. **Configure Docker CLI to use the Remote Host**:
|
||||||
|
You can point your local Docker CLI to the remote server by setting the `DOCKER_HOST` environment variable:
|
||||||
|
- **PowerShell (Windows)**:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:DOCKER_HOST="tcp://192.168.88.40:2375"
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Bash (Linux/macOS)**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DOCKER_HOST="tcp://192.168.88.40:2375"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify Connection**:
|
||||||
|
Run `docker info` to confirm your local CLI is communicating with the remote server at `192.168.88.40`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker info
|
||||||
|
```
|
||||||
|
|
||||||
|
The output should show the remote server's hostname and system details.
|
||||||
|
|
||||||
|
3. **Deploy the Stack**:
|
||||||
|
With `DOCKER_HOST` set, any `docker` or `docker compose` commands you run locally will execute directly on the remote server.
|
||||||
|
- **Deploy from Registry (Production-like)**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml pull
|
||||||
|
docker compose -f docker-compose.prod.yml up -d --remove-orphans
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Build and Deploy from Source**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Access the Test Environment**:
|
||||||
|
- Playout Health: `http://192.168.88.40:8081/health`
|
||||||
|
- Chat Health: `http://192.168.88.40:3000/health`
|
||||||
|
- Nginx Entrypoint: `http://192.168.88.40:8080` (or the port mapped to `NGINX_PORT` in `.env`)
|
||||||
|
|
||||||
|
5. **Reset to Local Docker Host**:
|
||||||
|
Once testing is complete, clear the `DOCKER_HOST` variable to point back to your local machine:
|
||||||
|
- **PowerShell**:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Remove-Item env:DOCKER_HOST
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Bash**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
unset DOCKER_HOST
|
||||||
|
```
|
||||||
|
|
||||||
### Production Setup Guide
|
### Production Setup Guide
|
||||||
|
|
||||||
1. **Prepare the target host**:
|
1. **Prepare the target host**:
|
||||||
@@ -260,7 +371,7 @@ This guide covers prerequisites, environment setup, running the application loca
|
|||||||
```
|
```
|
||||||
|
|
||||||
5. **Publish or verify required images in Gitea**:
|
5. **Publish or verify required images in Gitea**:
|
||||||
- Ensure the `playout`, `chat`, and `nginx` images exist under `${GITEA_REGISTRY_URL}/${GITEA_REGISTRY_NAMESPACE}`.
|
- Ensure the `playout`, `chat`, and `nginx` images exist under `${CI_REGISTRY_URL}/${CI_REGISTRY_NAMESPACE}`.
|
||||||
- Log in to the registry from the VPS before pulling.
|
- Log in to the registry from the VPS before pulling.
|
||||||
|
|
||||||
6. **Deploy the production stack**:
|
6. **Deploy the production stack**:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ RUN go mod tidy
|
|||||||
RUN CGO_ENABLED=1 GOOS=linux go build -o /chat-server ./src/main.go
|
RUN CGO_ENABLED=1 GOOS=linux go build -o /chat-server ./src/main.go
|
||||||
|
|
||||||
FROM alpine:3.20
|
FROM alpine:3.20
|
||||||
RUN apk --no-cache add ca-certificates
|
RUN apk --no-cache add ca-certificates curl curl
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /chat-server /usr/local/bin/chat-server
|
COPY --from=builder /chat-server /usr/local/bin/chat-server
|
||||||
|
|
||||||
|
|||||||
@@ -16,20 +16,18 @@ RUN apk add --no-cache \
|
|||||||
ffmpeg \
|
ffmpeg \
|
||||||
curl \
|
curl \
|
||||||
bash
|
bash
|
||||||
|
# Set working directory for playout
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
# Copy the playout start script and the built playlist manager binary
|
||||||
COPY --from=builder /playlist-manager /app/playlist-manager
|
|
||||||
COPY start-playout.sh /app/
|
COPY start-playout.sh /app/
|
||||||
COPY *.sh /app/
|
# Copy demo data for out-of-the-box playout
|
||||||
|
COPY demodata/ /app/
|
||||||
RUN chmod +x /app/*.sh /app/playlist-manager
|
# Copy the built playlist manager binary from the builder stage
|
||||||
|
COPY --from=builder /playlist-manager /app/playlist-manager
|
||||||
# Create directories for playlist, media, and HLS output
|
# Create directories for playlist, media, and HLS output
|
||||||
RUN mkdir -p /app/playlist /app/media /app/hls
|
RUN mkdir -p /app/hls
|
||||||
|
RUN chmod +x /app/start-playout.sh /app/playlist-manager
|
||||||
# Expose HLS directory (will be served by nginx)
|
# Expose HLS directory (will be served by nginx)
|
||||||
VOLUME ["/app/hls"]
|
VOLUME ["/app/hls"]
|
||||||
|
|
||||||
# Default command runs the playout loop (which calls the Go validator)
|
# Default command runs the playout loop (which calls the Go validator)
|
||||||
CMD ["./start-playout.sh"]
|
CMD ["./start-playout.sh"]
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
|||||||
|
# Linear Void Demo Playlist
|
||||||
|
file '/app/media/demo1.mp4'
|
||||||
|
file '/app/media/demo2.mp4'
|
||||||
@@ -6,7 +6,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/playlist:/app/playlist:ro
|
- ./data/playlist:/app/playlist:rw
|
||||||
- ./data/media:/app/media:ro
|
- ./data/media:/app/media:ro
|
||||||
- ./data/hls:/app/hls:rw
|
- ./data/hls:/app/hls:rw
|
||||||
networks:
|
networks:
|
||||||
@@ -102,7 +102,7 @@ services:
|
|||||||
container_name: linearvoid-prometheus
|
container_name: linearvoid-prometheus
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
- prometheus-config:/etc/prometheus
|
||||||
- prometheus-data:/prometheus
|
- prometheus-data:/prometheus
|
||||||
ports:
|
ports:
|
||||||
- "9090:9090"
|
- "9090:9090"
|
||||||
@@ -142,4 +142,5 @@ volumes:
|
|||||||
redis-data:
|
redis-data:
|
||||||
postgres-data:
|
postgres-data:
|
||||||
prometheus-data:
|
prometheus-data:
|
||||||
|
prometheus-config:
|
||||||
grafana-data:
|
grafana-data:
|
||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
playout:
|
playout:
|
||||||
image: ${GITEA_REGISTRY_URL:-git.allucanget.biz}/${GITEA_REGISTRY_NAMESPACE:-zwitschi/linearvoid}/playout:latest
|
image: ${CI_REGISTRY_URL:-git.allucanget.biz}/${CI_REGISTRY_NAMESPACE:-zwitschi/linearvoid}/playout:latest
|
||||||
build:
|
build:
|
||||||
context: ./backend/playout
|
context: ./backend/playout
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
start_period: 10s
|
start_period: 10s
|
||||||
|
|
||||||
chat:
|
chat:
|
||||||
image: ${GITEA_REGISTRY_URL:-git.allucanget.biz}/${GITEA_REGISTRY_NAMESPACE:-zwitschi/linearvoid}/chat:latest
|
image: ${CI_REGISTRY_URL:-git.allucanget.biz}/${CI_REGISTRY_NAMESPACE:-zwitschi/linearvoid}/chat:latest
|
||||||
build:
|
build:
|
||||||
context: ./backend/chat
|
context: ./backend/chat
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
@@ -51,10 +51,10 @@ services:
|
|||||||
start_period: 10s
|
start_period: 10s
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: ${GITEA_REGISTRY_URL:-git.allucanget.biz}/${GITEA_REGISTRY_NAMESPACE:-zwitschi/linearvoid}/nginx:latest
|
image: ${CI_REGISTRY_URL:-git.allucanget.biz}/${CI_REGISTRY_NAMESPACE:-zwitschi/linearvoid}/nginx:latest
|
||||||
build:
|
build:
|
||||||
context: ./infrastructure/nginx
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: infrastructure/nginx/Dockerfile
|
||||||
container_name: linearvoid-nginx
|
container_name: linearvoid-nginx
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -217,6 +217,65 @@ Notable aspects: Manifest freshness ensures all viewers stay on same timeline; c
|
|||||||
|
|
||||||
## Deployment View
|
## Deployment View
|
||||||
|
|
||||||
|
### CI/CD Pipeline Architecture
|
||||||
|
|
||||||
|
The deployment follows a two-stage pipeline: **CI builds and pushes images**, then **CD pulls and deploys** them to the production host.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph "Gitea Actions"
|
||||||
|
CI[CI Workflow<br/>Build + Push Images]
|
||||||
|
CD[CD Workflow<br/>Pull + Deploy]
|
||||||
|
end
|
||||||
|
subgraph "Gitea Container Registry"
|
||||||
|
REGISTRY[git.allucanget.biz<br/>playout:latest<br/>chat:latest<br/>nginx:latest]
|
||||||
|
end
|
||||||
|
subgraph "Production Host (192.168.88.40)"
|
||||||
|
DOCKER[Docker Engine<br/>via TCP :2375]
|
||||||
|
PLAYOUT[linearvoid-playout]
|
||||||
|
CHAT[linearvoid-chat]
|
||||||
|
NGINX[linearvoid-nginx]
|
||||||
|
REDIS[linearvoid-redis]
|
||||||
|
DB[linearvoid-db]
|
||||||
|
PROM[linearvoid-prometheus]
|
||||||
|
GRAF[linearvoid-grafana]
|
||||||
|
end
|
||||||
|
|
||||||
|
CI -->|push| REGISTRY
|
||||||
|
REGISTRY -->|pull| CD
|
||||||
|
CD -->|deploy via DOCKER_HOST| DOCKER
|
||||||
|
DOCKER --> PLAYOUT
|
||||||
|
DOCKER --> CHAT
|
||||||
|
DOCKER --> NGINX
|
||||||
|
DOCKER --> REDIS
|
||||||
|
DOCKER --> DB
|
||||||
|
DOCKER --> PROM
|
||||||
|
DOCKER --> GRAF
|
||||||
|
|
||||||
|
classDef ci fill:#e1f5fe,stroke:#0288d1
|
||||||
|
classDef reg fill:#fff3e0,stroke:#f57c00
|
||||||
|
classDef prod fill:#e8f5e9,stroke:#388e3c
|
||||||
|
class CI,CD ci
|
||||||
|
class REGISTRY reg
|
||||||
|
class DOCKER,PLAYOUT,CHAT,NGINX,REDIS,DB,PROM,GRAF prod
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pipeline Sequence:**
|
||||||
|
|
||||||
|
1. **CI Workflow** (`.gitea/workflows/ci.yml`):
|
||||||
|
- Triggers on `push` to `main` or `pull_request`
|
||||||
|
- Runs `test` job: frontend lint/build, Go validation, `docker compose build`
|
||||||
|
- Runs `docker` job (after `test` passes, only on `main` push):
|
||||||
|
- Builds `playout`, `chat`, `nginx` images with Buildx
|
||||||
|
- Pushes to Gitea Container Registry with `main` and `latest` tags
|
||||||
|
2. **CD Workflow** (`.gitea/workflows/cd.yml`):
|
||||||
|
- Triggers on `workflow_run` when CI completes successfully, or manually via `workflow_dispatch`
|
||||||
|
- Pulls latest images from registry
|
||||||
|
- Generates `.env` from secrets
|
||||||
|
- Seeds Prometheus config into named volume
|
||||||
|
- Deploys via `docker compose -f docker-compose.prod.yml up -d` to remote host (`192.168.88.40:2375`)
|
||||||
|
- Runs health checks with retry logic for playout initialization
|
||||||
|
|
||||||
### Infrastructure Level 1
|
### Infrastructure Level 1
|
||||||
|
|
||||||
**Overview Diagram**: See Mermaid in Building Block section (VPS + Cloudflare R2/Pages/CDN).
|
**Overview Diagram**: See Mermaid in Building Block section (VPS + Cloudflare R2/Pages/CDN).
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
|
# Stage 1: Build frontend
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
WORKDIR /build
|
||||||
|
COPY frontend/package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY frontend/ .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 2: Nginx with bundled frontend
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
COPY infrastructure/nginx/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
# Create directories for HLS and frontend
|
# Copy prebuilt frontend from builder stage
|
||||||
RUN mkdir -p /srv/frontend /srv/hls /srv/frontend/admin
|
COPY --from=builder /build/dist/ /srv/frontend/
|
||||||
|
|
||||||
|
# Create HLS directory
|
||||||
|
RUN mkdir -p /srv/hls
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"title": "Linear Void Monitoring",
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"title": "Concurrent Viewers",
|
||||||
|
"type": "timeseries",
|
||||||
|
"targets": [{ "expr": "linearvoid_chat_connected_clients" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Stored Messages",
|
||||||
|
"type": "stat",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "linearvoid_chat_messages_total"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Moderation Actions",
|
||||||
|
"type": "timeseries",
|
||||||
|
"targets": [{ "expr": "linearvoid_chat_moderation_actions_total" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Redis Reachable",
|
||||||
|
"type": "stat",
|
||||||
|
"targets": [{ "expr": "linearvoid_chat_redis_up" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Admin Sessions",
|
||||||
|
"type": "timeseries",
|
||||||
|
"targets": [{ "expr": "linearvoid_chat_admin_sessions_active" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Chat Scrape Health",
|
||||||
|
"type": "stat",
|
||||||
|
"targets": [{ "expr": "up{job=\"chat\"}" }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: "chat"
|
||||||
|
static_configs:
|
||||||
|
- targets: ["chat:3000"]
|
||||||
|
- job_name: "prometheus"
|
||||||
|
static_configs:
|
||||||
|
- targets: ["prometheus:9090"]
|
||||||
Reference in new issue
Block a user