woodpecker
Some checks are pending
ci/woodpecker/manual/woodpecker Pipeline is pending

This commit is contained in:
2026-01-15 19:27:41 +01:00
parent e573dfd9cc
commit 102a24d6a3
4 changed files with 282 additions and 1 deletions

28
.woodpecker.yml Normal file
View File

@@ -0,0 +1,28 @@
pipeline:
build:
image: woodpeckerci/plugin-docker
settings:
registry: gitea.infra.mintel.me
repo: gitea.infra.mintel.me/mintel/mb-grid-solutions
username:
from_secret: GITEA_USER
password:
from_secret: GITEA_TOKEN
when:
event: push
branch: main
deploy:
image: alpine
commands:
- apk add --no-cache openssh
- mkdir -p ~/.ssh
- echo "$ALPHA_SSH_KEY" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
- ssh -o StrictHostKeyChecking=no deploy@alpha.mintel.me "mkdir -p /opt/alpha/sites/mb-grid-solutions"
- scp -o StrictHostKeyChecking=no docker-compose.yaml deploy@alpha.mintel.me:/opt/alpha/sites/mb-grid-solutions/docker-compose.yaml
- ssh -o StrictHostKeyChecking=no deploy@alpha.mintel.me "cd /opt/alpha/sites/mb-grid-solutions && docker compose pull && docker compose up -d"
secrets: [ ALPHA_SSH_KEY ]
when:
event: push
branch: main

26
docker-compose.yaml Normal file
View File

@@ -0,0 +1,26 @@
services:
app:
build: .
image: gitea.infra.mintel.me/mintel/mb-grid-solutions:latest
restart: always
expose:
- "3000"
labels:
- "traefik.enable=true"
- "traefik.http.routers.mb-grid-solutions.rule=Host(`mb-grid-solutions.com`, `www.mb-grid-solutions.com`)"
- "traefik.http.routers.mb-grid-solutions.entrypoints=websecure"
- "traefik.http.routers.mb-grid-solutions.tls.certresolver=le"
- "traefik.http.services.mb-grid-solutions.loadbalancer.server.port=3000"
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:3000/health"]
interval: 5s
timeout: 2s
retries: 10
deploy:
replicas: 2
networks:
- alpha
networks:
alpha:
external: true

227
docs/PLATFORM.md Normal file
View File

@@ -0,0 +1,227 @@
# Mintel Alpha Platform — Developer Cheat Sheet
This platform runs real customer websites on their own domains
(e.g. klz-cables.com, shop.customer.de, example.org).
You do not manage servers.
You ship Docker containers.
Mintel runs the platform.
---
## Control Plane (Infra)
These are for developers only (not customers):
Git
https://git.infra.mintel.me
CI
https://ci.infra.mintel.me
Errors (GlitchTip)
https://errors.infra.mintel.me
Analytics (Umami)
https://analytics.infra.mintel.me
Uptime
https://status.infra.mintel.me
Logs
https://logs.infra.mintel.me
---
## Production Platform (Alpha)
Alpha runs all customer websites and listens on ports 80 and 443 for the entire internet.
Customer domains point their DNS A records to the Alpha server IP.
Traefik on Alpha routes domains to the correct containers.
---
## How routing works
Each web service declares which domains it owns via Traefik labels.
Example domains:
- klz-cables.com
- www.klz-cables.com
Traefik routes traffic by Host header.
---
## Directory layout on Alpha
Each app lives in:
/opt/alpha/sites/APP_NAME
This directory contains:
- docker-compose.yml
- .env (optional)
- persistent volumes
---
## Databases
### Postgres (shared)
All apps share one Postgres server but use separate databases.
Connection format:
postgres://infra:infra@postgres:5432/APP_DB
Example:
postgres://infra:infra@postgres:5432/klz_site
Each app must use its own database.
---
### Redis (shared)
All apps share one Redis server but use separate DB indexes.
Connection format:
redis://redis:6379/N
Example:
redis://redis:6379/1
redis://redis:6379/2
Each app must use its own Redis DB number.
---
## Traefik labels (required)
Every public web service must define these labels:
traefik.enable=true
traefik.http.routers.app.rule=Host(klz-cables.com,www.klz-cables.com)
traefik.http.routers.app.entrypoints=websecure
traefik.http.routers.app.tls.certresolver=le
traefik.http.services.app.loadbalancer.server.port=YOUR_INTERNAL_PORT
Traefik automatically provides HTTPS.
---
## Zero-downtime deployments
All web services must support health checks.
Your app must expose:
GET /health
returns HTTP 200 when ready.
Docker Compose example:
healthcheck:
test: wget -q -O - http://localhost:3000/health
interval: 5s
timeout: 2s
retries: 10
Run multiple replicas:
deploy:
replicas: 2
During deploy:
- New containers start
- They become healthy
- Traefik switches traffic
- Old containers are removed
No downtime.
---
## Error tracking (GlitchTip)
Each project gets a DSN, similar to Sentry.
Example:
https://PUBLIC_KEY@errors.infra.mintel.me/PROJECT_ID
Use as SENTRY_DSN in your app.
All errors appear in GlitchTip.
---
## Analytics (Umami)
Each site gets a website ID.
Include this script in your site:
https://analytics.infra.mintel.me/script.js
data-website-id=YOUR_ID
Traffic is visible in Umami.
---
## Deployment via Woodpecker
Woodpecker deploys to Alpha via SSH.
Target:
deploy@alpha.mintel.me
Auth:
ALPHA_SSH_KEY is provided as a CI secret.
---
## Woodpecker pipeline example
Every repo must contain .woodpecker.yml:
pipeline:
deploy:
image: alpine
commands:
- apk add --no-cache openssh
- mkdir -p ~/.ssh
- echo "$ALPHA_SSH_KEY" > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
- ssh -o StrictHostKeyChecking=no deploy@alpha.mintel.me "cd /opt/alpha/sites/APP_NAME && docker compose pull && docker compose up -d"
---
## Monitoring
Errors: GlitchTip
Traffic: Umami
Uptime: Uptime-Kuma
Logs: Dozzle
Infra monitors all services automatically.
---
## Summary
You push code.
Woodpecker deploys.
Traefik routes domains.
Postgres and Redis are shared but isolated.
Zero-downtime updates are automatic.
Errors, traffic and uptime are tracked.
This is a real production platform.

View File

@@ -92,7 +92,7 @@ ${message}
});
// Health check
app.get('/healthz', (req, res) => {
app.get('/health', (req, res) => {
res.status(200).send('OK');
});