feat: initial installer release
Installer scripts and compose templates for deploying the Cameleer SaaS platform. Supports multi-tenant SaaS and standalone modes. Bootstrap: curl -fsSL https://registry.cameleer.io/.../get-cameleer.sh | bash Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
57
get-cameleer.ps1
Normal file
57
get-cameleer.ps1
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Bootstrap script — downloads the Cameleer installer and runs it.
|
||||||
|
.EXAMPLE
|
||||||
|
irm https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw/branch/main/get-cameleer.ps1 | iex
|
||||||
|
.\get-cameleer.ps1 -Version v1.2.0
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[string]$Version,
|
||||||
|
[string]$Ref,
|
||||||
|
[switch]$Run
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$Repo = 'https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw'
|
||||||
|
if ($Version) { $RefPath = "tag/$Version" }
|
||||||
|
elseif ($Ref) { $RefPath = "branch/$Ref" }
|
||||||
|
else { $RefPath = 'branch/main' }
|
||||||
|
|
||||||
|
$Base = "$Repo/$RefPath"
|
||||||
|
$Dir = '.\installer'
|
||||||
|
|
||||||
|
$Files = @(
|
||||||
|
'install.sh'
|
||||||
|
'templates/docker-compose.yml'
|
||||||
|
'templates/docker-compose.saas.yml'
|
||||||
|
'templates/docker-compose.server.yml'
|
||||||
|
'templates/docker-compose.tls.yml'
|
||||||
|
'templates/docker-compose.monitoring.yml'
|
||||||
|
'templates/traefik-dynamic.yml'
|
||||||
|
'templates/.env.example'
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host 'Downloading Cameleer installer...'
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path "$Dir\templates" -Force | Out-Null
|
||||||
|
|
||||||
|
foreach ($file in $Files) {
|
||||||
|
$localPath = Join-Path $Dir $file
|
||||||
|
$localDir = Split-Path $localPath -Parent
|
||||||
|
if (-not (Test-Path $localDir)) { New-Item -ItemType Directory -Path $localDir -Force | Out-Null }
|
||||||
|
|
||||||
|
Write-Host " $file"
|
||||||
|
Invoke-WebRequest -Uri "$Base/$file" -OutFile $localPath -UseBasicParsing
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host "Installer ready in $Dir\"
|
||||||
|
Write-Host 'Run: cd installer; .\install.sh'
|
||||||
|
Write-Host ''
|
||||||
|
|
||||||
|
if ($Run) {
|
||||||
|
Set-Location $Dir
|
||||||
|
& .\install.sh @args
|
||||||
|
}
|
||||||
55
get-cameleer.sh
Normal file
55
get-cameleer.sh
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Bootstrap script — downloads the Cameleer installer and runs it.
|
||||||
|
# Usage:
|
||||||
|
# curl -fsSL https://get.cameleer.io/install | bash
|
||||||
|
# curl -fsSL https://get.cameleer.io/install | bash -s -- --version v1.2.0
|
||||||
|
|
||||||
|
REPO="https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw"
|
||||||
|
REF="branch/main"
|
||||||
|
DIR="./installer"
|
||||||
|
|
||||||
|
# Parse --version / --ref
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--version=*) REF="tag/${arg#*=}"; shift ;;
|
||||||
|
--ref=*) REF="branch/${arg#*=}"; shift ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
BASE="$REPO/$REF"
|
||||||
|
|
||||||
|
FILES=(
|
||||||
|
"install.sh"
|
||||||
|
"templates/docker-compose.yml"
|
||||||
|
"templates/docker-compose.saas.yml"
|
||||||
|
"templates/docker-compose.server.yml"
|
||||||
|
"templates/docker-compose.tls.yml"
|
||||||
|
"templates/docker-compose.monitoring.yml"
|
||||||
|
"templates/traefik-dynamic.yml"
|
||||||
|
"templates/.env.example"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "Downloading Cameleer installer..."
|
||||||
|
|
||||||
|
mkdir -p "$DIR/templates"
|
||||||
|
|
||||||
|
for file in "${FILES[@]}"; do
|
||||||
|
echo " $file"
|
||||||
|
curl -fsSL "$BASE/$file" -o "$DIR/$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
chmod +x "$DIR/install.sh"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Installer ready in $DIR/"
|
||||||
|
echo "Run: cd $DIR && ./install.sh"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Auto-run if not piped with extra args that look like they want manual control
|
||||||
|
if [ "${1:-}" = "--run" ]; then
|
||||||
|
shift
|
||||||
|
cd "$DIR"
|
||||||
|
exec ./install.sh "$@"
|
||||||
|
fi
|
||||||
1525
install.sh
Normal file
1525
install.sh
Normal file
File diff suppressed because it is too large
Load Diff
102
templates/.env.example
Normal file
102
templates/.env.example
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Cameleer Configuration
|
||||||
|
# Copy this file to .env and fill in the values.
|
||||||
|
# The installer generates .env automatically — this file is for reference.
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Compose file assembly (set by installer)
|
||||||
|
# ============================================================
|
||||||
|
# SaaS: docker-compose.yml:docker-compose.saas.yml
|
||||||
|
# Standalone: docker-compose.yml:docker-compose.server.yml
|
||||||
|
# Add :docker-compose.tls.yml for custom TLS certificates
|
||||||
|
# Add :docker-compose.monitoring.yml for external monitoring network
|
||||||
|
COMPOSE_FILE=docker-compose.yml:docker-compose.saas.yml
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Image version
|
||||||
|
# ============================================================
|
||||||
|
VERSION=latest
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Public access
|
||||||
|
# ============================================================
|
||||||
|
PUBLIC_HOST=localhost
|
||||||
|
PUBLIC_PROTOCOL=https
|
||||||
|
# Auth domain (Logto). Defaults to PUBLIC_HOST for single-domain setups.
|
||||||
|
# Set to a separate subdomain (e.g. auth.cameleer.io) to split auth from the app.
|
||||||
|
# AUTH_HOST=localhost
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Ports
|
||||||
|
# ============================================================
|
||||||
|
HTTP_PORT=80
|
||||||
|
HTTPS_PORT=443
|
||||||
|
# Set to 0.0.0.0 to expose Logto admin console externally (default: localhost only)
|
||||||
|
# LOGTO_CONSOLE_BIND=0.0.0.0
|
||||||
|
LOGTO_CONSOLE_PORT=3002
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PostgreSQL
|
||||||
|
# ============================================================
|
||||||
|
POSTGRES_USER=cameleer
|
||||||
|
POSTGRES_PASSWORD=CHANGE_ME
|
||||||
|
# SaaS: cameleer_saas, Standalone: cameleer
|
||||||
|
POSTGRES_DB=cameleer_saas
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# ClickHouse
|
||||||
|
# ============================================================
|
||||||
|
CLICKHOUSE_PASSWORD=CHANGE_ME
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Admin credentials (SaaS mode)
|
||||||
|
# ============================================================
|
||||||
|
SAAS_ADMIN_USER=admin
|
||||||
|
SAAS_ADMIN_PASS=CHANGE_ME
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Admin credentials (standalone mode)
|
||||||
|
# ============================================================
|
||||||
|
# SERVER_ADMIN_USER=admin
|
||||||
|
# SERVER_ADMIN_PASS=CHANGE_ME
|
||||||
|
# BOOTSTRAP_TOKEN=CHANGE_ME
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# SMTP (for email verification during registration)
|
||||||
|
# ============================================================
|
||||||
|
# Required for self-service sign-up. Without SMTP, only admin-created users can sign in.
|
||||||
|
SMTP_HOST=
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USER=
|
||||||
|
SMTP_PASS=
|
||||||
|
SMTP_FROM_EMAIL=noreply@cameleer.io
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# TLS
|
||||||
|
# ============================================================
|
||||||
|
# Set to 1 to reject unauthorized TLS certificates (production)
|
||||||
|
NODE_TLS_REJECT=0
|
||||||
|
# Custom TLS certificate paths (inside container, set by installer)
|
||||||
|
# CERT_FILE=/user-certs/cert.pem
|
||||||
|
# KEY_FILE=/user-certs/key.pem
|
||||||
|
# CA_FILE=/user-certs/ca.pem
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Docker
|
||||||
|
# ============================================================
|
||||||
|
DOCKER_SOCKET=/var/run/docker.sock
|
||||||
|
# GID of the docker socket — detected by installer, used for container group_add
|
||||||
|
DOCKER_GID=0
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Provisioning images (SaaS mode only)
|
||||||
|
# ============================================================
|
||||||
|
# CAMELEER_SAAS_PROVISIONING_SERVERIMAGE=gitea.siegeln.net/cameleer/cameleer-server:latest
|
||||||
|
# CAMELEER_SAAS_PROVISIONING_SERVERUIIMAGE=gitea.siegeln.net/cameleer/cameleer-server-ui:latest
|
||||||
|
# CAMELEER_SAAS_PROVISIONING_RUNTIMEBASEIMAGE=gitea.siegeln.net/cameleer/cameleer-runtime-base:latest
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Monitoring (optional)
|
||||||
|
# ============================================================
|
||||||
|
# External Docker network name for Prometheus scraping.
|
||||||
|
# Only needed when docker-compose.monitoring.yml is in COMPOSE_FILE.
|
||||||
|
# MONITORING_NETWORK=prometheus
|
||||||
7
templates/docker-compose.monitoring.yml
Normal file
7
templates/docker-compose.monitoring.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# External monitoring network overlay
|
||||||
|
# Overrides the noop monitoring bridge with a real external network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
monitoring:
|
||||||
|
external: true
|
||||||
|
name: ${MONITORING_NETWORK:?MONITORING_NETWORK must be set in .env}
|
||||||
131
templates/docker-compose.saas.yml
Normal file
131
templates/docker-compose.saas.yml
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# Cameleer SaaS — Logto + management plane
|
||||||
|
# Loaded in SaaS deployment mode
|
||||||
|
|
||||||
|
services:
|
||||||
|
cameleer-logto:
|
||||||
|
image: ${LOGTO_IMAGE:-gitea.siegeln.net/cameleer/cameleer-logto}:${VERSION:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
cameleer-postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
DB_URL: postgres://${POSTGRES_USER:-cameleer}:${POSTGRES_PASSWORD}@cameleer-postgres:5432/logto
|
||||||
|
ENDPOINT: ${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}
|
||||||
|
ADMIN_ENDPOINT: ${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}:${LOGTO_CONSOLE_PORT:-3002}
|
||||||
|
TRUST_PROXY_HEADER: 1
|
||||||
|
NODE_TLS_REJECT_UNAUTHORIZED: "${NODE_TLS_REJECT:-0}"
|
||||||
|
LOGTO_ENDPOINT: http://cameleer-logto:3001
|
||||||
|
LOGTO_ADMIN_ENDPOINT: http://cameleer-logto:3002
|
||||||
|
LOGTO_PUBLIC_ENDPOINT: ${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}
|
||||||
|
PUBLIC_HOST: ${PUBLIC_HOST:-localhost}
|
||||||
|
AUTH_HOST: ${AUTH_HOST:-localhost}
|
||||||
|
PUBLIC_PROTOCOL: ${PUBLIC_PROTOCOL:-https}
|
||||||
|
PG_HOST: cameleer-postgres
|
||||||
|
PG_USER: ${POSTGRES_USER:-cameleer}
|
||||||
|
PG_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
PG_DB_SAAS: cameleer_saas
|
||||||
|
SAAS_ADMIN_USER: ${SAAS_ADMIN_USER:-admin}
|
||||||
|
SAAS_ADMIN_PASS: ${SAAS_ADMIN_PASS:?SAAS_ADMIN_PASS must be set in .env}
|
||||||
|
# SMTP (for email verification during registration)
|
||||||
|
SMTP_HOST: ${SMTP_HOST:-}
|
||||||
|
SMTP_PORT: ${SMTP_PORT:-587}
|
||||||
|
SMTP_USER: ${SMTP_USER:-}
|
||||||
|
SMTP_PASS: ${SMTP_PASS:-}
|
||||||
|
SMTP_FROM_EMAIL: ${SMTP_FROM_EMAIL:-noreply@cameleer.io}
|
||||||
|
extra_hosts:
|
||||||
|
# Logto validates M2M tokens by fetching its own JWKS from ENDPOINT.
|
||||||
|
# Route the public hostname back to the Docker host (Traefik on :443)
|
||||||
|
# so the container can reach itself without going through the tunnel.
|
||||||
|
- "${AUTH_HOST:-localhost}:host-gateway"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3001/oidc/.well-known/openid-configuration', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\" && test -f /data/logto-bootstrap.json"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 60
|
||||||
|
start_period: 30s
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- "traefik.http.routers.cameleer-logto.rule=Host(`${AUTH_HOST:-localhost}`)"
|
||||||
|
- traefik.http.routers.cameleer-logto.priority=1
|
||||||
|
- traefik.http.routers.cameleer-logto.entrypoints=websecure
|
||||||
|
- traefik.http.routers.cameleer-logto.tls=true
|
||||||
|
- traefik.http.routers.cameleer-logto.service=cameleer-logto
|
||||||
|
- traefik.http.routers.cameleer-logto.middlewares=cameleer-logto-cors
|
||||||
|
- "traefik.http.middlewares.cameleer-logto-cors.headers.accessControlAllowOriginList=${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}:${LOGTO_CONSOLE_PORT:-3002}"
|
||||||
|
- traefik.http.middlewares.cameleer-logto-cors.headers.accessControlAllowMethods=GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||||
|
- traefik.http.middlewares.cameleer-logto-cors.headers.accessControlAllowHeaders=Authorization,Content-Type
|
||||||
|
- traefik.http.middlewares.cameleer-logto-cors.headers.accessControlAllowCredentials=true
|
||||||
|
- traefik.http.services.cameleer-logto.loadbalancer.server.port=3001
|
||||||
|
- traefik.http.routers.cameleer-logto-console.rule=PathPrefix(`/`)
|
||||||
|
- traefik.http.routers.cameleer-logto-console.entrypoints=admin-console
|
||||||
|
- traefik.http.routers.cameleer-logto-console.tls=true
|
||||||
|
- traefik.http.routers.cameleer-logto-console.service=cameleer-logto-console
|
||||||
|
- traefik.http.services.cameleer-logto-console.loadbalancer.server.port=3002
|
||||||
|
volumes:
|
||||||
|
- cameleer-bootstrapdata:/data
|
||||||
|
networks:
|
||||||
|
- cameleer
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
cameleer-saas:
|
||||||
|
image: ${CAMELEER_IMAGE:-gitea.siegeln.net/cameleer/cameleer-saas}:${VERSION:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
cameleer-logto:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
# SaaS database
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:postgresql://cameleer-postgres:5432/cameleer_saas
|
||||||
|
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER:-cameleer}
|
||||||
|
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
# Identity (Logto)
|
||||||
|
CAMELEER_SAAS_IDENTITY_LOGTOENDPOINT: http://cameleer-logto:3001
|
||||||
|
CAMELEER_SAAS_IDENTITY_LOGTOPUBLICENDPOINT: ${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}
|
||||||
|
CAMELEER_SAAS_IDENTITY_AUTHHOST: ${AUTH_HOST:-localhost}
|
||||||
|
# Provisioning — passed to per-tenant server containers
|
||||||
|
CAMELEER_SAAS_PROVISIONING_PUBLICHOST: ${PUBLIC_HOST:-localhost}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_PUBLICPROTOCOL: ${PUBLIC_PROTOCOL:-https}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_NETWORKNAME: ${COMPOSE_PROJECT_NAME:-cameleer-saas}_cameleer
|
||||||
|
CAMELEER_SAAS_PROVISIONING_TRAEFIKNETWORK: cameleer-traefik
|
||||||
|
CAMELEER_SAAS_PROVISIONING_DATASOURCEUSERNAME: ${POSTGRES_USER:-cameleer}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_DATASOURCEPASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_CLICKHOUSEPASSWORD: ${CLICKHOUSE_PASSWORD}
|
||||||
|
CAMELEER_SERVER_SECURITY_JWTSECRET: ${CAMELEER_SERVER_SECURITY_JWTSECRET:?CAMELEER_SERVER_SECURITY_JWTSECRET must be set in .env}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_SERVERIMAGE: ${CAMELEER_SAAS_PROVISIONING_SERVERIMAGE:-gitea.siegeln.net/cameleer/cameleer-server:latest}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_SERVERUIIMAGE: ${CAMELEER_SAAS_PROVISIONING_SERVERUIIMAGE:-gitea.siegeln.net/cameleer/cameleer-server-ui:latest}
|
||||||
|
CAMELEER_SAAS_PROVISIONING_RUNTIMEBASEIMAGE: ${CAMELEER_SAAS_PROVISIONING_RUNTIMEBASEIMAGE:-gitea.siegeln.net/cameleer/cameleer-runtime-base:latest}
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.saas.rule=PathPrefix(`/platform`)
|
||||||
|
- traefik.http.routers.saas.entrypoints=websecure
|
||||||
|
- traefik.http.routers.saas.tls=true
|
||||||
|
- traefik.http.services.saas.loadbalancer.server.port=8080
|
||||||
|
# Root redirect: / → /platform/ (scoped to app host so it doesn't catch auth domain)
|
||||||
|
- "traefik.http.routers.saas-root.rule=Host(`${PUBLIC_HOST:-localhost}`) && Path(`/`)"
|
||||||
|
- traefik.http.routers.saas-root.priority=100
|
||||||
|
- traefik.http.routers.saas-root.entrypoints=websecure
|
||||||
|
- traefik.http.routers.saas-root.tls=true
|
||||||
|
- traefik.http.routers.saas-root.middlewares=root-to-platform
|
||||||
|
- traefik.http.routers.saas-root.service=saas
|
||||||
|
- "traefik.http.middlewares.root-to-platform.redirectRegex.regex=^(https?://[^/]+)/?$$"
|
||||||
|
- "traefik.http.middlewares.root-to-platform.redirectRegex.replacement=$${1}/platform/"
|
||||||
|
- traefik.http.middlewares.root-to-platform.redirectRegex.permanent=false
|
||||||
|
- "prometheus.io/scrape=true"
|
||||||
|
- "prometheus.io/port=8080"
|
||||||
|
- "prometheus.io/path=/platform/actuator/prometheus"
|
||||||
|
volumes:
|
||||||
|
- cameleer-bootstrapdata:/data/bootstrap:ro
|
||||||
|
- cameleer-certs:/certs
|
||||||
|
- ${DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
|
||||||
|
group_add:
|
||||||
|
- "${DOCKER_GID:-0}"
|
||||||
|
networks:
|
||||||
|
- cameleer
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
cameleer-bootstrapdata:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
monitoring:
|
||||||
|
name: cameleer-monitoring-noop
|
||||||
99
templates/docker-compose.server.yml
Normal file
99
templates/docker-compose.server.yml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# Cameleer Server (standalone)
|
||||||
|
# Loaded in standalone deployment mode
|
||||||
|
|
||||||
|
services:
|
||||||
|
cameleer-traefik:
|
||||||
|
volumes:
|
||||||
|
- ./traefik-dynamic.yml:/etc/traefik/dynamic.yml:ro
|
||||||
|
|
||||||
|
cameleer-postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-cameleer}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-cameleer} -d $${POSTGRES_DB:-cameleer}"]
|
||||||
|
|
||||||
|
cameleer-server:
|
||||||
|
image: ${SERVER_IMAGE:-gitea.siegeln.net/cameleer/cameleer-server}:${VERSION:-latest}
|
||||||
|
container_name: cameleer-server
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
cameleer-postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
CAMELEER_SERVER_TENANT_ID: default
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:postgresql://cameleer-postgres:5432/${POSTGRES_DB:-cameleer}?currentSchema=tenant_default
|
||||||
|
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER:-cameleer}
|
||||||
|
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
CAMELEER_SERVER_CLICKHOUSE_URL: jdbc:clickhouse://cameleer-clickhouse:8123/cameleer
|
||||||
|
CAMELEER_SERVER_CLICKHOUSE_USERNAME: default
|
||||||
|
CAMELEER_SERVER_CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD}
|
||||||
|
CAMELEER_SERVER_SECURITY_BOOTSTRAPTOKEN: ${BOOTSTRAP_TOKEN:?BOOTSTRAP_TOKEN must be set in .env}
|
||||||
|
CAMELEER_SERVER_SECURITY_JWTSECRET: ${CAMELEER_SERVER_SECURITY_JWTSECRET:?CAMELEER_SERVER_SECURITY_JWTSECRET must be set in .env}
|
||||||
|
CAMELEER_SERVER_SECURITY_UIUSER: ${SERVER_ADMIN_USER:-admin}
|
||||||
|
CAMELEER_SERVER_SECURITY_UIPASSWORD: ${SERVER_ADMIN_PASS:?SERVER_ADMIN_PASS must be set in .env}
|
||||||
|
CAMELEER_SERVER_SECURITY_CORSALLOWEDORIGINS: ${PUBLIC_PROTOCOL:-https}://${PUBLIC_HOST:-localhost}
|
||||||
|
CAMELEER_SERVER_RUNTIME_ENABLED: "true"
|
||||||
|
CAMELEER_SERVER_RUNTIME_SERVERURL: http://cameleer-server:8081
|
||||||
|
CAMELEER_SERVER_RUNTIME_ROUTINGDOMAIN: ${PUBLIC_HOST:-localhost}
|
||||||
|
CAMELEER_SERVER_RUNTIME_ROUTINGMODE: path
|
||||||
|
CAMELEER_SERVER_RUNTIME_JARSTORAGEPATH: /data/jars
|
||||||
|
CAMELEER_SERVER_RUNTIME_DOCKERNETWORK: cameleer-apps
|
||||||
|
CAMELEER_SERVER_RUNTIME_JARDOCKERVOLUME: cameleer-jars
|
||||||
|
CAMELEER_SERVER_RUNTIME_BASEIMAGE: gitea.siegeln.net/cameleer/cameleer-runtime-base:${VERSION:-latest}
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.server-api.rule=PathPrefix(`/api`)
|
||||||
|
- traefik.http.routers.server-api.entrypoints=websecure
|
||||||
|
- traefik.http.routers.server-api.tls=true
|
||||||
|
- traefik.http.services.server-api.loadbalancer.server.port=8081
|
||||||
|
- traefik.docker.network=cameleer-traefik
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -sf http://localhost:8081/api/v1/health || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 30
|
||||||
|
start_period: 30s
|
||||||
|
volumes:
|
||||||
|
- jars:/data/jars
|
||||||
|
- cameleer-certs:/certs:ro
|
||||||
|
- ${DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
|
||||||
|
group_add:
|
||||||
|
- "${DOCKER_GID:-0}"
|
||||||
|
networks:
|
||||||
|
- cameleer
|
||||||
|
- cameleer-traefik
|
||||||
|
- cameleer-apps
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
cameleer-server-ui:
|
||||||
|
image: ${SERVER_UI_IMAGE:-gitea.siegeln.net/cameleer/cameleer-server-ui}:${VERSION:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
cameleer-server:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
CAMELEER_API_URL: http://cameleer-server:8081
|
||||||
|
BASE_PATH: ""
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.ui.rule=PathPrefix(`/`)
|
||||||
|
- traefik.http.routers.ui.priority=1
|
||||||
|
- traefik.http.routers.ui.entrypoints=websecure
|
||||||
|
- traefik.http.routers.ui.tls=true
|
||||||
|
- traefik.http.services.ui.loadbalancer.server.port=80
|
||||||
|
- traefik.docker.network=cameleer-traefik
|
||||||
|
networks:
|
||||||
|
- cameleer-traefik
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
jars:
|
||||||
|
name: cameleer-jars
|
||||||
|
|
||||||
|
networks:
|
||||||
|
cameleer-apps:
|
||||||
|
name: cameleer-apps
|
||||||
|
driver: bridge
|
||||||
|
monitoring:
|
||||||
|
name: cameleer-monitoring-noop
|
||||||
7
templates/docker-compose.tls.yml
Normal file
7
templates/docker-compose.tls.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Custom TLS certificates overlay
|
||||||
|
# Adds user-supplied certificate volume to traefik
|
||||||
|
|
||||||
|
services:
|
||||||
|
cameleer-traefik:
|
||||||
|
volumes:
|
||||||
|
- ./certs:/user-certs:ro
|
||||||
80
templates/docker-compose.yml
Normal file
80
templates/docker-compose.yml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Cameleer Infrastructure
|
||||||
|
# Shared base — always loaded. Mode-specific services in separate compose files.
|
||||||
|
|
||||||
|
services:
|
||||||
|
cameleer-traefik:
|
||||||
|
image: ${TRAEFIK_IMAGE:-gitea.siegeln.net/cameleer/cameleer-traefik}:${VERSION:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${HTTP_PORT:-80}:80"
|
||||||
|
- "${HTTPS_PORT:-443}:443"
|
||||||
|
- "${LOGTO_CONSOLE_BIND:-127.0.0.1}:${LOGTO_CONSOLE_PORT:-3002}:3002"
|
||||||
|
environment:
|
||||||
|
PUBLIC_HOST: ${PUBLIC_HOST:-localhost}
|
||||||
|
AUTH_HOST: ${AUTH_HOST:-localhost}
|
||||||
|
CERT_FILE: ${CERT_FILE:-}
|
||||||
|
KEY_FILE: ${KEY_FILE:-}
|
||||||
|
CA_FILE: ${CA_FILE:-}
|
||||||
|
volumes:
|
||||||
|
- cameleer-certs:/certs
|
||||||
|
- ${DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock:ro
|
||||||
|
labels:
|
||||||
|
- "prometheus.io/scrape=true"
|
||||||
|
- "prometheus.io/port=8082"
|
||||||
|
- "prometheus.io/path=/metrics"
|
||||||
|
networks:
|
||||||
|
- cameleer
|
||||||
|
- cameleer-traefik
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
cameleer-postgres:
|
||||||
|
image: ${POSTGRES_IMAGE:-gitea.siegeln.net/cameleer/cameleer-postgres}:${VERSION:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-cameleer_saas}
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-cameleer}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
|
||||||
|
volumes:
|
||||||
|
- cameleer-pgdata:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-cameleer} -d $${POSTGRES_DB:-cameleer_saas}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- cameleer
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
cameleer-clickhouse:
|
||||||
|
image: ${CLICKHOUSE_IMAGE:-gitea.siegeln.net/cameleer/cameleer-clickhouse}:${VERSION:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:?CLICKHOUSE_PASSWORD must be set in .env}
|
||||||
|
volumes:
|
||||||
|
- cameleer-chdata:/var/lib/clickhouse
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "clickhouse-client --password $${CLICKHOUSE_PASSWORD} --query 'SELECT 1'"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
labels:
|
||||||
|
- "prometheus.io/scrape=true"
|
||||||
|
- "prometheus.io/port=9363"
|
||||||
|
- "prometheus.io/path=/metrics"
|
||||||
|
networks:
|
||||||
|
- cameleer
|
||||||
|
- monitoring
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
cameleer-pgdata:
|
||||||
|
cameleer-chdata:
|
||||||
|
cameleer-certs:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
cameleer:
|
||||||
|
driver: bridge
|
||||||
|
cameleer-traefik:
|
||||||
|
name: cameleer-traefik
|
||||||
|
driver: bridge
|
||||||
|
monitoring:
|
||||||
|
name: cameleer-monitoring-noop
|
||||||
6
templates/traefik-dynamic.yml
Normal file
6
templates/traefik-dynamic.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
tls:
|
||||||
|
stores:
|
||||||
|
default:
|
||||||
|
defaultCertificate:
|
||||||
|
certFile: /certs/cert.pem
|
||||||
|
keyFile: /certs/key.pem
|
||||||
Reference in New Issue
Block a user