Revel应用生产环境必须用revel build生成可执行文件运行,不可用revel run;因后者依赖源码热重载和文件监听,在只读镜像中会panic退出,且需多阶段构建精简镜像、挂载外部配置、确保run.sh权限及路径配置正确。

Revel应用必须用 revel build 生成可执行文件再运行,不能直接 revel run 启动容器 —— 这是生产部署最常踩的坑。
为什么不能在Docker里用 revel run
Revel 的 revel run 是开发模式:它依赖源码热重载、文件监听、模板实时编译,这些机制在只读的生产镜像里无法工作,还会因缺少 inotify 等系统工具直接 panic。容器启动后几秒就退出,日志里常见 failed to watch file 或 template parse error。
- 开发时本地跑
revel run没问题,但 Dockerfile 中绝不能写CMD ["revel", "run", "."] - 生产镜像应只含编译后的二进制和静态资源,体积更小、启动更快、无运行时依赖
- Revel 官方文档也明确建议:生产环境使用
revel build输出独立可执行文件
Dockerfile 必须用多阶段构建
Go 应用编译需要 Go 工具链,但运行时完全不需要。把 golang 镜像直接当运行镜像,会导致镜像臃肿(>800MB)、暴露编译器风险、启动变慢。
- 第一阶段用
golang:1.21-alpine安装revelCLI、下载依赖、执行revel build -a . -t /app/target - 第二阶段用
alpine:3.18,仅复制上一阶段生成的/app/target目录 - 务必在第二阶段安装
ca-certificates和tzdata,否则 HTTPS 请求失败、时区错误 -
EXPOSE 9000是声明,实际端口由docker-compose.yml或docker run -p控制
docker-compose.yml 要显式挂载配置与日志
Revel 默认从 conf/ 目录读取 app.conf,但容器内路径和宿主机不一致。硬编码配置或把配置打进镜像,会导致环境切换困难(dev/staging/prod)。
- 用
volumes将宿主机的./conf:/app/conf:ro挂载,确保配置可外部管理 - 日志默认输出到 stdout/stderr,但 Revel 的
app.LogLevel和app.OutLogPath仍可能写文件;建议在app.conf中设app.OutLogPath = "",强制走标准输出 - 若需持久化上传文件或缓存,单独定义命名卷(如
revel-uploads),不要用绑定挂载到相对路径 - 服务名别叫
web或app,用revel-app,避免和其他框架混淆
启动前必须验证 run.sh 权限和入口点
Alpine 镜像默认不带 bash,而很多新手写的 run.sh 第一行是 #!/bin/bash,结果容器启动报错 exec: "run.sh": permission denied 或 no such file or directory。
-
run.sh必须用#!/bin/sh(Alpine 自带 busybox sh) - 构建镜像前,本地执行
chmod +x run.sh,否则 COPY 进去也没执行权限 - 推荐简化入口:直接
CMD ["./revel-app"](假设revel build输出名为revel-app),省去 shell 层级 - 启动后检查端口:进入容器执行
netstat -tlnp | grep :9000,确认进程真在监听,不是被防火墙或app.http.port配置覆盖
真正麻烦的从来不是写完 Dockerfile,而是 app.conf 里那些看似无关紧要的路径配置 —— 比如 app.static.dir 指向 public,但镜像里该目录位置不对,404 就静默发生,连日志都不报。











