Erlang/OTP生产应用部署介绍

18

我希望在VPS上开发和部署一个Erlang/OTP应用程序。

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

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

注意:我已经阅读了一些关于Erlang和命令行、Erlangcode模块、Erlangreleases的文档,但我仍然不确定如何追求所需的任务。

然而,我猜部署基于Erlang的软件到服务器可能比执行sudo tasksel来安装LAMP要棘手一些。

我计划开发一个基于Erlang/OTP框架的应用程序,它依赖Mochiweb、CouchDB(couchbeam)和boss_db
因此,我对在生产服务器上部署所有这些东西有一些初学者的问题:
  • 我计划使用Ubuntu Server 12.04;对于Erlang/OTP在生产中使用的Linux发行版,是否有更好的选择?
  • 所有代码应该如何组织?我应该将我的应用程序放入/home/myapp/目录中,然后将所有依赖项放入/home/myapp/deps中吗?还是应该将所有依赖项放入/usr/local/lib/erlang/lib中?(由code:get_path()返回)。我应该定期更新依赖项还是应该冻结它们?
  • 如何使整个应用程序在服务器启动时启动?应该是某种bash脚本还是其他什么东西?
  • 我知道Erlang允许热代码升级,但我应该如何组织它?在Rails上,我可以通过git 更新代码,在Erlang世界中是否存在类似的东西?
2个回答

12

依赖有两种类型:内部依赖和外部依赖。如果你想要做到正确(tm),需要花费一些时间才能使其正常工作:

外部依赖:

首先,外部依赖是指在应用程序运行之前必须运行的其他内容,比如PostgreSQL数据库或Riak集群。对于这些内容,通常可以使用Ubuntu中的常规方法来确保它们能够正常启动。我使用 monit 来管理这些任务,效果还不错:

http://mmonit.com/monit/

内部依赖:

对于内部依赖,你需要将程序组织成 Erlang VM 中的 应用程序。这些应用程序也像外部依赖一样相互依赖。例如,您的主要应用程序可能需要在它开始之前运行一个记录器。然后,您创建了一个发布版本。发行版将 Erlang 二进制文件和必要的库/beam/应用程序复制到一个发布目录中,形成一个自包含的 Erlang 系统。它包含一个引导脚本,告诉如何按正确的顺序启动应用程序并保持运行。因此,您可以将此发行版打包成 tar-ball,将其复制到服务器上,然后启动它。这里介绍了一些基本知识:

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

但还需要阅读之前关于应用程序的章节。您还可以让 rebar 为您调用 reltool 来构建发行版。这是我通常做的。

热更新:

在生产环境中处理热升级有几种方式。你可以将 beam 文件移动到机器上,然后部署它。或者,你可以使用 shell 并调用 l(Module) 将其加载到正在运行的系统中。这适合于较小的修复。对于大型系统性升级,你可以进行发行版升级 (release-upgrade),此举可以在运行服务的同时升级运行中的系统。但如果你的系统大多数都是独立的,通常不值得这样做。相反,你可以拥有多台机器并按顺序对它们进行升级。

例如,你可以升级一台机器,然后使用类似 HAProxy 的系统将所有请求的 2% 发送到新系统中。然后逐步增加请求负载权重。


2
我假设在现实世界中,没有人将源代码推送到生产机器上更新系统,而只是传输文件,对吗? - skanatek
2
你所说的“自包含 Erlang 系统”是指一个发布版本,其中包含了 .beam 文件,这些文件应该由已安装 Erlang VM 的生产机器执行? - skanatek

8
虽然@I GIVE CRAP ANSWERS给出了非常详尽的概述,但我想补充一下使用sync来自动化模块热重编译和重新加载的方法。
简单来说,您可以将sync指定为rebar依赖项,然后在准备部署升级时,在Erlang节点上运行sync:go()。这将启动同步引擎,它会监视文件系统更改。然后,您可以使用git推送到服务器。 Sync将注意到文件更改,重新编译它们,并自动加载新的beam文件。
然后,您可以立即运行sync:stop(),告诉系统停止监视文件系统更改(通常不建议在活动服务器上保持同步运行,以防止源文件意外更改而发生意外重新编译)。

虽然这在小型项目中可能有效,但当存在许多具有混乱依赖关系的应用程序时,这难道不会搞砸事情吗?(即app-ups解决了什么问题?) - Seb
1
这对于较小的升级来说绝对是一个更简单的解决方案(“简单”有它的缺点 - 主要是它不是一个全面的解决方案)。对于具有新应用程序和待升级应用程序的重大升级,是需要使用更全面的东西。但是,对于推送对生产环境的更改而不需要添加或升级依赖项,这非常方便且几乎不需要搞什么麻烦:只需推送代码即可完成升级。 - chops
1
话虽如此,同步操作也会升级rebar依赖项(基本上是监视在erlang系统中加载的任何内容,以及源文件和beam文件的目录)。因此,执行类似于 rebar update-deps 的操作也会热加载新的应用程序。当然,如果应用程序升级失败无法编译,则您将处于不一致状态(其中有一半的依赖项应用程序已升级),这显然不是好事情。因此,这可能适用于此,但对于混乱的依赖层次结构来说并不是最佳选择。 - chops
看起来很有趣,我会再仔细看看的 - 我一直在使用mochiweb的reloader.erl,但是我会尝试一下Sync - 对于简单的项目来说,用它来替换所有的appups会很不错... - Seb
1
chops,感谢您提供关于同步的参考。我已经接受了其他答案,因为它更加详细和通用。无论如何,谢谢您。 - skanatek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接