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
@@ -3,6 +3,10 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sql-platform/config"
|
||||
"sql-platform/internal/middleware"
|
||||
@@ -82,6 +86,32 @@ func main() {
|
||||
// Routes
|
||||
router.Setup(r)
|
||||
|
||||
// 单镜像部署:直接托管前端产物(DIST_DIR 为空则跳过,开发模式由 vite 独立提供)
|
||||
if distDir := os.Getenv("DIST_DIR"); distDir != "" {
|
||||
indexPath := filepath.Join(distDir, "index.html")
|
||||
if _, err := os.Stat(indexPath); err == nil {
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
p := c.Request.URL.Path
|
||||
if strings.HasPrefix(p, "/api") {
|
||||
c.JSON(http.StatusNotFound, gin.H{"detail": "Not found"})
|
||||
return
|
||||
}
|
||||
// 目录穿越防护后按文件直出(assets/db-logos/favicon),其余回落 SPA index
|
||||
full := filepath.Join(distDir, filepath.Clean("/"+p))
|
||||
if strings.HasPrefix(full, filepath.Clean(distDir)) {
|
||||
if info, err := os.Stat(full); err == nil && !info.IsDir() {
|
||||
c.File(full)
|
||||
return
|
||||
}
|
||||
}
|
||||
c.File(indexPath)
|
||||
})
|
||||
log.Printf("serving frontend from %s", distDir)
|
||||
} else {
|
||||
log.Printf("DIST_DIR=%s 无 index.html,跳过静态托管", distDir)
|
||||
}
|
||||
}
|
||||
|
||||
// Start server
|
||||
addr := fmt.Sprintf(":%s", config.C.Port)
|
||||
log.Printf("SQL Platform Go backend starting on %s", addr)
|
||||
|
||||
Reference in new issue
Block a user