Revel应用必须打包为无状态容器镜像,禁用watch、固定runmode、分离ConfigMap与Secret、暴露健康端点、日志输出至stdout/stderr。

Revel 应用必须打包成无状态容器镜像
Revel 默认会把 app.conf、routes、静态资源等放在项目目录下,直接 go run main.go 在本地能跑,但进 Kubernetes 就会挂——因为 Pod 启动时工作目录不固定,且文件系统是临时的。必须把所有运行时依赖打进镜像。
实操建议:
- 用
Dockerfile显式复制conf/、app/、public/和编译后的二进制(不要go run) -
conf/app.conf中禁用watch = true,否则 Revel 会在容器里尝试监听文件变化,失败且浪费 CPU - 把
runmode = prod写死在配置里,或通过环境变量覆盖:REVEL_RUNMODE=prod - 确保
main.go调用的是revel.Init+revel.Run,不是开发用的revel.NewApp或热重载逻辑
ConfigMap 和 Secret 必须分离敏感与非敏感配置
Kubernetes 不允许直接挂载整个 conf/ 目录,尤其当里面混着数据库密码、API 密钥时。Revel 的 app.conf 支持环境变量插值(如 db.url = ${DB_URL}),这是关键突破口。
实操建议:
- 把非敏感项(如
http.port、template.suffix)放进ConfigMap,挂载为文件或环境变量 - 把
db.password、jwt.secret等放进Secret,同样用环境变量方式注入 - 避免在 ConfigMap 里写
runmode = dev—— Revel 会自动加载dev.conf,而该文件通常不会进 Git,导致启动失败 - 检查
revel.Config.String("db.url")是否真能读到环境变量值:Revel v0.25+ 才完整支持${VAR}解析,旧版需手动调os.Getenv
Service 和 Ingress 需绕过 Revel 的默认 HTTP Server 设置
Revel 自带 http.ListenAndServe,监听 :9000 或配置的端口。Kubernetes 的 Service 不能靠它自动注册,更不能指望它处理 TLS 终止或路径重写。
实操建议:
- 容器内只暴露一个端口(如
EXPOSE 9000),别设HEALTH_PORT或额外 admin 接口 —— Revel 没内置健康检查 endpoint - 自己加一个
/health路由,返回 200 + 简单 JSON,供 KuberneteslivenessProbe用 - Ingress 的
path必须匹配 Revel 的routes前缀;若 Ingress 配了/api/前缀,而 Revel 的routes里写的是GET /users,请求会 404 —— 要么改 Ingress,要么在 Revel 里用revel.Intercept做路径前缀剥离 - 禁用 Revel 的
gzip = true(除非你确认 Ingress controller 不重复压缩),否则可能和 Nginx/Envoy 的 gzip 冲突
日志必须输出到 stdout/stderr,且禁用文件轮转
Revel 默认把日志写进 logs/ 目录下的文件,Kubernetes 无法收集这些文件,且空目录挂载后权限常出错,导致启动失败。
实操建议:
- 初始化时强制替换 Revel 的日志输出器:
revel.INFO.Out = os.Stdout、revel.ERROR.Out = os.Stderr - 删掉
conf/app.conf里的log.path和log.rotate配置项,它们在容器里毫无意义 - 如果用了结构化日志(如
zerolog替换 Revel 日志),确保时间戳格式是 RFC3339,方便 Loki/Promtail 解析 - 注意 Revel 的
revel.TRACE级别日志量极大,生产环境务必设为INFO或更高


















