fix: 数据持久化到/app/data目录,简化部署配置
- 配置文件和SQLite数据库存储在/app/data - Docker volume持久化数据 - 无需预设环境变量,安装向导自动配置
This commit is contained in:
@@ -2,29 +2,40 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init 初始化配置
|
var dataDir = "/app/data"
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
|
if dir := os.Getenv("DATA_DIR"); dir != "" {
|
||||||
|
dataDir = dir
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
|
||||||
|
os.MkdirAll(dataDir, 0755)
|
||||||
|
}
|
||||||
|
|
||||||
viper.SetConfigName("config")
|
viper.SetConfigName("config")
|
||||||
viper.SetConfigType("yaml")
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AddConfigPath(dataDir)
|
||||||
viper.AddConfigPath(".")
|
viper.AddConfigPath(".")
|
||||||
viper.AddConfigPath("./config")
|
viper.AddConfigPath("./config")
|
||||||
|
|
||||||
// 设置默认值
|
|
||||||
setDefaults()
|
setDefaults()
|
||||||
|
|
||||||
// 读取配置文件
|
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
log.Printf("Warning: Config file not found, using defaults: %v", err)
|
log.Printf("Warning: Config file not found, using defaults: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 环境变量覆盖
|
|
||||||
viper.AutomaticEnv()
|
viper.AutomaticEnv()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDataDir() string {
|
||||||
|
return dataDir
|
||||||
|
}
|
||||||
|
|
||||||
// setDefaults 设置默认配置值
|
// setDefaults 设置默认配置值
|
||||||
func setDefaults() {
|
func setDefaults() {
|
||||||
// 应用配置
|
// 应用配置
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
"verification-platform-backend/internal/config"
|
"verification-platform-backend/internal/config"
|
||||||
@@ -52,26 +51,18 @@ func initDatabase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initSQLite() {
|
func initSQLite() {
|
||||||
dbPath := "verification_platform.db"
|
dataDir := config.GetDataDir()
|
||||||
absPath, err := filepath.Abs(dbPath)
|
dbPath := filepath.Join(dataDir, "verification_platform.db")
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to get absolute path:", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err == nil && filepath.Base(wd) == "cmd" {
|
|
||||||
absPath = filepath.Join(filepath.Dir(wd), "verification_platform.db")
|
|
||||||
}
|
|
||||||
|
|
||||||
var errOpen error
|
var errOpen error
|
||||||
DB, errOpen = gorm.Open(sqlite.Open(absPath), &gorm.Config{
|
DB, errOpen = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||||
Logger: logger.Default.LogMode(logger.Silent),
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
})
|
})
|
||||||
if errOpen != nil {
|
if errOpen != nil {
|
||||||
log.Fatal("Failed to create SQLite database:", errOpen.Error())
|
log.Fatal("Failed to create SQLite database:", errOpen.Error())
|
||||||
}
|
}
|
||||||
log.Printf("Using SQLite database: %s\n", absPath)
|
log.Printf("Using SQLite database: %s\n", dbPath)
|
||||||
|
|
||||||
if sqlDB, err := DB.DB(); err == nil {
|
if sqlDB, err := DB.DB(); err == nil {
|
||||||
sqlDB.SetMaxIdleConns(10)
|
sqlDB.SetMaxIdleConns(10)
|
||||||
@@ -132,27 +123,19 @@ func initAutoDetect() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to connect to MySQL, using SQLite database for development:", err.Error())
|
log.Println("Failed to connect to MySQL, using SQLite database:", err.Error())
|
||||||
|
|
||||||
dbPath := "verification_platform.db"
|
dataDir := config.GetDataDir()
|
||||||
absPath, err := filepath.Abs(dbPath)
|
dbPath := filepath.Join(dataDir, "verification_platform.db")
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to get absolute path:", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
DB, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||||
if err == nil && filepath.Base(wd) == "cmd" {
|
|
||||||
absPath = filepath.Join(filepath.Dir(wd), "verification_platform.db")
|
|
||||||
}
|
|
||||||
|
|
||||||
DB, err = gorm.Open(sqlite.Open(absPath), &gorm.Config{
|
|
||||||
Logger: logger.Default.LogMode(logger.Silent),
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to create SQLite database:", err.Error())
|
log.Fatal("Failed to create SQLite database:", err.Error())
|
||||||
}
|
}
|
||||||
log.Printf("Database file path: %s\n", absPath)
|
log.Printf("Using SQLite database: %s\n", dbPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sqlDB, err := DB.DB(); err == nil {
|
if sqlDB, err := DB.DB(); err == nil {
|
||||||
|
|||||||
@@ -80,9 +80,9 @@ func handleTestDatabase(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if req.DbType == "sqlite" {
|
if req.DbType == "sqlite" {
|
||||||
dbPath := "verification_platform.db"
|
dataDir := config.GetDataDir()
|
||||||
absPath, _ := filepath.Abs(dbPath)
|
dbPath := filepath.Join(dataDir, "verification_platform.db")
|
||||||
testDB, err := gorm.Open(sqlite.Open(absPath), &gorm.Config{
|
testDB, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||||
Logger: logger.Default.LogMode(logger.Silent),
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -167,9 +167,9 @@ func handleSetup(c *gin.Context) {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if req.DbType == "sqlite" {
|
if req.DbType == "sqlite" {
|
||||||
dbPath := "verification_platform.db"
|
dataDir := config.GetDataDir()
|
||||||
absPath, _ := filepath.Abs(dbPath)
|
dbPath := filepath.Join(dataDir, "verification_platform.db")
|
||||||
newDB, err = gorm.Open(sqlite.Open(absPath), &gorm.Config{
|
newDB, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||||
Logger: logger.Default.LogMode(logger.Silent),
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
})
|
})
|
||||||
@@ -241,6 +241,11 @@ func handleSetup(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkConfigFile() bool {
|
func checkConfigFile() bool {
|
||||||
|
dataDir := config.GetDataDir()
|
||||||
|
configPath := filepath.Join(dataDir, "config.yaml")
|
||||||
|
if _, err := os.Stat(configPath); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
paths := []string{"config.yaml", "./config/config.yaml"}
|
paths := []string{"config.yaml", "./config/config.yaml"}
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
if _, err := os.Stat(p); err == nil {
|
if _, err := os.Stat(p); err == nil {
|
||||||
@@ -338,7 +343,9 @@ func generateConfigFile(dbType string, req SetupRequest, jwtSecret string) strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func saveConfigFile(content string) error {
|
func saveConfigFile(content string) error {
|
||||||
file, err := os.Create("config.yaml")
|
dataDir := config.GetDataDir()
|
||||||
|
configPath := filepath.Join(dataDir, "config.yaml")
|
||||||
|
file, err := os.Create(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-30
@@ -1,4 +1,16 @@
|
|||||||
services:
|
services:
|
||||||
|
app:
|
||||||
|
image: ghcr.io/cmakecpp/verify:main
|
||||||
|
container_name: verify-app
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${APP_PORT:-8080}:8080"
|
||||||
|
volumes:
|
||||||
|
- app_data:/app/data
|
||||||
|
- uploads:/app/uploads
|
||||||
|
networks:
|
||||||
|
- verify-network
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
container_name: verify-mysql
|
container_name: verify-mysql
|
||||||
@@ -8,42 +20,13 @@ services:
|
|||||||
MYSQL_DATABASE: ${MYSQL_DATABASE:-verification_platform}
|
MYSQL_DATABASE: ${MYSQL_DATABASE:-verification_platform}
|
||||||
MYSQL_CHARACTER_SET_SERVER: utf8mb4
|
MYSQL_CHARACTER_SET_SERVER: utf8mb4
|
||||||
MYSQL_COLLATION_SERVER: utf8mb4_unicode_ci
|
MYSQL_COLLATION_SERVER: utf8mb4_unicode_ci
|
||||||
ports:
|
|
||||||
- "${MYSQL_PORT:-3306}:3306"
|
|
||||||
volumes:
|
volumes:
|
||||||
- mysql_data:/var/lib/mysql
|
- mysql_data:/var/lib/mysql
|
||||||
networks:
|
networks:
|
||||||
- verify-network
|
- verify-network
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
app:
|
|
||||||
image: ghcr.io/cmakecpp/verify:main
|
|
||||||
container_name: verify-app
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
- APP_ENV=production
|
|
||||||
- APP_PORT=8080
|
|
||||||
- APP_JWT_SECRET=${JWT_SECRET:-your-jwt-secret-change-me}
|
|
||||||
- DATABASE_HOST=mysql
|
|
||||||
- DATABASE_PORT=3306
|
|
||||||
- DATABASE_NAME=${MYSQL_DATABASE:-verification_platform}
|
|
||||||
- DATABASE_USERNAME=root
|
|
||||||
- DATABASE_PASSWORD=${MYSQL_ROOT_PASSWORD:-root123456}
|
|
||||||
ports:
|
|
||||||
- "${APP_PORT:-8080}:8080"
|
|
||||||
volumes:
|
|
||||||
- uploads:/app/uploads
|
|
||||||
depends_on:
|
|
||||||
mysql:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- verify-network
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
app_data:
|
||||||
mysql_data:
|
mysql_data:
|
||||||
uploads:
|
uploads:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user