查看源代码 在 Fly.io 上部署

Fly.io 为 Elixir/Phoenix 提供了他们自己的指南:Fly.io/docs/elixir/getting-started/ 我们会继续维护本指南,但最新的信息请参考他们的网站!

我们需要什么

本指南只需要一个可运行的 Phoenix 应用程序。对于需要部署简单应用程序的用户,请遵循 运行指南

你只需要

$ mix phx.new my_app

目标

本指南的主要目标是在 Fly.io 上运行一个 Phoenix 应用程序。

章节

我们将把这个过程分成几个步骤,这样我们就可以跟踪我们的进度。

  • 安装 Fly.io CLI
  • 注册 Fly.io
  • 将应用程序部署到 Fly.io
  • Fly.io 额外提示
  • 有用的 Fly.io 资源

安装 Fly.io CLI

按照 这里的说明 安装 Flyctl,它是 Fly.io 平台的命令行界面。

注册 Fly.io

我们可以使用 CLI 注册一个帐户

$ fly auth signup

或者登录。

$ flyctl auth login

Fly 为大多数应用程序提供 免费层级。在设置帐户时需要信用卡,以防止滥用。有关更多详细信息,请查看 定价 页面。

将应用程序部署到 Fly.io

要将应用程序告知 Fly,请在包含源代码的目录中运行 fly launch。这将创建和配置一个 Fly.io 应用程序。

$ fly launch

这将扫描您的源代码,检测 Phoenix 项目,并为您运行 mix phx.gen.release --docker!这将为您创建一个 Dockerfile。

fly launch 命令将引导您完成一些问题。

  • 您可以命名应用程序,也可以让它为您生成随机名称。
  • 选择一个组织(默认为 personal)。组织是 Fly.io 用户之间共享应用程序和资源的一种方式。
  • 选择一个要部署到的区域。默认为最接近的 Fly.io 区域。您可以查看 完整的区域列表
  • 为您设置一个 Postgres DB。
  • 构建 Dockerfile。
  • 部署您的应用程序!

fly launch 命令还为您创建了一个 fly.toml 文件。您可以在其中设置环境变量和其他配置。

在 Fly.io 上存储秘密

您可能还有一些秘密需要在您的应用程序上设置。

使用 fly secrets 来配置它们。

$ fly secrets set MY_SECRET_KEY=my_secret_value

再次部署

当您想部署对应用程序的更改时,请使用 fly deploy

$ fly deploy

注意:在 Apple Silicon (M1) 计算机上,docker 使用 qemu 运行跨平台构建,这可能并不总是有效。如果您遇到以下类似的段错误,

 => [build  7/17] RUN mix deps.get --only
 => => # qemu: uncaught target signal 11 (Segmentation fault) - core dumped

您可以通过添加 --remote-only 标志来使用 fly 的远程构建器

$ fly deploy --remote-only

您始终可以检查部署的状态

$ fly status

检查您的应用程序日志

$ fly logs

如果一切正常,请在 Fly 上打开您的应用程序

$ fly open

Fly.io 额外提示

进入正在运行的节点的 IEx shell

Elixir 支持进入正在运行的生产节点的 IEx shell。

有几个先决条件,我们首先需要建立一个到 Fly.io 上我们机器的 SSH Shell

此步骤将为您的帐户设置根证书,然后颁发证书。

$ fly ssh issue --agent

配置好 SSH 后,让我们打开一个控制台。

$ fly ssh console
Connecting to my-app-1234.internal... complete
/ #

如果一切顺利,那么您就可以进入机器的 shell 了!现在我们只需要启动远程 IEx shell 即可。部署的 Dockerfile 被配置为将我们的应用程序拉取到 /app。因此,名为 my_app 的应用程序的命令如下所示

$ app/bin/my_app remote
Erlang/OTP 23 [erts-11.2.1] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1]

Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(my_app@fdaa:0:1da8:a7b:ac4:b204:7e29:2)1>

现在我们已经进入节点的运行 IEx shell 了!您可以使用 CTRL+C、CTRL+C 安全地断开连接。

对应用程序进行集群

Elixir 和 BEAM 具有令人难以置信的能力,可以将它们一起集群,并在节点之间无缝传递消息。本指南的这一部分将引导您完成对 Elixir 应用程序进行集群的过程。

在 Fly.io 上快速设置集群有两个部分。

  • 安装和使用 libcluster
  • 将应用程序扩展到多个实例

添加 libcluster

广泛采用的库 libcluster 在这里有所帮助。

libcluster 可以使用多种策略来查找和连接其他节点。我们将在 Fly.io 上使用的策略是 DNSPoll

安装 libcluster 后,像这样将其添加到应用程序中

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    topologies = Application.get_env(:libcluster, :topologies) || []

    children = [
      # ...
      # setup for clustering
      {Cluster.Supervisor, [topologies, [name: MyApp.ClusterSupervisor]]}
    ]

    # ...
  end

  # ...
end

我们的下一步是在 config/runtime.exs 中添加 topologies 配置。

  app_name =
    System.get_env("FLY_APP_NAME") ||
      raise "FLY_APP_NAME not available"

  config :libcluster,
    topologies: [
      fly6pn: [
        strategy: Cluster.Strategy.DNSPoll,
        config: [
          polling_interval: 5_000,
          query: "#{app_name}.internal",
          node_basename: app_name
        ]
      ]
    ]

这将配置 libcluster 使用 DNSPoll 策略,并使用 $FLY_APP_NAME.internal 私有网络上查找其他已部署的应用程序。

控制节点的名称

我们需要控制 Elixir 节点的命名。为了帮助它们连接起来,我们将使用以下模式为它们命名:[email protected]。为此,我们将生成发布配置。

$ mix release.init

然后编辑生成的 rel/env.sh.eex 文件,并添加以下几行

ip=$(grep fly-local-6pn /etc/hosts | cut -f 1)
export RELEASE_DISTRIBUTION=name
export RELEASE_NODE=$FLY_APP_NAME@$ip

完成更改后,部署您的应用程序!

$ fly deploy

为了让我们的应用程序形成集群,我们必须拥有多个实例。接下来,我们将添加一个额外的节点实例。

运行多个实例

运行多个实例有两种方法。

  1. 将我们的应用程序扩展到在一个区域中拥有多个实例。
  2. 向另一个区域添加一个实例(多个区域)。

首先让我们从单个部署的基线开始。

$ fly status
...
Instances
ID       VERSION REGION DESIRED STATUS  HEALTH CHECKS      RESTARTS CREATED
f9014bf7 26      sea    run     running 1 total, 1 passing 0        1h8m ago

在一个区域中进行扩展

让我们将当前区域中的实例扩展到 2 个。

$ fly scale count 2
Count changed to 2

检查状态,我们可以看到发生了什么。

$ fly status
...
Instances
ID       VERSION REGION DESIRED STATUS  HEALTH CHECKS      RESTARTS CREATED
eb4119d3 27      sea    run     running 1 total, 1 passing 0        39s ago
f9014bf7 27      sea    run     running 1 total, 1 passing 0        1h13m ago

现在我们拥有两个位于同一个区域的实例。

让我们确保它们已形成集群。我们可以查看日志

$ fly logs
...
app[eb4119d3] sea [info] 21:50:21.924 [info] [libcluster:fly6pn] connected to :"my-app-1234@fdaa:0:1da8:a7b:ac2:f901:4bf7:2"
...

但这不如从节点内部查看它那么令人满意。从 IEx shell 中,我们可以询问我们连接到的节点,它可以看到哪些其他节点。

$ fly ssh console -C "/app/bin/my_app remote"
iex(my-app-1234@fdaa:0:1da8:a7b:ac2:f901:4bf7:2)1> Node.list
[:"my-app-1234@fdaa:0:1da8:a7b:ac4:eb41:19d3:2"]

IEx 提示符已包含在内,以帮助显示我们连接到的节点的 IP 地址。然后获取 Node.list 将返回另一个节点。我们的两个实例已连接并形成集群!

扩展到多个区域

Fly 使得在靠近您的用户的位置部署实例变得非常容易。通过 DNS 的魔力,用户会被定向到您应用程序所在的最近区域。您可以在此处阅读有关 Fly.io 区域 的更多信息。

从我们的基线开始,它是一个位于 sea(即美国华盛顿州西雅图)中的单个实例,让我们添加区域 ewr(即美国新泽西州帕西帕尼)。这将在美国的两个海岸上放置一个实例。

$ fly regions add ewr
Region Pool:
ewr
sea
Backup Region:
iad
lax
sjc
vin

查看状态显示我们只在 1 个区域中,因为我们的计数设置为 1。

$ fly status
...
Instances
ID       VERSION REGION DESIRED STATUS  HEALTH CHECKS      RESTARTS CREATED
cdf6c422 29      sea    run     running 1 total, 1 passing 0        58s ago

让我们添加一个第二个实例,看看它是否部署到 ewr

$ fly scale count 2
Count changed to 2

现在状态显示我们拥有两个跨越 2 个区域的实例!

$ fly status
...
Instances
ID       VERSION REGION DESIRED STATUS  HEALTH CHECKS      RESTARTS CREATED
0a8e6666 30      ewr    run     running 1 total, 1 passing 0        16s ago
cdf6c422 30      sea    run     running 1 total, 1 passing 0        6m47s ago

让我们确保它们已形成集群。

$ fly ssh console -C "/app/bin/my_app remote"
iex(my-app-1234@fdaa:0:1da8:a7b:ac2:cdf6:c422:2)1> Node.list
[:"my-app-1234@fdaa:0:1da8:a7b:ab2:a8e:6666:2"]

我们拥有两个应用程序实例,分别部署到北美大陆的西海岸和东海岸,它们已形成集群!我们的用户将自动被定向到离他们最近的服务器。

Fly.io 平台内置了分发支持,使在多个区域中对分布式 Elixir 节点进行集群变得非常容易。

有用的 Fly.io 资源

打开您帐户的仪表板

$ fly dashboard

部署您的应用程序

$ fly deploy

显示已部署应用程序的状态

$ fly status

访问并跟踪日志

$ fly logs

将您的应用程序扩展或缩减

$ fly scale count 2

有关更多信息,请参考 Fly.io Elixir 文档

使用 Fly.io 应用程序 涵盖了以下内容

  • 状态和日志
  • 自定义域名
  • 证书

故障排除

请查看 故障排除Elixir 故障排除

访问 Fly.io 社区 以找到解决方案并提出问题。