必须用os.Getenv读环境变量、监听动态端口禁用HTTP/2、日志输出纯JSON到stdout、静态编译镜像,四条均严格遵循12-Factor原则,避免viper/flag陷阱、硬编码端口、非结构化日志及动态链接二进制。

Go 应用在 Kubernetes 或其他云平台跑不稳、日志收不到、配置总漏掉、健康检查失败——八成是没踩准 12-Factor 的几个硬性动作。不是加个 viper 就算配置管理,也不是 log.Printf 打印几行就叫结构化日志。
os.Getenv 是唯一可信的环境变量读取方式
Go 进程启动极快,flag.Parse() 和 viper.AutomaticEnv() 都依赖初始化顺序和命名约定,容易在容器里静默失效。比如 viper.Get("port") 返回空字符串而不是报错,你根本不知道 PORT 没传进来。
- 所有配置项必须显式调用
os.Getenv("DATABASE_URL"),赋值给局部变量或结构体字段 - 启动时集中校验:如果
os.Getenv("PORT") == "",直接log.Fatal("missing PORT") - 类型转换自己做:
port, err := strconv.Atoi(os.Getenv("PORT")),别让库替你猜 - 禁止用
.env文件在生产环境加载配置——它只适合本地开发,且必须.gitignore
HTTP 服务必须监听 ":" + os.Getenv("PORT") 并禁用 HTTP/2
Kubernetes readiness probe 失败、反向代理超时、连接复用异常,很多都源于 Go 默认行为:硬编码端口、自动启用 HTTP/2 推送。这些在单机调试时没问题,上云就暴露。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 监听地址只能是
":" + os.Getenv("PORT"),不能是":8080",也不能拼"0.0.0.0:" - 不用
http.ListenAndServe或http.ListenAndServeTLS——它们会自动启用 HTTP/2;改用&http.Server{Addr: addr, Handler: mux} - 健康检查端点(如
/healthz)用http.HandleFunc直接注册,绕过中间件链,避免 panic 影响探针 - 加优雅关闭:
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)后调用server.Shutdown(ctx)
日志必须输出纯 JSON 到 os.Stdout
log.Printf 带文件名、行号、ANSI 颜色,在容器里被 fluentd/vector 截断或解析失败;logrus.WithField("meta", map[string]interface{}{...}) 会嵌套 JSON,日志系统无法提取字段。
- 只用
fmt.Println或json.NewEncoder(os.Stdout).Encode(...) - 每条日志是一个扁平 JSON 对象:
{"level":"info","ts":"2024-05-20T10:30:00Z","msg":"request completed","status":200,"duration_ms":12.3} - 禁用所有
log.SetOutput到文件或自定义 writer - 不要加颜色、不要加前缀、不要换行符外的控制字符
最常被忽略的其实是“进程模型”本身:Go 程序一旦启动,就该是自包含、无状态、可随时终止的单一进程。任何后台 goroutine 没做退出协调、任何全局变量缓存了连接或状态、任何日志写到文件——都在悄悄违反第 6 条(Processes)和第 9 条(Disposability)。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










