介绍
Elixir建立在Erlang编程语言的基础之上,是一种功能强大的编程语言,因其注重开发人员的工作效率和易于编写高度并行和可扩展的应用程序而受到欢迎。
Phoenix是一个基于Elixir构建的Web框架,可以创建高性能的Web应用程序。
当与另外两个工具( Distillery和edeliver)结合使用时,您可以将Phoenix项目从开发环境部署到生产服务器。
Distillery将Elixir应用程序编译成一个包,然后可以在其他地方部署。 它还生成允许热插拔代码的软件包,这意味着您可以在不停机的情况下升级实时应用程序。 所有这一切都可以在你很少或没有配置的情况下完成,这使得Distillery与其他许多选项分开。
edeliver通过负责构建应用程序,将构建的包传输到服务器,迁移数据库以及启动/更新服务器等重复任务来自动执行此构建和部署过程。 如果需要,甚至可以配置edeliver以允许进行中间分段设置。
在本教程中,您将在本地开发机器和生产服务器上安装Erlang,Elixir和Phoenix,您将简化两个位置之间的SSH通信,然后创建一个示例Phoenix项目来构建和部署与edeliver。 最后,您将使用Nginx反向代理和SSL证书来保护生产服务器。
在本教程结束时,您将拥有一个可以执行以下操作的命令:
- 建立一个与您的生产环境兼容的Phoenix版本
- 将发行版部署到您的生产环境
- 在生产环境中启动您的应用程序
- 通过部署新版本热插拔当前的产品版本,而无需停机
先决条件
在开始之前,请确保您具有以下内容:
一个基于Ubuntu的本地开发机器。 虽然本教程的说明是为基于Ubuntu的本地开发机器编写的,但是这个部署过程的一个优势是它完全独立于生产环境。 有关在其他操作系统上设置本地开发机器的说明,请参阅官方的Elixir安装文档 。 或者,要设置一个基于Ubuntu的远程开发机器,请遵循这个最初的服务器设置教程 。
在Ubuntu 16.04服务器上具有sudo权限的非root用户帐户,具有至少1GB RAM,按照此初始服务器设置教程中的前四个步骤进行设置 。 由于我们的目标是自动执行部署过程,因此请在安装教程的第4步后输入SSH密码。 此外,请确保允许在安装教程的第7步中使用命令
sudo ufw allow 4000
访问端口sudo ufw allow 4000
。 这是我们将在本教程中用于测试Phoenix的端口。Nginx的安装如下:在Ubuntu 16.04上安装Nginx 。
完全注册的域名。 本教程将始终使用
example.com
。 您可以在Namecheap上购买域名,在Freenom上免费获取域名,或使用您所选择的域名注册商。以下两个DNS记录都是为您的服务器设置的。 你可以按照这个主机名教程了解如何添加它们的细节。
-
example.com
指向您服务器的公有IP地址的记录。 - 与
www. example.com
的一条记录www. example.com
www. example.com
指向您的服务器的公共IP地址。
-
Nginx通过遵循这个设置使用SSL证书进行保护让我们使用Ubuntu 16.04教程中的Nginx服务器模块进行加密 。 请务必在Nginx设置教程的第4步中选择选项2,
Redirect
,因为这将在本教程中创建的生产服务器上提供自动重定向到HTTPS。
第1步 - 在本地开发机器上安装Elixir和Phoenix
因为Elixir运行在Erlang虚拟机上,所以在安装Elixir之前我们需要安装虚拟机。 由于我们要确保使用最新的Erlang稳定版本,我们将从Erlang解决方案资源库中安装Erlang。
首先,下载并添加Erlang解决方案资源库到您的本地开发机器。
cd ~
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
sudo dpkg -i erlang-solutions_1.0_all.deb
现在,更新你的软件包列表并安装esl-erlang
软件包,它提供了Erlang编程语言以及有用的工具,库和中间件(统称为Erlang / OTP平台)。
sudo apt-get update
sudo apt-get install esl-erlang
然后,安装Elixir。
sudo apt-get install elixir
接下来,使用Mix - 与Elixir捆绑的构建工具来创建Elixir项目并管理依赖项 - 安装Elixir自己的包管理器Hex ,稍后您将使用它来安装Phoenix。
这个命令的local
部分告诉Mix在本地安装hex
。
mix local.hex
当提示确认安装时,请输入Y
OutputAre you sure you want to install "https://repo.hex.pm/installs/1.5.0/hex-0.17.1.ez"? [Yn] Y
* creating .mix/archives/hex-0.17.1
现在,使用十六进制来安装Phoenix Mix归档文件,这是一个Zip文件,其中包含了生成新的基础Phoenix项目所需的一切。
mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez
当提示确认安装时,再次输入Y
OutputAre you sure you want to install "https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez"? [Yn] Y
* creating .mix/archives/phoenix_new
在本地开发机器上安装Elixir和Phoenix,让我们在生产服务器上安装我们需要的部分。
第2步 - 在生产服务器上安装Elixir和Phoenix
因为我们需要我们的Phoenix项目在本地开发机器和生产服务器上运行,所以我们需要在两个地方安装所有相同的语言和工具。
使用第1步中的相同命令,下载Erlang Solutions存储库并将其添加到生产服务器。
cd ~
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
sudo dpkg -i erlang-solutions_1.0_all.deb
更新你的软件包列表并安装esl-erlang
软件包。
sudo apt-get update
sudo apt-get install esl-erlang
安装药剂。
sudo apt-get install elixir
使用Mix来安装十六进制。
mix local.hex
当提示确认安装时,请输入Y
OutputAre you sure you want to install "https://repo.hex.pm/installs/1.5.0/hex-0.17.1.ez"? [Yn] Y
* creating .mix/archives/hex-0.17.1
最后,使用Hex来安装Phoenix。
mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez
当提示确认安装时,再次输入Y
OutputAre you sure you want to install "https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez"? [Yn] Y
* creating .mix/archives/phoenix_new
本地开发机器和生产服务器现在都可以运行Phoenix,但通过设置SSH主机别名,让本地开发机器更容易地连接到生产服务器。
第3步 - 设置SSH主机别名
由于我们的目标是一个完全自动化的部署过程,因此我们在初始生产服务器设置期间生成了一个SSH密钥对,该密钥对不会提示输入密码。
现在,我们可以使用命令ssh -i ~/.ssh/ private_key_file sammy @ example.com
从本地开发机器连接到生产服务器。
在这里,我们以用户sammy的身份连接到example.com
。 -i
标志告诉SSH使用位于~/.ssh/private_key_file
文件进行连接。
尽管我们可以通过设置一个SSH主机别名来自己知道连接到生产服务器时使用哪个私钥,用户和域,我们可以使这个命令和部署过程本身更简单。
在本地开发机器上打开~/.ssh/config
进行编辑。
nano ~/.ssh/config
然后,复制到下面的行中。
Host example.com
HostName example.com
User sammy
IdentityFile ~/.ssh/private_key_file
注意:如果你的config
文件已经包含了一些东西,那么包含一个额外的空行,将这个新配置从现有的配置中分离出来。
Host
线提供了一个别名来标识这个特定的配置。 为了更容易记住,我们正在使用我们的域名。 HostName
行告诉SSH连接的主机。 User
行允许SSH知道连接哪个用户, IdentityFile
告诉SSH使用哪个私钥文件。
保存您的更改并关闭文件。
最后,通过连接到生产服务器来测试配置。
ssh example.com
您应该能够在不指定用户,私钥文件或域的情况下进行连接。 如果无法连接,请按照屏幕上的消息并重新执行上述步骤来解决问题。
现在我们简化了与生产服务器的连接,我们可以创建一个示例Phoenix项目进行部署。
第4步 - 创建一个测试项目
默认情况下,当您创建一个新的Phoenix项目时,它配置了一个PostgreSQL数据库适配器和一个基于JavaScript的Web应用程序构建工具Brunch 。 为了避免这种额外的复杂性,我们将通过分别传入--no-ecto
和--no-brunch
标志来创建一个名为test
的简单Phoenix项目,其中没有数据库适配器,也没有Brunch。
转到您的主目录并创建新项目。
cd ~
mix phoenix.new --no-ecto --no-brunch test
输出结果包括Phoenix为test
项目脚手架创建的目录和文件,提示确认是否要安装所需的依赖关系,以及有关如何启动Phoenix内置服务器的说明。
当提示确认安装时输入Y
Output* creating test/config/config.exs
* creating test/config/dev.exs
* creating test/config/prod.exs
...
Fetch and install dependencies? [Yn] Y
* running mix deps.get
We are all set! Run your Phoenix application:
$ cd test
$ mix phoenix.server
You can also run your app inside IEx (Interactive Elixir) as:
$ iex -S mix phoenix.server
现在,让我们看看我们的测试项目是否正在工作。
进入test
目录并运行mix phoenix.server
命令来编译项目并启动服务器。
cd ~/test
mix phoenix.server
输出结果会告诉您Phoenix编译的文件的数量和类型,并提供有关它一路上遇到的问题的警告,如果成功,则可以让您知道到达项目的位置。
首次在本地开发机器上编译一个基于Elixir的应用程序时,系统会提示您安装Rebar依赖的Erlang构建和依赖项工具。 在提示符处输入Y
Output==> file_system
Compiling 6 files (.ex)
Generated file_system app
...
Could not find "rebar3", which is needed to build dependency :ranch
I can install a local copy which is just used by Mix
Shall I install rebar3? (if running non-interactively, use "mix local.rebar --force") [Yn] Y
...
Compiling 11 files (.ex)
Generated test app
[info] Running Test.Endpoint with Cowboy using http://localhost:4000
要测试当前设置,请将您的Web浏览器指向http:// localhost:4000 。 您应该看到Phoenix的默认主页欢迎您来到Phoenix。 如果不这样做,请确保您的防火墙允许在端口4000
上连接,然后查看您的终端输出以获取进一步说明。
一旦你确认了一切正常,请按CTRL+C
两次以停止服务器,以便在第5步中进一步配置。
现在你已经有了一个功能齐全的本地Phoenix项目,让我们来配置它使用Distillery和edeliver。
第5步 - 配置项目使用Distillery和edeliver
Phoenix项目存储像项目所运行的端口以及config/prod.exs
的项目主机URL等config/prod.exs
,因此我们将开始编辑该文件,告知Phoenix如何在生产环境中访问项目。
在本地开发机器上打开config/prod.exs
进行编辑。
nano ~/test/config/prod.exs
找到以下代码块:
...
config :test, Test.Endpoint,
http: [port: {:system, "PORT"}],
url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/manifest.json"
...
http: [port]
值是项目运行的端口,而url: [host]
和url: [port]
用于在项目中生成链接。 在设置代理端点暴露在与Phoenix项目不同的端口上的代理时,这种差异特别有用。
为了简单起见,我们将在运行test
项目的端口中进行硬编码。 这将减少移动部件的数量,而这又会增加我们的自动化部署过程的可靠性。
除了我们将要修改的默认选项之外,我们还将添加两个新选项。
server
选项告诉Distillery将项目配置为在启动时启动HTTP服务器,这是我们在全自动部署过程中所需的。
code_reloader
选项告诉项目在项目代码改变时刷新所有连接的Web浏览器。 虽然这在开发中可能是一个非常有用的功能,但它并不适用于生产环境,所以我们将其关闭。
现在,修改默认配置。
...
config :test, Test.Endpoint,
http: [port: 4000],
url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/manifest.json",
server: true,
code_reloader: false
...
注:为避免潜在的配置问题,请在继续之前仔细检查是否在cache_static_manifest
行的末尾添加了一个。
保存并关闭config/prod.exs
一旦你做了更改。
当我们在第4步中创建test
项目时,Phoenix会自动生成一个.gitignore
文件,当我们使用edeliver将代码更改推送到构建服务器时,我们将在第6步中需要该文件。
默认情况下, .gitignore
文件告诉Git忽略依赖关系和构建文件,这样版本库不会变得不必要的大。 此外,该文件还告诉Git忽略prod.secret.exs
,这是所有Phoenix项目的config
目录中的一个文件,它包含非常敏感的信息,如生产数据库密码和签名令牌的应用程序秘密。
由于test
项目需要生产服务器上的prod.secret.exs
才能正常工作,而且我们不能使用Git来移动它,所以我们必须手动将其传输到服务器。
在生产服务器的主目录中,创建一个名为app_config
的新目录。 这是你将存储prod.secret.exs
。
cd ~
mkdir app_config
现在,使用scp
将prod.secret.exs
复制到生产服务器上的app_config
目录。
scp ~/test/config/prod.secret.exs example.com:/home/sammy/app_config/prod.secret.exs
最后,通过在生产服务器上列出app_config
的内容来验证传输是否发生。
ls ~/app_config
如果在输出中没有看到prod.secret.exs
,请查看本地开发机器上的终端以获取更多信息。
通过生产服务器上的prod.secret.exs
,我们已经准备好将安装Distillery的构建过程和edeliver进行部署,将它们都包含在mix.exs
( test
项目的主要配置文件)中。
在本地开发机器上打开mix.exs
。
nano ~/test/mix.exs
找到以下代码块:
...
def application do
[mod: {Test, []},
applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext]]
end
...
applications
列表定义了我们希望Mix在开始test
项目之前启动的依赖项。 由于我们希望在test
项目运行时确保Distillery和edeliver始终可用,因此我们将在这里添加它们。
警告:因为这个列表中的应用程序通常是按照它们出现的顺序启动的,并且因为在启动edeliver之前我们需要启动和运行所有的东西,所以edeliver必须是列表中的最后一个应用程序。
添加distillery
和edeliver
到applications
列表。
...
def application do
[mod: {Test, []},
applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext, :distillery, :edeliver]]
end
...
现在,找到下面的代码块:
...
defp deps do
[{:phoenix, "~> 1.2.5"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_html, "~> 2.6"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"}]
end
...
deps
是一个私有函数,明确定义了我们所有的test
项目的依赖关系。 虽然这不是严格要求,但确实有助于保持项目组态。
添加edeliver
和distillery
的依赖列表。
...
defp deps do
[{:phoenix, "~> 1.2.5"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_html, "~> 2.6"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:edeliver, "~> 1.4.3"},
{:distillery, "~> 1.4"}]
end
...
注:为避免潜在的配置问题,请仔细检查您是否在新edeliver
条目前面的行末尾添加了一个。
保存您的更改并关闭mix.exs
。
现在,告诉mix
来获取新的依赖关系,以便它们在运行时可用。
cd ~/test/
mix deps.get
产量告诉我们, edeliver
和distillery
已成功添加到我们的项目。
OutputResolving Hex dependencies...
Dependency resolution completed:
...
* Getting edeliver (Hex package)
Checking package (https://repo.hex.pm/tarballs/edeliver-1.4.4.tar)
Fetched package
* Getting distillery (Hex package)
Checking package (https://repo.hex.pm/tarballs/distillery-1.5.2.tar)
Fetched package
最后,在本地开发机上重新启动Phoenix的服务器来测试当前的配置。
mix phoenix.server
将浏览器指向http:// localhost:4000 。 您应该看到您在第4步中看到的相同的默认Phoenix主页。如果您没有,请重新跟踪以前的步骤并查看您的本地开发机器的终端以获取更多信息。
准备好继续时,按两次CTRL+C
停止服务器,以便在下一步中进一步配置。
随着Distillery和edeliver的安装,我们准备配置他们的部署。
第6步 - 配置Edeliver和Distillery
Distillery需要一个默认不生成的构建配置文件。 但是,我们可以通过运行mix release.init
来生成默认配置。
进入本地开发机器的test
目录并生成配置文件。
cd ~/test
mix release.init
输出确认该文件已创建,并包含有关如何编辑和构建发行版的更多说明。
OutputAn example config file has been placed in rel/config.exs, review it,
make edits as needed/desired, and then run `mix release` to build the release
在执行热升级时,edeliver将在rel/ test
目录中查找发行版,但Distillery默认将发行版放在_build
目录中。 因此,让我们修改Distillery的默认配置文件rel/config.exs
,将生产版本放在正确的位置。
打开rel/config.exs
进行编辑。
nano rel/config.exs
找到以下内容:
...
environment :prod do
set include_erts: true
set include_src: false
set cookie: :"f3a1[Q^31~]3~N=|T|T=0NvN;h7OHK!%%c.}$)iP9!X|TS[X@sqG=m`yBYVt4/`:"
end
...
该块告诉Distillery我们如何让它建立独立的产品发布包。 include_erts
指示我们是否要捆绑Erlang运行时系统,这在目标系统没有安装Erlang或Elixir时很有用。 include_src
指示我们是否要包含源代码文件。 并且, cookie
值用于认证Erlang节点彼此通信。
将output_dir
选项添加到此块,以告诉Distillery我们希望它放置生产版本的位置。
...
environment :prod do
set include_erts: true
set include_src: false
set cookie: :"f3a1[Q^31~]3~N=|T|T=0NvN;h7OHK!%%c.}$)iP9!X|TS[X@sqG=m`yBYVt4/`:"
set output_dir: "rel/test"
end
...
保存并关闭文件。
我们现在准备配置edeliver,但是我们必须手动创建它的配置文件。
进入本地开发机器上的test
目录,并创建一个名为.deliver
的新目录,然后在.deliver/config
打开一个新文件进行编辑。
cd ~/test
mkdir .deliver
nano .deliver/config
在这个文件中,我们将指定构建和生产服务器的细节。 由于我们在建筑和生产中使用相同的服务器,因此我们的主机和用户在构建和生产中是相同的。 另外,我们将在app_build
目录中执行构建,并将编译后的生产文件放在app_release
目录中。
将以下内容复制到文件中。
APP="test"
BUILD_HOST="example.com"
BUILD_USER="sammy"
BUILD_AT="/home/sammy/app_build"
PRODUCTION_HOSTS="example.com"
PRODUCTION_USER="sammy"
DELIVER_TO="/home/sammy/app_release"
接下来,我们将在build文件夹中创建一个符号链接prod.secret.exs
,这是我们在第5步中传送到生产服务器的app_config
目录中的文件。该符号链接是在edeliver钩子内部创建的。 在构建,阶段和部署过程的每个点,edeliver调用一个特定的钩子。 对于我们的自动化部署设置,我们正在监听在edeliver获取我们的依赖关系之前调用的pre_erlang_get_and_update_deps
钩子,并开始编译。
将以下内容添加到.deliver/config
。
pre_erlang_get_and_update_deps() {
local _prod_secret_path="/home/sammy/app_config/prod.secret.exs"
if [ "$TARGET_MIX_ENV" = "prod" ]; then
__sync_remote "
ln -sfn '$_prod_secret_path' '$BUILD_AT/config/prod.secret.exs'
"
fi
}
完成编辑后保存并关闭文件。
因为edeliver使用Git将代码从最新的提交推送到构建服务器以进行进一步操作,所以部署之前的最后一步是为我们的项目创建一个Git存储库。
在本地开发机器上的test
目录中,使用git init
命令创建一个空的Git存储库。
cd ~/test
git init
接下来,将来自test
项目的完整文件集添加到Git临时区域,以便将它们包含在下一次提交中。
git add .
现在,设置Git应该与这个仓库关联的身份。 这将帮助您跟踪项目更改的来源。
git config user.email "you@example.com"
git config user.name "Your Name"
最后,使用-m
选项将文件提交到存储库以描述提交的原因。
git commit -m "Setting up automated deployment"
输出会重复提交您的提交消息,然后报告更改的文件数量,插入的行数以及添加到存储库的文件的名称。
Output[master (root-commit) e58b766] Setting up automated deployment
38 files changed, 2143 insertions(+)
create mode 100644 .deliver/config
...
现在我们的项目已经完成了Git和Distillery以及edeliver的配置,我们已经做好了第一次部署的准备。
第7步 - 部署项目
这个部署过程的一个好处是你可以在本地开发机器上做几乎所有事情,很少需要Touch生产服务器。
现在通过将test
项目推送到生产服务器来测试所有东西。
首先,在您的本地开发机器上使用mix
来构建项目的发行版,并使用edeliver将其转移到构建服务器。
cd ~/test
mix edeliver build release
输出会实时更新构建过程的每个步骤,如果一切按预期工作,则会告诉您构建成功。
OutputBUILDING RELEASE OF TEST APP ON BUILD HOST
-----> Authorizing hosts
-----> Ensuring hosts are ready to accept git pushes
-----> Pushing new commits with git to: sammy@example.com
-----> Resetting remote hosts to fc86f878d96...
-----> Cleaning generated files from last build
-----> Fetching / Updating dependencies
-----> Compiling sources
-----> Generating release
-----> Copying release 0.0.1 to local release store
-----> Copying test.tar.gz to release store
RELEASE BUILD OF TEST WAS SUCCESSFUL!
如果你的构建不成功,edeliver会指出它遇到问题时试图执行的代码行。 您可以使用该信息来解决问题。
构建完成后,将该版本转移到生产服务器。
mix edeliver deploy release to production
再一次,输出会实时更新您关于流程的每一步,如果一切正常,则会告诉您构建已发布到生产环境。
OutputDEPLOYING RELEASE OF TEST APP TO PRODUCTION HOSTS
-----> Authorizing hosts
-----> Uploading archive of release 0.0.1 from local release store
-----> Extracting archive test_0.0.1.tar.gz
DEPLOYED RELEASE TO PRODUCTION!
如果遇到部署问题,请检查终端中的输出以获取更多信息。
最后,在生产服务器上启动test
项目。
mix edeliver start production
输出会告诉用户项目正在运行,运行的主机以及生产服务器上正在使用的发行版的路径。 回应将会START DONE!
。
OutputEDELIVER TEST WITH START COMMAND
-----> starting production servers
production node:
user : sammy
host : example.com
path : /home/sammy/app_release
response:
START DONE!
通过将浏览器指向http:// example.com :4000
来测试部署过程。 你应该再次看到默认的Phoenix Framework主页。 如果不这样做,请仔细检查生产服务器上是否打开了端口4000
,然后咨询本地开发机器的终端以获取更多信息。
现在我们已经验证了完整的构建和部署过程,让我们通过在生产服务器上执行代码更新而无需任何停机时间来进行更进一步的设置。
第8步 - 升级项目没有生产停机时间
我们构建和部署过程的一个特点是能够热插拔代码,更新生产服务器上的项目而不会造成任何停机。 让我们对这个项目做一些改变,试试看。
打开项目的主页文件进行编辑。
nano ~/test/web/templates/page/index.html.eex
找到以下行:
...
<h2><%= gettext "Welcome to %{name}", name: "Phoenix!" %></h2>
...
现在,用以下代替这一行:
<h2>Hello, World!</h2>
保存并关闭文件。
现在我们已经更新了代码库,我们还需要增加应用程序的版本。 如果需要,版本号可以更容易地跟踪版本并回滚到以前的版本。
在本地开发机器上打开mix.exs
。
nano ~/test/mix.exs
找到以下块:
...
def project do
[app: :test,
version: "0.0.1",
elixir: "~> 1.2",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext] ++ Mix.compilers,
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps()]
end
...
将版本从0.0.1
增加到0.0.2
。
...
def project do
[app: :test,
version: "0.0.2",
elixir: "~> 1.2",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext] ++ Mix.compilers,
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps()]
end
...
然后保存并关闭文件。
现在我们需要添加和提交我们对Git的修改,以便edeliver知道它应该将它们推送到构建服务器。
git add .
git commit -m "Changed welcome message"
最后,我们准备热插拔我们的更改。 这一次,我们有一个单一的命令,相当于我们在第7步中使用的三个相关的命令。
使用一个命令,在生产服务器上构建,部署和重新启动应用程序。
mix edeliver upgrade production
再一次,输出将实时完成整个过程的每一步,如果成功,则以UPGRADE DONE!
。
OutputEDELIVER TEST WITH UPGRADE COMMAND
-----> Upgrading to revision 2fc28b6 from branch master
-----> Detecting release versions on production hosts
-----> Deploying upgrades to 1 online hosts
-----> Checking whether installed version 0.0.1 is in release store
-----> Building the upgrade from version 0.0.1
-----> Authorizing hosts
-----> Validating * version 0.0.1 is in local release store
-----> Ensuring hosts are ready to accept git pushes
-----> Pushing new commits with git to: sammy@example.com
-----> Resetting remote hosts to 2fc28b6...
-----> Cleaning generated files from last build
-----> Checking out 2fc28b6...
-----> Fetching / Updating dependencies
-----> Compiling sources
-----> Checking version of new release
-----> Uploading archive of release 0.0.1 from local release store
-----> Extracting archive test_0.0.1.tar.gz
-----> Generating release
-----> Removing built release 0.0.1 from remote release directory
-----> Copying release 0.0.2 to local release store
-----> Copying test.tar.gz to release store
-----> Upgrading production hosts to version 0.0.2
-----> Authorizing hosts
-----> Uploading archive of release 0.0.2 from local release store
-----> Upgrading release to 0.0.2
UPGRADE DONE!
要验证一切正常,请在浏览器中重新加载http:// example.com :4000
。 你应该看到新的消息。 如果您不这样做,请重新跟踪之前的步骤,并检查您的终端是否有其他错误和警告消息。
现在部署过程已经被简化为一个命令,我们也正在使用Erlang最着名的功能之一 - 代码热插拔。 作为最后一步,让我们通过把它放在Nginx代理的后面来强化我们的应用程序。
第9步 - 在生产服务器上设置反向代理
虽然我们可以直接将我们的应用程序暴露给Internet,但是反向代理将提供更好的安全性。 为了便于配置,支持SSL以及设置自定义HTTP响应头的功能,我们将使用Nginx作为我们的代理。
如果您按照先决条件在Ubuntu 16.04教程中设置了Let's Encrypt with Nginx服务器模块 ,那么您应该已经在生产服务器上为我们的项目创建了一个单独的Nginx服务器模块。
打开该服务器块的配置文件进行编辑。
sudo nano /etc/nginx/sites-available/example.com
首先,我们需要告诉Nginx我们的Phoenix项目所在的位置以及它监听的端口。 由于我们正在本地端口4000
,所以我们告诉Nginx我们的代理端点是127.0.0.1:4000
。
将以下代码复制到默认服务器配置块上方的配置文件中。
<^>upstream phoenix {
server 127.0.0.1:4000;
}<^>
现在,在同一个文件中,找到下面的代码块:
...
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
...
为了使代理正常工作,我们需要告诉Nginx将所有连接到web服务器的连接重定向到我们的Phoenix项目,包括请求头,客户端通过代理服务器的IP地址以及客户端的IP地址本身。
我们还将Nginx配置为通过WebSockets (一种Web服务器与客户端之间的消息传递协议)将标准无状态HTTP连接升级为持久连接的协议来转发传入请求。
Phoenix有一个名为Channels的功能,我们在本教程中没有进行探索,但Channels需要对WebSockets的支持。 如果没有这个配置,Channels将无法工作,因为WebSocket请求不会将其发送到服务器。
将以前的location
块替换为以下内容:
location / {
allow all;
# Proxy Headers
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Cluster-Client-Ip $remote_addr;
# WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://phoenix;
}
保存并关闭文件以继续。
现在,验证新的Nginx配置。
sudo nginx -t
Nginx应该报告语法没问题,测试成功了。 如果没有,请按照屏幕上的信息解决问题。
重新启动Nginx来传播更改。
sudo systemctl restart nginx
最后,通过将浏览器指向https:// example.com
来测试一切正常。
您现在拥有一个完全自动化的构建和部署过程,以及一个由反向代理和SSL证书保护的生产服务器。
结论
尽管我们已经建立了edeliver来使用一个命令来构建和部署我们的Phoenix项目到生产服务器,但是仍然有很多可以做的事情。
如果您的生产基础架构由一组Phoenix节点组成,则可以使用edeliver一次性部署到所有节点并进行热交换。
或者,如果您想要具有更高可靠性的设置,则可以创建一个完整的临时基础架构,并使用edeliver来管理暂存和部署过程。
要了解有关这两个主题的更多信息,或想要了解有关扩展当前edeliver安装的更多信息,请访问GitHub上的项目官方主页 。