如何在Ubuntu16.04上使用Distillery和edeliver自动化Elixir-Phoenix部署
介绍
基于 Erlang 编程语言,Elixir 是一种函数式编程语言,因其专注于开发人员的生产力和易于编写高度并发和可扩展的应用程序而广受欢迎。
Phoenix 是基于 Elixir 构建的 Web 框架,允许创建高性能 Web 应用程序。
当与两个额外的工具——Distillery 和 edeliver 结合使用时,您可以完全自动化地将 Phoenix 项目从开发环境部署到生产服务器。
Distillery 将 Elixir 应用程序编译成单个包,然后您可以将其部署到其他地方。 它还生成允许 热交换 代码的包,这意味着您可以升级实时应用程序而无需停机。 所有这些都可以在您几乎没有配置的情况下完成,这使 Distillery 与许多其他选项不同。
edeliver 通过处理重复性任务(例如构建应用程序、将构建的包传输到服务器、迁移数据库以及启动/更新服务器)来自动化此构建和部署过程。 如果需要,您甚至可以配置 edeliver 以允许中间暂存设置。
在本教程中,您将在本地开发机器和生产服务器上安装 Erlang、Elixir 和 Phoenix 1.3,您将简化两个位置之间的 SSH 通信,然后您将创建一个示例 Phoenix 项目来构建和使用 edeliver 部署。 最后,您将使用 Nginx 反向代理和 SSL 证书保护生产服务器。
在本教程结束时,您将拥有一个命令,它可以:
- 构建与您的生产环境兼容的 Phoenix 版本
- 将发布部署到您的生产环境
- 在生产环境中启动您的应用程序
- 通过在不停机的情况下部署新版本来热交换当前的生产版本
先决条件
在开始之前,请确保您具备以下条件:
- 基于 Ubuntu 的本地开发机器。 尽管本教程的说明是为基于 Ubuntu 的本地开发机器编写的,但此部署过程的一个优势在于它完全独立于生产环境。 关于在其他操作系统上设置本地开发机器的说明,请参见【X94X】官方Elixir安装文档【X140X】。 或者,要设置基于 Ubuntu 的 远程 开发机器,请按照 这个初始服务器设置教程 。
- 在具有至少 1GB RAM 的 Ubuntu 16.04 生产服务器上具有 sudo 权限的非 root 用户帐户,按照 此初始服务器设置教程 中的前四个步骤进行设置。
- 由于我们的目标是自动化部署过程,因此在执行设置教程的第 4 步时不要输入 SSH 密码。 此外,请确保在设置教程的第 7 步中使用命令
sudo ufw allow 4000
允许访问端口4000
。 这是我们将在本教程中用于测试 Phoenix 的端口。
- 由于我们的目标是自动化部署过程,因此在执行设置教程的第 4 步时不要输入 SSH 密码。 此外,请确保在设置教程的第 7 步中使用命令
- 按照 this How To Install Nginx on Ubuntu 16.04 guide 在生产服务器上安装 Nginx。
- 完全注册的域名。 本教程将自始至终使用
example.com
。 您可以在 Namecheap 上购买一个域名,在 Freenom 上免费获得一个域名,或者使用您选择的域名注册商。 - 为您的服务器设置了以下两个 DNS 记录。 您可以关注 this hostname tutorial 了解如何添加它们的详细信息。
- 带有
example.com
的 A 记录指向您服务器的公共 IP 地址。 - 带有
www.example.com
的 A 记录指向您服务器的公共 IP 地址。
- 带有
- Nginx 通过遵循 在 Ubuntu 16.04 教程 上设置 Let's Encrypt with Nginx server blocks 使用 SSL 证书进行保护。 请务必在 Nginx 设置教程的第 4 步中选择选项 2
Redirect
,因为这将自动重定向到我们在本教程中创建的生产服务器上的 HTTPS。
第 1 步 — 在本地开发机器上安装 Elixir 和 Phoenix
因为 Elixir 在 Erlang VM 上运行,所以我们需要先安装 VM,然后才能安装 Elixir 本身。 由于我们要确保我们使用的是最新的稳定版本的 Erlang,我们将从 Erlang Solutions 存储库安装 Erlang。
首先,下载 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
软件包,它提供 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
现在,使用 Hex 安装 Phoenix 1.3.0 Mix 存档,这是一个 Zip 文件,其中包含生成新的基础 Phoenix 项目以进行构建所需的一切。
mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new-1.3.0.ez
同样,当提示确认安装时,输入 Y
。
OutputAre you sure you want to install "https://github.com/phoenixframework/archives/raw/master/phx_new-1.3.0.ez"? [Yn] Y * creating .mix/archives/phx_new-1.3.0
警告: 如果您从 phx_new.ez
存档安装 Phoenix,您将获得最新版本的 Phoenix,它可能与我们在本教程中使用的版本不同 - 1.3.0。 然后,您必须使本教程适应您正在使用的 Phoenix 版本。
在本地开发机器上安装了 Elixir 和 Phoenix,让我们在生产服务器上安装我们需要的部分。
第 2 步 — 在生产服务器上安装 Elixir 和 Phoenix
因为我们需要 Phoenix 项目同时在本地开发机器和生产服务器上运行,所以我们需要在这两个地方安装所有相同的语言和工具。
使用 Step 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 安装 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,但是让我们通过设置 SSH 主机别名来更轻松地从本地开发机器连接到生产服务器。
第 3 步 — 设置 SSH 主机别名
因为我们的目标是完全自动化的部署过程,所以我们在 初始生产服务器设置 期间生成了一个不提示输入密码的 SSH 密钥对。
现在,我们可以使用命令 ssh -i ~/.ssh/private_key_file sammy@example.com
从本地开发机器连接到生产服务器。
在这里,我们以用户 sammy 的身份连接到 example.com
。 -i
标志告诉 SSH 使用位于 ~/.ssh/private_key_file
的私钥文件进行连接。
不过,我们可以通过设置一个 SSH 主机别名来使这个命令——以及部署过程本身——更加简单,该别名在连接到生产服务器时自动知道要使用哪个私钥、用户和域。
在本地开发机上打开【X5X】【X9X】进行编辑。
nano ~/.ssh/config
并且,复制以下行。
~/.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 数据库适配器和 Brunch,这是一个基于 JavaScript 的 Web 应用程序构建工具。 为了避免这种额外的复杂性,我们将通过分别传入 --no-ecto
和 --no-brunch
标志来创建一个名为 myproject
的简单 Phoenix 项目,它没有数据库适配器和早午餐。
切换到您的主目录并创建新项目。
cd ~ mix phx.new --no-ecto --no-brunch myproject
输出包括 Phoenix 作为 myproject
项目的脚手架创建的目录和文件,确认您要安装所需依赖项的提示,以及有关如何启动 Phoenix 内置服务器的说明。
提示确认安装时输入Y
。
Output* creating myproject/config/config.exs * creating myproject/config/dev.exs * creating myproject/config/prod.exs ... Fetch and install dependencies? [Yn] Y * running mix deps.get * running mix deps.compile We are all set! Go into your application by running: $ cd myproject Start your Phoenix app with: $ mix phx.server You can also run your app inside IEx (Interactive Elixir) as: $ iex -S mix phx.server
现在,让我们看看我们的测试项目是否正常工作。
进入myproject
目录,运行mix phx.server
命令编译工程并启动服务器。
cd ~/myproject mix phx.server
输出告诉你 Phoenix 编译的文件的数量和类型,给你关于它在此过程中遇到的问题的警告,如果成功,让你知道在哪里可以访问项目。
第一次在本地开发机器上编译基于 Elixir 的应用程序时,系统会提示您安装 Rebar,这是 Mix 所依赖的 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 myproject app [info] Running MyprojectWeb.Endpoint with Cowboy using http://0.0.0.0:4000
要测试当前设置,请将 Web 浏览器指向 http://localhost:4000。 您应该会看到默认的 Phoenix 框架主页欢迎您来到 Phoenix。 如果不这样做,请确保您的防火墙允许端口 4000
上的连接,然后查看终端输出以获取进一步说明。
确认一切正常后,按 CTRL+C
两次以停止服务器,以便在 步骤 5 中进行进一步配置。
现在您已经有了一个功能齐全的本地 Phoenix 项目,让我们将其配置为使用 Distillery 和 edeliver。
第 5 步 — 配置项目以使用 Distillery 和 edeliver
Phoenix 项目在 config/prod.exs
中存储配置详细信息,例如项目运行的端口和项目的主机 URL,因此我们将首先编辑该文件以告诉 Phoenix 如何在生产环境中访问项目。
在本地开发机器上打开config/prod.exs
进行编辑。
nano ~/myproject/config/prod.exs
找到以下代码块:
配置/prod.exs
... config :myproject, MyprojectWeb.Endpoint, load_from_system_env: true, url: [host: "example.com", port: 80], cache_static_manifest: "priv/static/cache_manifest.json" ...
当 load_from_system_env
设置为 true
时,Phoenix 默认从 PORT
环境变量中获取项目应该运行的端口。 这称为 HTTP 端口。
url: [host]
和 url: [port]
用于在项目内生成链接。 在设置代理端点暴露在与 Phoenix 项目不同的端口上的代理时,HTTP 和 URL 之间的这种差异特别有用。
为简单起见,我们将在 myproject
运行的 HTTP 端口中进行硬编码。 这将减少活动部件的数量,进而提高我们自动化部署过程的可靠性。
除了我们将要修改的默认选项外,我们还将添加两个新选项。
server
选项告诉 Distillery 配置项目以在启动时启动 HTTP 服务器,这是我们在全自动部署过程中想要的。
code_reloader
选项告诉项目在项目代码更改时刷新所有连接的 Web 浏览器。 虽然这在开发中可能是一个非常有用的功能,但它并不适用于生产环境,因此我们将其关闭。
现在,修改默认配置。
配置/prod.exs
... config :myproject, MyprojectWeb.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
。
当我们在 Step 4 中创建 myproject
项目时,Phoenix 自动生成了一个 .gitignore
文件,我们在推送代码时将在 Step 6 中需要该文件使用 edeliver 更改构建服务器。
默认情况下,那个 .gitignore
文件告诉 Git 忽略依赖项并构建文件,这样存储库就不会变得不必要的大。 此外,该文件告诉 Git 忽略 prod.secret.exs
,该文件位于所有 Phoenix 项目的 config
目录中,其中包含非常敏感的信息,例如生产数据库密码和用于签名令牌的应用程序机密。
由于 myproject
项目需要生产服务器上的 prod.secret.exs
才能正常运行,而我们无法使用 Git 将其移动到那里,因此我们必须手动将其传输到服务器。
在生产服务器的主目录中,创建一个名为 app_config
的新目录。 这是您将存储 prod.secret.exs
的地方。
cd ~ mkdir app_config
现在,使用 scp
将 prod.secret.exs
复制到生产服务器上的 app_config
目录。
scp ~/myproject/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,并通过将它们都包含在 mix.exs
中来进行部署,myproject
的主要配置文件] 项目。
在本地开发机器上打开 mix.exs
。
nano ~/myproject/mix.exs
现在,找到以下代码块:
mix.exs 中的依赖项
... defp deps do [ {:phoenix, "~> 1.3.0"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_html, "~> 2.10"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, {:cowboy, "~> 1.0"} ] end ...
deps
是一个私有函数,它明确定义了我们所有的 myproject
项目的依赖项。 虽然不是严格要求,但它确实有助于保持项目配置的有序性。
将 edeliver
和 distillery
添加到依赖项列表中。
mix.exs 中的依赖项
... defp deps do [ {:phoenix, "~> 1.3.0"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_html, "~> 2.10"}, {: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 ~/myproject/ 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 phx.server
将浏览器指向 http://localhost:4000。 您应该会看到与在 Step 4 中看到的相同的默认 Phoenix 主页。 如果不这样做,请重新跟踪前面的步骤并查看本地开发机器的终端以获取更多信息。
当您准备好继续时,按 CTRL+C
两次以停止服务器,以便为下一步的进一步配置做好准备。
安装 Distillery 和 edeliver 后,我们已准备好配置它们以进行部署。
第 6 步 — 配置 Edeliver 和 Distillery
Distillery 需要默认不生成的构建配置文件。 但是,我们可以通过运行 mix release.init
来生成默认配置。
进入本地开发机器上的myproject
目录并生成配置文件。
cd ~/myproject 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/myproject
目录中查找版本,但 Distillery 默认将版本放在 _build
目录中。 因此,让我们修改 Distillery 的默认配置文件 rel/config.exs
,以将生产版本放在正确的位置。
在编辑器中打开 rel/config.exs
。
nano rel/config.exs
找到以下部分:
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 节点之间的通信。
关闭文件。
我们现在已准备好配置 edeliver,但我们必须手动创建其配置文件。
进入本地开发机器上的myproject
目录,新建一个名为.deliver
的目录,然后在.deliver/config
打开一个新文件进行编辑。
cd ~/myproject mkdir .deliver nano .deliver/config
在此文件中,我们将指定构建和生产服务器的详细信息。 由于我们在构建和生产中使用相同的服务器,因此我们的主机和用户在构建和生产中是相同的。 此外,我们将在 app_build
目录中执行构建,并将编译后的生产文件放在 app_release
目录中。
将以下内容复制到文件中。
.交付/配置
APP="myproject" 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
的符号链接,我们在 Step 5 中将文件转移到生产服务器上的 app_config
目录。 这个符号链接是在 edeliver hook 中创建的。 在构建、阶段和部署过程的每一点,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 存储库。
在本地开发机器上的 myproject
目录中,使用 git init
命令创建一个空的 Git 存储库。
cd ~/myproject git init
在我们将文件添加到 Git 索引之前,我们还需要将包含我们的发布 tarball 的目录添加到 .gitignore
文件中。 否则,Git 存储库会在几个版本之后变得非常大。
echo ".deliver/releases/" >> .gitignore
接下来,将 myproject
项目中的完整文件集添加到 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 39 files changed, 2344 insertions(+) create mode 100644 .deliver/config ...
现在我们的项目已提交到 Git 和 Distillery 并已完全配置好,我们已准备好进行第一次部署。
第 7 步 — 部署项目
这种部署过程的一个好处是您几乎可以在本地开发机器上完成所有工作,而很少需要接触生产服务器。
现在让我们通过将 myproject
项目推送到生产服务器来完成所有项目。
首先,在您的本地开发机器上使用 mix
构建项目的发布版本,并使用 edeliver 将其传输到构建服务器。
cd ~/myproject mix edeliver build release
输出会实时更新您构建过程的每个步骤,如果一切正常,则告诉您构建成功。
OutputBUILDING RELEASE OF MYPROJECT 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 myproject.tar.gz to release store RELEASE BUILD OF MYPROJECT WAS SUCCESSFUL!
如果您的构建不成功,edeliver 将指出它遇到问题时尝试执行的代码行。 您可以使用该信息来解决问题。
构建完成后,将发布传输到生产服务器。
mix edeliver deploy release to production
再一次,输出会实时更新您流程的每个步骤,如果一切正常,则会告诉您构建已发布到生产环境。
OutputDEPLOYING RELEASE OF MYPROJECT APP TO PRODUCTION HOSTS -----> Authorizing hosts -----> Uploading archive of release 0.0.1 from local release store -----> Extracting archive myproject.0.1.tar.gz DEPLOYED RELEASE TO PRODUCTION!
如果您在部署时遇到问题,请检查终端中的输出以获取更多信息。
最后,在生产服务器上启动myproject
项目。
mix edeliver start production
输出告诉您项目正在运行的用户,它正在运行的主机,以及它在生产服务器上使用的版本的路径。 响应将是 START DONE!
。
OutputEDELIVER MYPROJECT 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 ~/myproject/lib/myproject_web/templates/page/index.html.eex
找到以下行:
~/myproject/web/templates/page/index.html.eex
... <h2><%= gettext "Welcome to %{name}", name: "Phoenix!" %></h2> ...
现在,将该行替换为以下内容:
<h2>Hello, World!</h2>
保存并关闭文件。
现在我们已经更新了代码库,我们还需要增加应用程序版本。 版本号可以更轻松地跟踪版本并在必要时回滚到以前的版本。
在本地开发机器上打开 mix.exs
。
nano ~/myproject/mix.exs
找到以下块:
mix.exs
... def project do [app: :myproject, 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
。
mix.exs
... def project do [app: :myproject, 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"
最后,我们准备好热交换我们的更改。 这一次,我们有一个命令,相当于我们在 Step 7 中使用的三个相关命令。
使用一个命令,在生产服务器上构建、部署和重新启动应用程序。
mix edeliver upgrade production
再一次,输出会实时引导我们完成过程的每个步骤,如果成功,则以 UPGRADE DONE!
结束。
OutputEDELIVER MYPROJECT 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 myproject_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 myproject.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 server blocks,您应该已经为我们的项目在生产服务器上创建了一个单独的Nginx服务器块。
打开该服务器块的配置文件进行编辑。
sudo nano /etc/nginx/sites-available/example.com
首先,我们需要告诉 Nginx 我们的 Phoenix 项目驻留在哪里以及它监听的端口。 由于我们在本地端口 4000
上为我们的项目提供服务,因此我们告诉 Nginx 我们的代理端点位于 127.0.0.1:4000
。
将以下代码复制到默认服务器配置块上方的配置文件中。
/etc/nginx/sites-available/example.com
upstream phoenix { server 127.0.0.1:4000; }
现在,在同一个文件中,找到以下代码块:
/etc/nginx/sites-available/example.com
... 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
块替换为以下内容:
/etc/nginx/sites-available/example.com
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
最后,出于安全考虑,禁止通过端口 4000
上的 HTTP 访问您的应用程序。
sudo ufw delete allow 4000
然后,检查 UFW 的状态。
sudo ufw status
此时防火墙应该只允许 SSH 和 Nginx 访问。
OutputStatus: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)
最后,通过将浏览器指向 https://example.com
来测试一切是否正常。
您现在拥有一个完全自动化的构建和部署过程以及一个由反向代理和 SSL 证书保护的生产服务器。
结论
尽管我们已经设置了 edeliver 以使用单个命令构建和部署我们的 Phoenix 项目到生产服务器,但您仍然可以做更多的事情。
大多数生产 Phoenix 应用程序都使用数据库。 在 如何在 Ubuntu 16.04 上使用 MySQL 部署 Elixir-Phoenix 应用程序中,您将在添加 MySQL 数据库并将新功能部署到生产环境时继续使用此应用程序。
如果您的生产基础设施由 Phoenix 节点集群组成,您可以使用 edeliver 一次部署到所有节点并在所有节点上执行热交换。
或者,如果您想要一个具有更高可靠性的设置,您可以创建一个成熟的暂存基础架构并使用 edeliver 来管理暂存和部署过程。
要了解有关这些主题的更多信息或了解有关扩展当前 edeliver 安装的更多信息,请访问项目的 GitHub 上的官方主页 。