feat: 新增 Docker Compose 一键部署(MySQL + 后端 + 前端)
- 新增 docker-compose.yml,按健康检查顺序启动 MySQL 8、Go 后端与 Nginx 前端 - 新增 server/web 多阶段 Dockerfile、nginx 反向代理配置与 .dockerignore - 后端支持 KENAITO_* 环境变量覆盖配置,新增 /health 健康检查接口 - 补充中英文 README 与 Docker 部署文档、.env.example 环境变量模板
This commit is contained in:
@@ -42,7 +42,10 @@ func Load(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
active := baseProps["active"]
|
||||
active := os.Getenv("KENAITO_ACTIVE")
|
||||
if active == "" {
|
||||
active = baseProps["active"]
|
||||
}
|
||||
if active == "" {
|
||||
return fmt.Errorf("missing required config: active")
|
||||
}
|
||||
@@ -60,17 +63,18 @@ func Load(path string) error {
|
||||
|
||||
Cfg = &Config{}
|
||||
|
||||
Cfg.Server.Port = intProp(baseProps, "server.port", 8080)
|
||||
Cfg.Server.Port = envInt("KENAITO_SERVER_PORT", intProp(baseProps, "server.port", 8080))
|
||||
setServerMode(active)
|
||||
|
||||
Cfg.Database.Host = baseProps["database.host"]
|
||||
Cfg.Database.Port = intProp(baseProps, "database.port", 3306)
|
||||
Cfg.Database.Name = baseProps["database.name"]
|
||||
Cfg.Database.User = baseProps["database.user"]
|
||||
Cfg.Database.Password = baseProps["database.password"]
|
||||
// 环境变量优先,便于容器化部署时覆盖配置文件
|
||||
Cfg.Database.Host = envStr("KENAITO_DB_HOST", baseProps["database.host"])
|
||||
Cfg.Database.Port = envInt("KENAITO_DB_PORT", intProp(baseProps, "database.port", 3306))
|
||||
Cfg.Database.Name = envStr("KENAITO_DB_NAME", baseProps["database.name"])
|
||||
Cfg.Database.User = envStr("KENAITO_DB_USER", baseProps["database.user"])
|
||||
Cfg.Database.Password = envStr("KENAITO_DB_PASSWORD", baseProps["database.password"])
|
||||
|
||||
Cfg.JWT.Secret = baseProps["jwt.secret"]
|
||||
Cfg.JWT.ExpireHours = intProp(baseProps, "jwt.expireHours", 24)
|
||||
Cfg.JWT.Secret = envStr("KENAITO_JWT_SECRET", baseProps["jwt.secret"])
|
||||
Cfg.JWT.ExpireHours = envInt("KENAITO_JWT_EXPIRE_HOURS", intProp(baseProps, "jwt.expireHours", 24))
|
||||
|
||||
if Cfg.Database.Host == "" {
|
||||
return fmt.Errorf("missing required config: database.host")
|
||||
@@ -82,7 +86,7 @@ func Load(path string) error {
|
||||
func setServerMode(active string) {
|
||||
if "daily" == active {
|
||||
Cfg.Server.Mode = gin.DebugMode
|
||||
} else if "stage" == active || "online" == active {
|
||||
} else if "stage" == active || "online" == active || "docker" == active {
|
||||
Cfg.Server.Mode = gin.ReleaseMode
|
||||
} else {
|
||||
Cfg.Server.Mode = gin.DebugMode
|
||||
@@ -129,6 +133,27 @@ func intProp(props map[string]string, key string, defaultVal int) int {
|
||||
return n
|
||||
}
|
||||
|
||||
// envStr 返回环境变量值,未设置时使用 fallback
|
||||
func envStr(key, fallback string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
// envInt 返回整数环境变量值,未设置或非法时使用 fallback
|
||||
func envInt(key string, fallback int) int {
|
||||
v := os.Getenv(key)
|
||||
if v == "" {
|
||||
return fallback
|
||||
}
|
||||
n, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (d *DatabaseConfig) DSN() string {
|
||||
return d.User + ":" + d.Password + "@tcp(" + d.Host + ":" + strconv.Itoa(d.Port) + ")/" + d.Name + "?charset=utf8&parseTime=true&loc=Local"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"kenaito-conf/server/internal/dao"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type HealthHandler struct{}
|
||||
|
||||
func NewHealthHandler() *HealthHandler {
|
||||
return &HealthHandler{}
|
||||
}
|
||||
|
||||
// Check 用于容器健康检查,数据库不可用时返回 503
|
||||
func (h *HealthHandler) Check(c *gin.Context) {
|
||||
if dao.Engine == nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"status": "error", "message": "database not initialized"})
|
||||
return
|
||||
}
|
||||
if err := dao.Engine.Ping(); err != nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"status": "error", "message": "database unavailable"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||
}
|
||||
Reference in New Issue
Block a user