Help us shape the future of Go! Take the 2026 Go Developer Survey

bootstrap

package
v0.32.27 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 96 Imported by: 0

README

bootstrap/ - 服务初始化(库入口)

此目录存放服务启动时的初始化代码。

文件说明

  • bootstrap.go - 初始化入口,协调各组件的初始化顺序

初始化顺序

  1. 配置 - 加载配置文件
  2. 日志 - 初始化日志系统
  3. 数据库 - 建立数据库连接
  4. 缓存 - 建立 Redis 连接
  5. 服务器 - 创建 HTTP 服务器并注册路由

使用方式

// main.go
func main() {
    h, err := bootstrap.Bootstrap("/path/to/config.yaml")
    if err != nil {
        log.Fatal(err)
    }
    defer bootstrap.Cleanup()

    h.Spin()
}

添加新组件初始化

// bootstrap.go
func Bootstrap(configPath string) (*server.Hertz, error) {
    // ... 现有初始化

    // 添加新组件
    if err := initNewComponent(); err != nil {
        return nil, err
    }

    // ...
}

清理资源

func Cleanup() {
    logger.Sync()
    _ = db.Close()
    _ = redis.Close()
    // 添加新组件的清理
}

Documentation

Overview

API Key 临期站内通知(波次3):定期扫描 7 天内到期的有效 Key, 给属主发站内信(带 Webhook 外推),并打去重标记。 通知失败不阻塞扫描(下轮重试);标记成功才视为已通知,绝不重复打扰。

datamigrate.go — 启动期数据迁移(2026-10-26 兼容层清理)。

为什么要 Go 侧迁移而不是 migrations/*.sql: 版本化迁移只在 database.migrate=true 时执行;默认路径走 GORM AutoMigrate, 而 AutoMigrate **不会**做数据回填(也不会删列)。本轮退役的兼容层里有 「存量数据必须先补齐,代码才能删掉兜底」的部分(子表回填),必须两条路径 都生效 ⇒ 实现为幂等的 Go 侧迁移。

全部步骤都幂等:可重复执行,失败只记日志不阻断启动(数据类迁移失败不应 让站点起不来;但读取侧会因缺数据而报错,故日志必须响亮)。

setup_gate.go —— 首启向导(/setup)的暴露面加固(2026-10-22)。

问题

/setup 是**无鉴权**的建号端点,唯一的护栏是「库里还没有 admin」。 ⇒ 一个尚未初始化的实例,**任何能访问到它的人都可以抢先完成首启**并拿到 管理员(setup-race)。此前四个打包面把「没配密码 → 走 /setup」设为默认 (hub/ugreen/terramaster 的 compose entrypoint、qnap 的 prepare_env), 这条默认把暴露面从「弱口令 admin/admin123」换成了「先到先得的管理员」—— 在**内网**是体验升级,在**公网**是新的暴露面。

三道加固(都不改变「不配密码也能用」的默认体验)

  1. **可选令牌**:设 PB_SETUP_TOKEN 后,建号端点需带匹配的 X-Setup-Token 头 (或 ?token= 查询参数 —— 便于把「服务启动日志里的那条链接」直接粘进 浏览器完成首启)。未设 = 不要求(保持默认体验不变)。
  2. **按 IP 失败锁定**:复用 middleware.Lockout(Redis 共享计数,多副本 生效;无 Redis 退进程内)。**只把「令牌不匹配」计为失败**——校验 参数不合法(弱口令等)是用户自己的输入问题,不该把他锁在门外。
  3. **启动告警**:未初始化且未设令牌时,响亮提示暴露面与两种处置办法。

为什么不用「必须令牌」

强制令牌会把「打开浏览器就走完首启」这条最顺的路变成「先翻日志抄令牌」, 与「多部署方式下的第一天体验」这个目标相反。故做成**可选加固**: 内网自托管(NAS)默认零摩擦;公网部署按需一行 env 打开。

Index

Constants

This section is empty.

Variables

View Source
var ErrInsecureDefaultAdmin = errors.New("refusing to create default admin with known default password in production mode")

ErrInsecureDefaultAdmin 生产模式下拒绝以已知默认口令创建默认管理员时返回 (errors.Is 可判)。逃生门:PB_ADMIN_PASSWORD 注入强密码,或 PB_DISABLE_DEFAULT_ADMIN=true 走 /setup 首启向导。

Functions

func Bootstrap

func Bootstrap(configPath string) (*server.Hertz, error)

Bootstrap 应用程序启动入口(兼容入口,等价于无选项的 BootstrapWithOptions)。 configPath 为空时依次回退到 CONFIG_PATH 环境变量、默认 configs/config.yaml。

func BootstrapWithOptions

func BootstrapWithOptions(configPath string, opts ...Option) (*server.Hertz, error)

BootstrapWithOptions 带函数选项的启动入口。 可用选项见 options.go(如 WithStaticDir 覆盖前端静态资源目录)。

func CORS

func CORS() app.HandlerFunc

CORS 跨域中间件(配置化)。

安全策略:

  • 配置了 allow_origins 白名单时,仅放行白名单内的 Origin(生产推荐)
  • 未配置白名单时,退化为反射 Origin(便于本地开发,等同于宽松模式)
  • allow_credentials=true 时,绝不返回 "*",而是精确匹配的 Origin

同时允许 X-Trace-Id / X-API-Key 等自定义请求头跨域。 allow_origins 来源:yaml 的 security.cors.allow_origins(数组)或 环境变量 PB_CORS_ALLOW_ORIGINS(逗号分隔,如 "https://a.com,https://b.com")。

func Cleanup

func Cleanup()

Cleanup 清理资源(优雅停机编排,oekit core/lifecycle——Manager 原语自 logx 迁来,logx 依赖随之移除):teardown 先取消后台任务根 ctx(拦下一轮),随后 各资源按注册序、各自独立超时预算排水——panic 隔离,单个资源卡死不拖垮整体 停机;在飞轮次由 bg-tasks 预算内等其跑完。停机失败经 Errors() 落回 zap (Manager 内部日志走自身门面,宿主观测以 Errors 为准)。

func CreateDefaultAdmin

func CreateDefaultAdmin(database *gorm.DB, cfg *conf.AppConfiguration) error

CreateDefaultAdmin 创建默认管理员。

密码来源(优先级):PB_ADMIN_PASSWORD 环境变量 > 默认 admin123。 密码用 bcrypt 现场哈希(此前硬编码的哈希与 admin123 不匹配,导致管理员无法登录)。 生产模式(app.production 或 server.mode=release)下若未注入 PB_ADMIN_PASSWORD 且库中无管理员,返回 ErrInsecureDefaultAdmin 由调用方终止启动——已知弱口令 不允许上线(2026-10-08 审计:此前仅 Warn,与 JWT secret 的全环境 fail-fast 不对称)。 仅在"即将创建"时校验:库中已有 admin 的存量部署升级不受影响(每次启动都查会 打断未配 env 的老部署)。cfg 允许 nil(视为非生产,保持旧行为)。

func InitDatabase

func InitDatabase(config *conf.DatabaseConfig) (*gorm.DB, error)

InitDatabase 初始化数据库。

迁移策略(按配置):

  • database.migrate=true:先执行版本化迁移(migrations/*.sql),适合生产/需要版本控制
  • database.auto_migrate(默认 true):GORM AutoMigrate,开发友好、自动补表/列
  • 两者可共存:版本化迁移建表后,AutoMigrate 兜底补充新字段

func ReapplyEnvOverrides added in v0.22.0

func ReapplyEnvOverrides(g *conf.AppConfiguration)

ReapplyEnvOverrides 把非空 env 绑定值重新施加到全局 conf(幂等)。 g 由调用方注入(bootstrap 包级 config / OnOverlayApplied 闭包捕获), 不直读 conf.GetGlobalConfig(棘轮规则 8:装配层也不再新增直读面)。 由 config service 的 OnOverlayApplied 钩子在每次 DB overlay 后调用; 启动期因钩子注册晚于首次 RestoreAdminSettings,wiring 在注册后显式补调一次。

func RunDataMigrations added in v0.32.14

func RunDataMigrations(gormDB *gorm.DB)

RunDataMigrations 启动期数据迁移入口(幂等)。

调用时机:InitDatabase 之后(AutoMigrate 已补齐表结构)、对外服务之前 (读取侧必须先于迁移完成——子表是文件清单的唯一真相源)。

Types

type Config

type Config = conf.AppConfiguration

Config 与 internal/conf 包中的统一配置类型互为别名。

func GetConfig

func GetConfig() *Config

GetConfig 获取全局配置

func InitConfig

func InitConfig(configPath string) (*Config, error)

InitConfig 初始化配置。

配置来源优先级(高 → 低):

  1. 环境变量(PB_ 前缀完整名 / 文档化的短名,见 bindEnvironment)
  2. 配置文件(yaml,路径由 configPath 或 CONFIG_PATH 决定)
  3. 代码内默认值(SetDefault)

这样容器化部署(K8s/Docker)可通过 env 注入敏感配置(jwt_secret、db 密码等), 而无需修改镜像内的配置文件,符合 12-factor。

type Option

type Option func(*Options)

Option 是 Bootstrap 的可选配置项(函数选项模式)。

用法:

h, err := bootstrap.BootstrapWithOptions(configPath,
    bootstrap.WithStaticDir("/opt/pb/ui"),
)

兼容性:Bootstrap(configPath) 等价于无选项的 BootstrapWithOptions, 既有调用方(server、fnos)不受影响。

func WithStaticDir

func WithStaticDir(dir string) Option

WithStaticDir 覆盖前端静态资源目录(空串忽略,保持默认)。

type Options

type Options struct {
	// StaticDir 是前端构建产物的根目录。
	// 该目录需包含 index.html 与 assets/(Vite 构建产物布局)。
	// 默认 "./static"(相对进程工作目录)。
	// 典型消费者:fnos 单容器部署时把前端内嵌到自定义路径。
	StaticDir string
}

Options 控制 Bootstrap 的行为。零值字段取默认。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL