Distillery(基础)
Distillery 是纯 Elixir 编写的发布管理工具。它可以让你在极少,甚至不需要配置的情况下生成发布包,并部署到其它环境。
什么是发布包?
一个发布包就是包含了 Erlang/Elixir 编译码的代码包(也就是 BEAM 字节码)。它里面还提供运行程序必须的脚本。
当你编写了一个或多个应用后,你或许想创造一个包含了这些应用和 Erlang/OTP 应用子集的完整系统。这个就是一个发布包。—— Erlang 文档
发布包简化了应用测部署:它们是自包含的,并提供了启动所需的所有东西;还可以通过内置命名行脚本来轻松地管理它们,包括打开远程命令行,启动/停止/重启应用,后台启动,发送远程命令等。另外,它们还是可归档保存的成品,意味着你可以在未来任意时刻,通过这个压缩包恢复到旧版本的系统(除非和底层的 OS 或系统库不兼容)。发布包的使用是热更新或降级的必备条件,而这正是 Erlang VM 最强大的特性之一。—— Distillery 文档
一个发布包包含以下内容:
/bin 文件夹
这包含了整个应用启动的脚本。
/lib 文件夹
这包含了应用编译后的字节码,及其所有依赖。
/releases 文件夹
这包含了发布包,及其钩子和自定义命令的元数据。
/erts-VERSION
这是 Erlang 运行时环境。它可以让你的机器在没有安装 Erlang 或 Elixir 的情况下运行你的应用。
入门及安装
把 Distillery 当作依赖,添加到你项目里 的 mix.exs
文件里头。注意 —— 如果你的是 umbrella 应用,请把它添加到项目根目录的 mix.exs 文件里。
然后在命令行输入:
生成发布包
在命令行,运行
命令完成后会产生一个 rel
目录,并包含一些配置文件在里面。
然后运行 mix release
就可以生成一个发布包。
发布包一生成,命令行应该会出现以下指引。
在命令行输入命令 _build/dev/rel/MYAPP/bin/MYAPP foreground
就可以启动你的应用。当然,你需要把 MYAPP 替换为你的项目名称。这样我们就已经通过发布包来运行我们的应用了!
在 Phoenix 项目中使用 Distillery
如果你需要结合 Phoenix 来使用 Distillery,有一些额外的步骤需要执行。
首先,编辑 config/prod.exs
文件。把以下内容:
更改为:
这里做的修改是:
server
—— 在系统启动的时候,运行 Cowboy 应用的 http 服务root
—— 配置系统根目录,也就是放置并提供静态文件的路径。version
—— 当系统版本升级的时候,系统缓存就会被清除。port
—— 根据 ENV 环境变量,在系统启动的时候设置端口,通过PORT=4001 _build/prod/rel/book_app/bin/book_app foreground
如果执行上述命令的时候,系统由于找不到数据库而崩溃了。我们可以通过 Ecto mix
命令来修复这个错误。在命令行,输入:
这个命令可以帮你创建数据库。尝试重新启动系统,这时候应该正常了。但是,你会发现数据库的升级脚本还没有运行。通常,在开发阶段,这些升级脚本都是手动调用 mix.ecto migrate
来运行的。到了发布阶段,我们希望它能自动按照配置运行。
在生产环境运行数据库升级脚本
Distillery 可以让我们在发布生命周期的不同时刻执行代码。这些点被称之为 boot-hooks。Distillery 提供的钩子包括:
pre_start
post_start
pre/post_configure
pre/post_stop
pre/post_upgrade
根据我们的需要,post_start
是在生产环境运行数据库升级脚本的点。我们先创建一个叫 migrate
的发布任务。这个任务是一个可以在命令行调用的模块函数入口,它包含了和系统应用去分开的代码。通常我们会把那些系统本身不需要运行的任务都放在这里。
注意 通常,好的做法是确保系统各部分都正常启动后,再运行这些升级脚本。Ecto.Migrator 可以帮助我们连接数据库,然后运行脚本。
接着,创建新的文件 —— rel/hooks/post_start/migrate.sh
并加入如下代码:
我们需要使用 Erlang 的 rpc
模块,通过远程程序调用服务(Remote Produce Call)来正确执行代码。简单来说,它能让我们在远程节点执行函数调用,获取回结果。一般来说,我们的系统应用在生产环境都是运行在好几个不同的节点上面的。
最后,在 rel/config.exs
文件,我们加入如下钩子到 prod 的配置里。
把一下配置:
替换为:
注意 —— 这个钩子只在应用的 production 发布包里。如果我们使用默认的 development 发布包,它并不会运行。
自定义命令
当发布的时候,你可能没有权限运行 mix
命令因为在要部署的机器上并没有安装 mix
。我们可以通过创建自定义命令来解决这个问题。
自定义命令是启动脚本的扩展。它和 foreground 或者 remote_console 的使用方法是一样的,也就是说,它们会成为启动脚本的一部分。就像钩子一样,它们能访问启动脚本的辅助函数和环境 —— Distillery 文档
命令和发布任务一样是函数,但不同的地方在于它们是通过命令行执行,而不是通过发布脚本来运行。
既然我们能运行升级脚本了,我们或许还需要通过命令来为数据库提供基础数据。首先,在我们的发布任务模块添加一个新的函数。在 BookAppWeb.ReleaseTasks
,加入以下代码:
接着,创建文件 rel/commands/seed.sh
并加入代码:
注意 - release_ctl()
是 Distillery 提供的脚本,可以让我们在本地或者一个干净的节点运行命令。如果需要在一个运行中的节点执行命令,你需要使用 release_remote_ctl()
。
需要了解更多 Distillery 的脚本,可以参考这里
最后,在 rel/config.exs
文件里,加入:
谨记,需要运行 MIX_ENV=prod mix release
来重新生成发布包。一旦完成,你就可以在命令行运行 PORT=4001 _build/prod/rel/book_app/bin/book_app seed
。
最后更新于