Erlang/OTP 生产应用部署简介

Posted

技术标签:

【中文标题】Erlang/OTP 生产应用部署简介【英文标题】:Introduction to Erlang/OTP production applications deployment 【发布时间】:2012-09-27 08:54:48 【问题描述】:

我想开发一个 Erlang/OTP 应用程序并将其部署到 VPS 上的生产环境中。

我非常熟悉在本地机器上开发 Erlang 代码,我的问题是关于部署的。

基本上,我想知道我应该采取哪些步骤才能将 Erlang 代码从本地机器移动到生产服务器并使其运行,即可供用户使用。

注意:我已经阅读了一些关于 Erlang and command line、Erlang code 模块、Erlang releases 的文档,但我仍然不确定如何执行所需的任务。

不过,我想在服务器上部署基于 Erlang 的软件比为 LAMP 执行 sudo tasksel 更棘手。

我计划有一个 Erlang/OTP 应用程序,它具有 Mochiweb、CouchDB (couchbeam) 和 boss_db 作为依赖项。

所以,我的新手关于在生产服务器上部署所有这些东西的问题如下:

我打算使用Ubuntu Server 12.04;有没有更好的选择让 Linux 发行版在生产环境中用于 Erlang/OTP? 应该如何组织所有代码?我应该将我的应用程序放入 /home/myapp/ 目录,然后将所有依赖项放入 /home/myapp/deps 吗?还是应该将所有依赖项放入/usr/local/lib/erlang/lib? (由代码返回:get_path())。我应该以某种方式定期更新依赖项还是应该冻结它们? 如何让整个应用程序在服务器启动后启动?它应该是某种 bash 脚本还是其他什么? 我知道 Erlang 允许热代码升级,但我应该如何组织呢?在 Rails 上我可以update the code with git,Erlang 世界中是否存在类似的东西?

【问题讨论】:

【参考方案1】:

有两种类型的依赖:内部和外部。如果你想以正确的方式做这件事(tm),开始工作需要一些时间:

外部依赖:

首先考虑后者,external 依赖项是在您的应用程序运行之前必须运行的其他东西。例如 PostgreSQL 数据库或 Riak 集群。对于那些,您通常只使用 Ubuntu 中的常用工具来使其正常启动。我在使用monit 完成这些任务方面有很好的经验:

http://mmonit.com/monit/

内部依赖:

对于internal依赖,你需要将你的程序安排到Erlang VM里面的applications中。它们相互依赖,就像外部依赖一样。例如,您的主应用程序可能需要在启动之前运行记录器。然后你创建一个releaserelease 将 Erlang 二进制文件和必要的库/beams/应用程序复制到发布目录中,形成一个独立的 Erlang 系统。它包含一个boot-script,它告诉如何以正确的顺序启动应用程序并保持它们运行。因此,您可以压缩此版本,将其复制到服务器,然后启动它。这里介绍了一些基础知识:

http://learnyousomeerlang.com/release-is-the-word

但也请阅读之前关于应用程序的章节。您还可以让rebar 致电reltool 为您构建一个版本。这是我通常做的。

热升级:

可以通过多种方式处理生产中的热升级。您可以将梁移动到机器上然后部署它,获取外壳然后调用l(Module) 将其加载到正在运行的系统中。这适用于较小的修复。对于大型系统升级,您可以进行发布升级,这将在不停止服务的情况下即时升级正在运行的系统。但是,如果您的系统大多不共享,通常不值得。相反,您可以拥有多台机器并按顺序升级它们。

例如,您可以升级一台机器,然后使用像 HAProxy 这样的系统将 2% 的请求发送到新系统。然后系统地调高请求负载权重。

【讨论】:

我假设在现实世界中没有人将源代码推送到生产机器上来更新系统,而只是束文件,对吧? “独立的 Erlang 系统”是指带有 .beam 文件的版本,应该由安装了 Erlang VM 的生产机器执行?【参考方案2】:

虽然@I GIVE CRAP ANSWERS 给出了相当详尽的总结,但我觉得有必要使用sync,它有助于自动化模块的热重新编译和重新加载。

简单的方法是将同步指定为 rebar 依赖项,然后在准备部署升级时,可以在 Erlang 节点上运行 sync:go()。这将启动同步引擎,它监视文件系统的变化。然后你可以使用 git 推送到你的服务器。 Sync 会注意到文件的变化,重新编译它们,并自动加载新的梁。

然后,您可以立即运行 sync:stop() 告诉系统停止监视文件系统更改(通常不建议在实时服务器上保持同步运行,只是为了防止意外重新编译,无论出于何种原因,源文件更改,这是无意的。

【讨论】:

虽然这可能适用于较小的事情,但当有很多应用程序具有混乱的依赖关系时,这是否有可能真正搞砸事情? (即应用程序解决了什么问题?) 对于较小的升级来说,这绝对是一个更简单的解决方案(而且“简单”也有它的缺点——主要是它不是一个全面的解决方案)。新应用程序的重大升级,以及新升级的应用程序,是的,你会想要使用更全面的东西。但是对于不需要添加或升级依赖项的将更改推送到生产环境,它非常方便并且几乎不需要乱七八糟:只需推送代码即可升级。 也就是说,sync 也会升级 rebar deps(基本上,加载到 erlang 系统中的任何内容,以及源文件和梁文件的目录都会受到监控)。所以像rebar update-deps 这样的操作也会热加载新的应用程序。当然,如果应用升级编译失败,那么你就会处于不一致的状态(有一半的依赖应用升级了),这显然不是一件好事。所以它可以为此工作,但它不是具有混乱依赖层次结构的最佳选择。 看起来很有趣;我再看看它 - 我一直在使用 mochiweb 的 reloader.erl,但会检查 Sync - 将所有应用程序替换为更简单的项目会很好...... 切碎,感谢您对同步的参考。我接受了另一个答案,因为它更具描述性和一般性。无论如何,谢谢。

以上是关于Erlang/OTP 生产应用部署简介的主要内容,如果未能解决你的问题,请参考以下文章

RabbitMQ Linux: 单机和集群部署

Erlang/OTP - 计时应用

Erlang OTP 应用程序设计

何时在 Erlang/OTP 应用程序中使用 gen_server

运行守护程序的 Erlang/OTP 应用程序的行业标准?

使用 OTP/Erlang 作为 Web 应用程序基于组件的架构的一部分