feat(deploy): single-image docker-compose and kubernetes install.sh
- multi-stage root Dockerfile (opsx-loki pattern): frontend dist + go binary + gh-ost in one alpine image, non-root user, HEALTHCHECK, entrypoint warning for missing SECRET_KEY; gin now serves the SPA from DIST_DIR (asset/db-logos/favicon passthrough, /api returns JSON 404, SPA fallback to index.html) - one origin, no CORS surface - docker-compose.yml rewritten: single service, named data volume, no-new-privileges + cap_drop ALL, /health healthcheck, resource limits, log rotation; SECRET_KEY required (openssl rand -hex 32), JWT_SECRET optional (auto-generated and persisted in prod) - kubernetes/: install.sh one-command deploy (idempotent secret reuse, --nodeport/--ingress flags, rollout wait, backup tips) plus namespace/secret/pvc/deployment(single replica + Recreate, probes, resource limits, non-root)/service/nodeport/ingress manifests and README (sqlite single-writer constraints, snapshot backup) - docs: README quick-start now has 3 deployment paths; ARCHITECTURE ch.14 expanded single-image runtime verified locally (SPA/assets/api/login coexist on :9002); full image build left to server (docker hub unreachable from this machine)
This commit is contained in:
1 parent
13fb3aceb3
commit
0b16488029
15 files changed
+683
-34
No files matched your search
+64
-25
@@ -1,30 +1,69 @@
|
||||
# ============================================================
|
||||
# opsxsql - Docker Compose 部署(单镜像,参照 opsx-loki)
|
||||
# 安全基线: 非 root / no-new-privileges / 健康检查 / 资源限额 / 日志轮转
|
||||
# 使用:
|
||||
# export SECRET_KEY=$(openssl rand -hex 32)
|
||||
# export JWT_SECRET=$(openssl rand -hex 32) # 可选;不设则生产模式自动生成并持久化
|
||||
# docker compose up -d --build
|
||||
# 访问: http://localhost:9000 (前后端同源,无需单独的前端容器)
|
||||
# ============================================================
|
||||
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
container_name: sql-audit-backend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- backend-data:/app/data
|
||||
environment:
|
||||
- DATABASE_URL=sqlite+aiosqlite:////app/data/sqlite3.db
|
||||
- DB_PATH=/app/data/sqlite3.db
|
||||
- SECRET_KEY=${SECRET_KEY:-change-me-in-production}
|
||||
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme}
|
||||
- ENV=production
|
||||
- DEBUG=false
|
||||
- CGO_ENABLED=1
|
||||
opsxsql:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
TARGETARCH: ${TARGETARCH:-amd64}
|
||||
image: opsxsql:latest
|
||||
container_name: opsxsql
|
||||
hostname: opsxsql
|
||||
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop:
|
||||
- ALL
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
container_name: sql-audit-frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
depends_on:
|
||||
- backend
|
||||
- "${OPSXSQL_PORT:-9000}:9000"
|
||||
|
||||
volumes:
|
||||
- opsxsql-data:/app/data
|
||||
|
||||
environment:
|
||||
- PORT=9000
|
||||
- DB_PATH=/app/data/sqlite3.db
|
||||
- DEBUG=${DEBUG:-false}
|
||||
# AES 密钥(实例/LDAP 密码加密): 必须外部提供,且部署后不可更换
|
||||
- "SECRET_KEY=${SECRET_KEY:?SECRET_KEY is required. Generate: openssl rand -hex 32}"
|
||||
# JWT 密钥: 可选;生产模式未提供时自动生成随机密钥并持久化到数据卷
|
||||
- JWT_SECRET=${JWT_SECRET:-}
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9000/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 1G
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "5"
|
||||
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 15s
|
||||
|
||||
volumes:
|
||||
backend-data:
|
||||
opsxsql-data:
|
||||
driver: local
|
||||
Reference in new issue
Block a user