一、为什么需要OTP release打包
当你用Erlang开发完一个应用后,总不能每次都手动启动一堆进程、加载配置吧?尤其是在生产环境,手动操作既容易出错,又难以维护。这时候,OTP release打包就派上用场了。
简单来说,OTP release就是把你的Erlang应用、依赖库、运行时环境打包成一个完整的、可独立运行的包。这样部署时只需要解压、运行,不需要关心复杂的依赖关系。
举个例子,假设我们有个简单的Erlang应用:
%% 技术栈: Erlang/OTP 25
%% 文件: my_app/src/my_app.erl
-module(my_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_Type, _Args) ->
io:format("启动my_app...~n"),
my_app_sup:start_link().
stop(_State) ->
io:format("停止my_app...~n").
如果没有release打包,每次启动都得手动确保所有依赖正确加载。而用release后,这些全自动搞定。
二、从零开始创建release
创建一个完整的release需要几个关键步骤:
准备项目结构
标准的OTP应用目录结构是这样的:my_app/ ├── rel/ # release配置目录 ├── src/ # 源代码 │ ├── my_app.app.src # 应用元数据 │ └── ... # 其他源文件 └── rebar.config # 构建配置配置rebar3
在rebar.config中添加release配置:
%% rebar.config
{erl_opts, [debug_info]}.
{deps, []}.
{profiles, [
{prod, [
{relx, [
{release, {my_app, "1.0.0"}, [my_app, sasl]},
{sys_config, "./config/sys.config"},
{vm_args, "./config/vm.args"},
{dev_mode, false},
{include_erts, true} % 包含Erlang运行时
]}
]}
]}.
- 生成release
运行命令:
这会生成一个完整的release包,包含Erlang运行时、你的应用和所有依赖。rebar3 as prod release
三、多环境配置管理实战
开发、测试、生产环境的配置通常不同。OTP release通过sys.config解决这个问题。
创建不同环境的配置
config/ ├── dev.sys.config # 开发配置 ├── prod.sys.config # 生产配置 └── sys.config # 默认配置示例配置内容
%% prod.sys.config
[
{my_app, [
{db_host, "prod.db.example.com"},
{max_connections, 100}
]},
{kernel, [
{logger_level, warning}
]}
].
- 构建时指定配置
修改rebar.config:
{relx, [
{sys_config, "./config/${RELX_SYS_CONFIG}.config"} % 动态加载
]}
然后通过环境变量指定配置:
RELX_SYS_CONFIG=prod rebar3 as prod release
四、版本回滚的两种实用方案
发布后发现问题怎么办?回滚!这里介绍两种可靠方法。
方案1:使用release的旧版本
Erlang release自带版本管理功能。假设我们有两个版本:
$ ls releases/
1.0.0/ 1.0.1/
回滚到1.0.0:
bin/my_app downgrade 1.0.0
方案2:热代码降级
如果只是某个模块有问题,可以单独降级:
%% 查看当前版本
code:which(my_module).
%% 加载旧版beam文件
code:load_file(my_module).
五、自动化发布流程设计
手动发布容易出错,我们需要自动化流程。以下是基于Shell脚本的示例:
#!/bin/bash
# 部署脚本示例
REL="1.0.0"
TARGET_DIR="/opt/my_app"
# 1. 上传release包
scp _build/prod/rel/my_app/my_app-$REL.tar.gz server:$TARGET_DIR
# 2. 解压并切换版本
ssh server <<EOF
cd $TARGET_DIR
tar -xzf my_app-$REL.tar.gz
bin/my_app upgrade $REL
EOF
更复杂的场景可以用Ansible或Docker,但核心逻辑不变:传输包→解压→切换版本。
六、常见问题与解决方案
问题1:启动时报缺失依赖
➤ 检查rebar.config是否包含所有依赖
➤ 确保include_erts设为true
问题2:配置不生效
➤ 检查sys.config语法是否正确
➤ 确认配置文件路径被正确指定
问题3:回滚后仍报错
➤ 可能依赖的库版本不兼容
➤ 建议回滚整个release而非单个应用
七、什么时候该用OTP release?
适用场景:
- 需要部署到多台服务器
- 要求稳定的版本控制
- 环境配置差异大
不适用场景:
- 快速原型开发
- 单次执行的脚本类应用
八、技术方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 手动启动 | 简单直接 | 难以维护 |
| OTP release | 完整可靠 | 学习曲线陡峭 |
| Docker打包 | 环境隔离 | 镜像体积较大 |
九、总结与最佳实践
- 保持release纯净:不要在生产环境手动修改代码
- 版本命名规范:建议使用语义化版本(如1.0.0)
- 自动化测试:在CI流程中加入release打包测试
- 监控:对release运行状态进行监控
最后附上一个完整的部署命令示例:
# 全新安装
tar -xzf my_app-1.0.0.tar.gz
bin/my_app start
# 升级版本
bin/my_app upgrade 1.0.1
评论