• 安装一个发布

    安装一个发布

    当我们完成了一个发布的新版本,然后就可以用这个新版本创建一个发布包并传输到目标环境中。

    要在运行时安装新版本的发布,得用到发布处理器。它是属于SASL应用的一个进程,负责发布包的解包、安装和移除。它通过模块 release_handler 暴露了借口,在 release_handler(3) 中有详细阐述。

    机设有一个正在运行的目标系统,安装根目录是 $ROOT ,包含发布新版本的发布包应被复制到 $ROOT/releases 中。

    第一个动作是先解开发布包,然后文件从包中被释放出来:

    1. release_handler:unpack_release(ReleaseName) => {ok, Vsn}

    ReleaseName 是发布包去掉 .tar.gz 扩展之后的名字。 Vsn 是被解开的发布的版本,和在 .rel 文件中定义的一样。

    然后会创建一个 $ROOT/lib/releases/Vsn ,其中有 .rel 文件、启动脚本 start.boot 、系统配置文件 sys.config 以及 relup 文件。对于有新版本号的应用,应用目录会被放在 $ROOT/lib 下。未更改的应用不受影响。

    解开的发布可以被安装。然后发布处理器会一条条执行在 relup 中指令:

    1. release_handler:install_release(Vsn) => {ok, FromVsn, []}

    如果在安装过程中出现了错误,那么系统会使用老版本的发布重新启动。如果安装成功了,系统以后就会使用新版本的发布,但是一旦出了状况系统重启了,那么还是会使用前一个版本进行启动。为了能成为默认版本,新安装的发布必须被设为持久(permanent)的,也就是说前一个版本变成旧的了:

    1. release_handler:make_permanent(Vsn) => ok

    系统将哪个版本是旧的哪个是持久的信息保存在文件 $ROOT/releases/RELEASES$ROOT/releases/start_erl.data

    要从 Vsn 降级至 FromVsn ,必须再次调用 install_release

    1. release_handler:install_release(Vsn) => {ok, FromVsn, []}

    一个安装了,但是并非持久的发布可以被移除。然后关于该发布的信息会从 $ROOT/releases/RELEASES 中被删除,同时该发布指定的代码,也就是新的应用的目录和 $ROOT/releases/Vsn 目录都会被删除。

    接着前一节的例子:

    • 按照系统原理中所描述的创建一个目标系统,包含来自 发布 一章的 ch_rel 的第一个版本“A”。这次必须在发布包中包含 sys.config 。如果不需要任何配置,该文件应该包含空列表:
    1. [].
    • 作为一个简单的目标系统启动。注意实际中,它要作为一个嵌入式系统启动。不过,用正确的启动脚本以及 .config 文件启动 erl 对于描述我们的目的已经足够了:
    1. % cd $ROOT
    2. % bin/erl -boot $ROOT/releases/A/start -config $ROOT/releases/A/sys
    3. ...
    • 在另一个Erlang shell中,为新版本“B”生成启动脚本并创建发布包。记住要包含(一个可能更新过的) sys.config 文件和 relup 文件,参见之前的 发布升级文件 。
    1. 1> systools:make_script("ch_rel-2").
    2. ok
    3. 2> systools:make_tar("ch_rel-2").
    4. ok

    现在新的发布包包含了 ch_app 的版本“2”和 relup 文件:

    1. % tar tf ch_rel-2.tar
    2. lib/kernel-2.9/ebin/kernel.app
    3. lib/kernel-2.9/ebin/application.beam
    4. ...
    5. lib/stdlib-1.12/ebin/stdlib.app
    6. lib/stdlib-1.12/ebin/beam_lib.beam
    7. ...
    8. lib/sasl-1.10/ebin/sasl.app
    9. lib/sasl-1.10/ebin/sasl.beam
    10. ...
    11. lib/ch_app-2/ebin/ch_app.app
    12. lib/ch_app-2/ebin/ch_app.beam
    13. lib/ch_app-2/ebin/ch_sup.beam
    14. lib/ch_app-2/ebin/ch3.beam
    15. releases/B/start.boot
    16. releases/B/relup
    17. releases/B/sys.config
    18. releases/ch_rel-2.rel
    • 将发布包 ch_rel-2.tar.gz 复制到 $ROOT/releases 目录中。
    • 在运行中的目标系统上,解开发布包:
    1. 1> release_handler:unpack_release("ch_rel-2").
    2. {ok,"B"}

    新应用版本 ch_app-2 被安装在 $ROOT/lib 中,就在 ch_app-1 旁边。 kernelstdlibsasl 目录没受影响,因为都没有做过更改。

    $ROOT/releases ,创建了一个新目录 B ,里面包含了 ch_rel-2.relstart.bootsys.configrelup

    • 检查函数 ch3:available/0 是否可用:
    1. 2> ch3:available().
    2. ** exception error: undefined function ch3:available/0
    • 安装新的发布。执行 $ROOT/releases/B/relup 中的指令,最后新版本的 ch3 载入了。现在函数 ch3:available/0 就可用了:
    1. 3> release_handler:install_release("B").
    2. {ok,"A",[]}
    3. 4> ch3:available().
    4. 3
    5. 5> code:which(ch3).
    6. ".../lib/ch_app-2/ebin/ch3.beam"
    7. 6> code:which(ch_sup).
    8. ".../lib/ch_app-1/ebin/ch_sup.beam"

    ch_app 中没有更新过代码的进程,例如督程,会继续执行 ch_app-1 中的代码。8. 如果目标系统现在重启了,它还会继续使用“A”。“B”版本必须设置为持久才能在系统重启之后被使用。

    1. 7> release_handler:make_permanent("B").
    2. ok