This commit is contained in:
28
.woodpecker.yml
Normal file
28
.woodpecker.yml
Normal 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
26
docker-compose.yaml
Normal 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
227
docs/PLATFORM.md
Normal 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.
|
||||||
Reference in New Issue
Block a user