Phoenix Production デプロイへの道その3：Distillery編

## はじめに

Phoenix の公式ドキュメントには 「heroku か Distillery」
と書いてあったので、 Distillery というのを使ってみます。

ちなみに Distillery (でぃす**てぃ**らりー) というのは「蒸留酒製造工場」
のことらしいです。 distilling ってのが「蒸留」って意味らしいです。

しかし、この Distillery、どうやら release というアーカイブをビルドするところまでが
仕事の範囲らしく、このアーカイブをどうやって本番サーバーに適用するかまでは
扱っていないようです。

それらは

- [EDeliver](https://github.com/edeliver/edeliver) (capistrano っぽい考え方？)
- [gatling](https://github.com/hashrocket/gatling) (heroku っぽい考え方？)

などを使って行わないといけないようです。

Distillery を使うと、

- 環境に応じた erts (Erlang RunTime System) の同梱
- 依存ライブラリの同梱
- OTP release 形式に対応したファイルの生成(Hot upgrade/downgrade)
- start, stop, restart, remote_console, ping などのアプリケーションに対する各種サブコマンド群の生成

などが行われるようです。

今回はビルドして動かしてみるところだけやってみます。

公式のドキュメントが結構充実しているので基本的にはここに書いてある通りにやってみます。

- [Using Distillery With Phoenix](https://hexdocs.pm/distillery/use-with-phoenix.html#content)
- [Phoenix Walkthrough](https://hexdocs.pm/distillery/phoenix-walkthrough.html#content)

## mix.exs へ依存関係の追加

``` diff:mix.exs
@@ -40,7 +40,8 @@ defmodule Blog.Mixfile do
       {:phoenix_html, "~> 2.10"},
       {:phoenix_live_reload, "~> 1.0", only: :dev},
       {:gettext, "~> 0.11"},
-      {:cowboy, "~> 1.0"}
+      {:cowboy, "~> 1.0"},
+      {:distillery, "~> 1.5", runtime: false}
     ]
   end
```

します。現在の最新版は1.5系っぽいので、1.5で。

## インストール

```
$ mix do deps.get, compile
Running dependency resolution...
Dependency resolution completed:
  connection 1.0.4
  cowboy 1.1.2
  cowlib 1.0.2
  db_connection 1.1.2
  decimal 1.4.0
  distillery 1.5.1
  ecto 2.1.6
  file_system 0.1.5
  gettext 0.13.1
  mime 1.1.0
  phoenix 1.3.0
  phoenix_ecto 3.2.3
  phoenix_html 2.10.4
  phoenix_live_reload 1.1.0
  phoenix_pubsub 1.0.2
  plug 1.4.3
  poison 3.1.0
  poolboy 1.5.1
  postgrex 0.13.3
  ranch 1.3.2
* Getting distillery (Hex package)
  Checking package (https://repo.hex.pm/tarballs/distillery-1.5.1.tar)
  Fetched package
==> distillery
Compiling 19 files (.ex)
Generated distillery app
==> blog
Compiling 17 files (.ex)
Generated blog app
```

を実行すると、mix.lock にも書き込まれます。

``` diff:mix.lock
@@ -3,6 +3,7 @@
   "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [], [], "hexpm"},
   "db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
   "decimal": {:hex, :decimal, "1.4.0", "fac965ce71a46aab53d3a6ce45662806bdd708a4a95a65cde8a12eb0124a1333", [], [], "hexpm"},
+  "distillery": {:hex, :distillery, "1.5.1", "7ad7354214959c0f65f57ddd49478c81c3b2733ca2e5ccfb9eb55351108466aa", [], [], "hexpm"},
   "ecto": {:hex, :ecto, "2.1.6", "29b45f393c2ecd99f83e418ea9b0a2af6078ecb30f401481abac8a473c490f84", [], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
   "file_system": {:hex, :file_system, "0.1.5", "4f20ec7d186cd84ad478bd5477061aeb993b36b5458872041bbabba8b09d36ff", [], [], "hexpm"},
   "gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [], [], "hexpm"},
```

一旦コミット。

## Distillery の初期化

```
$ mix release.init
```

というのでやるらしいです。やってみましょう。

```
$ mix release.init

An 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
```

`rel/config.exs` というファイルを作ったので、中身を確認して `mix release` しなさいよ、と言っていますね。

``` elixir:rel/config.exs
# Import all plugins from `rel/plugins`
# They can then be used by adding `plugin MyPlugin` to
# either an environment, or release definition, where
# `MyPlugin` is the name of the plugin module.
Path.join(["rel", "plugins", "*.exs"])
|> Path.wildcard()
|> Enum.map(&Code.eval_file(&1))

use Mix.Releases.Config,
    # This sets the default release built by `mix release`
    default_release: :default,
    # This sets the default environment used by `mix release`
    default_environment: Mix.env()

# For a full list of config options for both releases
# and environments, visit https://hexdocs.pm/distillery/configuration.html


# You may define one or more environments in this file,
# an environment's settings will override those of a release
# when building in that environment, this combination of release
# and environment configuration is called a profile

environment :dev do
  # If you are running Phoenix, you should make sure that
  # server: true is set and the code reloader is disabled,
  # even in dev mode.
  # It is recommended that you build with MIX_ENV=prod and pass
  # the --env flag to Distillery explicitly if you want to use
  # dev mode.
  set dev_mode: true
  set include_erts: false
  set cookie: :"&aDTF9&j0V;jKvIkZZnGy1t@~MGQcAjPKbDAnOQtpuXF$%bu0NvLbOJ.;<f69L;W"
end

environment :prod do
  set include_erts: true
  set include_src: false
  set cookie: :"6w@<XVk7z?(or5_.A).YbBxVxL,]tU={/v6xicVy~Zq;?l~BN){{auYM%aWx82[*"
end

# You may define one or more releases in this file.
# If you have not set a default release, or selected one
# when running `mix release`, the first release in the file
# will be used by default

release :blog do
  set version: current_version(:blog)
  set applications: [
    :runtime_tools
  ]
end


```

plugin、environment, release という概念があるみたいですね。

plugin が何をするのかはいまいちよくわかってませんが、それ以外については
詳細なコメントを書いてくれてるのでだいたいわかりますね。

`include_erts` というのが erts(Erlang RunTime System) を release の
中に含めるのかを設定する場所のようです。

```
  set applications: [
    :runtime_tools
  ]
```

の部分がいまいちよくわかりませんが、とりあえず先へ進みます。

今回は初期状態から何も書き換える箇所がありませんでした。

一旦コミット。

## prod.exs の設定

``` diff:config/prod.exs
@@ -15,8 +15,12 @@ use Mix.Config
 # which you typically run after static files are built.
 config :blog, BlogWeb.Endpoint,
   load_from_system_env: true,
-  url: [host: "example.com", port: 80],
-  cache_static_manifest: "priv/static/cache_manifest.json"
+  http: [port: {:system, "PORT"}],
+  url: [host: "localhost", port: {:system, "PORT"}],
+  cache_static_manifest: "priv/static/cache_manifest.json",
+  server: true,
+  root: ".",
+  version: Application.spec(:blog, :vsn)
```

`server: true` とすると、 ビルド結果を実行したときに
Cowboy （というWebサーバー？)が起動するみたいです。

あと、PORT 番号は PORT 環境変数から起動時に読み込むように設定しています。

## いよいよリリース用のビルド

まずは前回と今までと同じく assets のコンパイルです。
どうやら assets ディレクトリに cd しなくても
ディレクトリを指定して実行すると成功するようです。

```
$ brunch b -p assets/
13:43:02 - info: compiled 6 files into 2 files, copied 3 in 2.5 sec
```

そして digest。

```
$ MIX_ENV=prod mix phoenix.digest
==> distillery
Compiling 19 files (.ex)
Generated distillery app
mix phoenix.digest is deprecated. Use phx.digest instead.
==> blog
Check your digested files at "priv/static"
```

いよいよ、 Distillery の release タスクを実行してみます。

`mix help <task名>` で詳細なヘルプを見られるということに気づきました。

```
$ mix help release

                                  mix release

Build a release for the current mix application.

## Examples

    # Build a release using defaults
    mix release

    # Build an executable release
    mix release --executable

    # Build an executable release which will cleanup after itself after it runs
    mix release --executable --transient

    # Build an upgrade release
    mix release --upgrade

    # Build an upgrade release from a specific version
    mix release --upgrade --upfrom=0.1.0

    # Build a specific release
    mix release --name=myapp

    # Build a release for a specific environment
    mix release --env=staging

    # Build a specific profile
    mix release --profile=myapp:staging

    # Pass args to erlexec when running the release
    mix release --erl="-env TZ UTC"

    # Enable dev mode. Make changes, compile using MIX_ENV=prod
    # and execute your release again to pick up the changes
    mix release --dev

    # Mute logging output
    mix release --silent

    # Quiet logging output
    mix release --quiet

    # Verbose logging output
    mix release --verbose

    # Do not package release, just assemble it
    mix release --no-tar

    # Treat warnings as errors
    mix release --warnings-as-errors

    # Skip warnings about missing applications
    mix release --no-warn-missing

Location: _build/dev/lib/distillery/ebin
```

verbose というのがあるのでつけてみましょう。
あと、`MIX_ENV` と `--env` を両方指定しないといけない
理由がいまいちよくわかってません。


```
$ MIX_ENV=prod mix release --env=prod --verbose
==> Loading configuration..
==> Assembling release..
==> Building release blog:0.0.1 using environment prod
==> Discovered applications:
  poolboy-1.5.1
    from: _build/prod/lib/poolboy
    applications:
      :kernel
      :stdlib
    includes: none

  ecto-2.1.6
    from: _build/prod/lib/ecto
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :decimal
      :poolboy
    includes: none

  phoenix_ecto-3.2.3
    from: _build/prod/lib/phoenix_ecto
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :ecto
      :plug
    includes: none

  decimal-1.4.0
    from: _build/prod/lib/decimal
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  connection-1.0.4
    from: _build/prod/lib/connection
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  db_connection-1.1.2
    from: _build/prod/lib/db_connection
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :connection
    includes: none

  postgrex-0.13.3
    from: _build/prod/lib/postgrex
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :db_connection
      :decimal
      :crypto
    includes: none

  eex-1.5.1
    from: /usr/local/Cellar/elixir/1.5.1/bin/../lib/eex
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  poison-3.1.0
    from: _build/prod/lib/poison
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  phoenix-1.3.0
    from: _build/prod/lib/phoenix
    applications:
      :kernel
      :stdlib
      :elixir
      :plug
      :poison
      :logger
      :eex
      :phoenix_pubsub
      :crypto
    includes: none

  mime-1.1.0
    from: _build/prod/lib/mime
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  plug-1.4.3
    from: _build/prod/lib/plug
    applications:
      :kernel
      :stdlib
      :elixir
      :crypto
      :logger
      :mime
    includes: none

  phoenix_html-2.10.4
    from: _build/prod/lib/phoenix_html
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :plug
    includes: none

  cowlib-1.0.2
    from: _build/prod/lib/cowlib
    applications:
      :kernel
      :stdlib
      :crypto
    includes: none

  asn1-5.0
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/asn1-5.0
    applications:
      :kernel
      :stdlib
    includes: none

  public_key-1.4.1
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/public_key-1.4.1
    applications:
      :asn1
      :crypto
      :kernel
      :stdlib
    includes: none

  ssl-8.2
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/ssl-8.2
    applications:
      :crypto
      :public_key
      :kernel
      :stdlib
    includes: none

  ranch-1.3.2
    from: _build/prod/lib/ranch
    applications:
      :kernel
      :stdlib
      :ssl
    includes: none

  cowboy-1.1.2
    from: _build/prod/lib/cowboy
    applications:
      :kernel
      :stdlib
      :ranch
      :cowlib
      :crypto
    includes: none

  crypto-4.0
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/crypto-4.0
    applications:
      :kernel
      :stdlib
    includes: none

  phoenix_pubsub-1.0.2
    from: _build/prod/lib/phoenix_pubsub
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :crypto
    includes: none

  gettext-0.13.1
    from: _build/prod/lib/gettext
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
    includes: none

  runtime_tools-1.12
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/runtime_tools-1.12
    applications:
      :kernel
      :stdlib
    includes: none

  logger-1.5.1
    from: /usr/local/Cellar/elixir/1.5.1/bin/../lib/logger
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  compiler-7.1
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/compiler-7.1
    applications:
      :kernel
      :stdlib
    includes: none

  elixir-1.5.1
    from: /usr/local/Cellar/elixir/1.5.1/bin/../lib/elixir
    applications:
      :kernel
      :stdlib
      :compiler
    includes: none

  stdlib-3.4
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/stdlib-3.4
    applications:
      :kernel
    includes: none

  kernel-5.3
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/kernel-5.3
    applications: none
    includes: none

  blog-0.0.1
    from: _build/prod/lib/blog
    applications:
      :kernel
      :stdlib
      :elixir
      :logger
      :runtime_tools
      :gettext
      :phoenix_pubsub
      :cowboy
      :phoenix_html
      :phoenix
      :postgrex
      :phoenix_ecto
    includes: none

  iex-1.5.1
    from: /usr/local/Cellar/elixir/1.5.1/bin/../lib/iex
    applications:
      :kernel
      :stdlib
      :elixir
    includes: none

  sasl-3.0.4
    from: /usr/local/Cellar/erlang/20.0/lib/erlang/lib/sasl-3.0.4
    applications:
      :kernel
      :stdlib
    includes: none

==> Generated overlay vars:
    release_name=:blog
    release_version="0.0.1"
    is_upgrade=false
    upgrade_from=:latest
    dev_mode=false
    include_erts=true
    include_src=false
    include_system_libs=true
    erl_opts=""
    run_erl_env=""
    erts_vsn="9.0"
    output_dir="_build/prod/rel/blog"
==> Copying applications to _build/prod/rel/blog
==> Generating nodetool
==> Generating start_erl.data
==> Generating vm.args
==> Generating sys.config from config/config.exs
==> Including ERTS 9.0 from /usr/local/Cellar/erlang/20.0/lib/erlang/erts-9.0
==> Generating boot script
==> Generating RELEASES
==> Generating start_clean.boot
==> Applying overlays
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/pre_configure.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/post_configure.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/pre_start.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/post_start.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/pre_stop.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/post_stop.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/pre_upgrade.d
==> Applying mkdir overlay
    dst: releases/0.0.1/hooks/post_upgrade.d
==> Applying copy overlay
    src: _build/prod/lib/distillery/priv/libexec
    dst: releases/0.0.1/libexec
==> Applying mkdir overlay
    dst: releases/0.0.1/commands
==> Packaging release..
==> Archiving blog-0.0.1
==> Writing tarball to _build/prod/rel/blog/releases/0.0.1/blog.tar.gz
==> Updating tarball
==> Tarball updated!
==> Release successfully built!
    You can run it in one of the following ways:
      Interactive: _build/prod/rel/blog/bin/blog console
      Foreground: _build/prod/rel/blog/bin/blog foreground
      Daemon: _build/prod/rel/blog/bin/blog start

```

これで、

- 各種依存ライブラリ
- Erlang 20.0 の erts
- 各種ファイルやディレクトリ群

がアーカイブ用に準備され、

- `_build/prod/rel/blog/bin/blog` というコマンド
- `_build/prod/rel/blog/releases/0.0.1/blog.tar.gz` という release アーカイブ

が出来上がったことがわかります。

## ビルドされた結果を実行

```
$ _build/prod/rel/blog/bin/blog foreground
"$@" -- "${1+$ARGS}"
14:24:20.220 [info] Application blog exited: Blog.Application.start(:normal, []) returned an error: shutdown: failed to start child: BlogWeb.Endpoint
    ** (EXIT) an exception was raised:
        ** (RuntimeError) expected the PORT environment variable to be set
            (blog) lib/blog_web/endpoint.ex:51: BlogWeb.Endpoint.init/2
            (phoenix) lib/phoenix/endpoint/supervisor.ex:32: Phoenix.Endpoint.Supervisor.init/1
            (stdlib) supervisor.erl:294: :supervisor.init/1
            (stdlib) gen_server.erl:365: :gen_server.init_it/2
            (stdlib) gen_server.erl:333: :gen_server.init_it/6
            (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
{"Kernel pid terminated",application_controller,"{application_start_failure,blog,{{shutdown,{failed_to_start_child,'Elixir.BlogWeb.Endpoint',{#{'__exception_
_' => true,'__struct__' => 'Elixir.RuntimeError',message => <<\"expected the PORT environment variable to be set\">>},[{'Elixir.BlogWeb.Endpoint',init,2,[{fi
le,\"lib/blog_web/endpoint.ex\"},{line,51}]},{'Elixir.Phoenix.Endpoint.Supervisor',init,1,[{file,\"lib/phoenix/endpoint/supervisor.ex\"},{line,32}]},{supervi
sor,init,1,[{file,\"supervisor.erl\"},{line,294}]},{gen_server,init_it,2,[{file,\"gen_server.erl\"},{line,365}]},{gen_server,init_it,6,[{file,\"gen_server.er
l\"},{line,333}]},{proc_lib,init_p_do_apply,3,[{file,\"proc_lib.erl\"},{line,247}]}]}}},{'Elixir.Blog.Application',start,[normal,[]]}}}"}
Kernel pid terminated (application_controller) ({application_start_failure,blog,{{shutdown,{failed_to_start_child,'Elixir.BlogWeb.Endpoint',{#{'__exception__
' => true,'__struct__' => 'Elixir.RuntimeEr

Crash dump is being written to: erl_crash.dump...done
```

おっと、PORT 環境変数を指定し忘れてしまいました。


```
$ PORT=4000 _build/prod/rel/blog/bin/blog foreground
"$@" -- "${1+$ARGS}"
14:26:25.732 [info] Running BlogWeb.Endpoint with Cowboy using http://:::4000
14:26:32.936 request_id=6bplk7dihh1kvv3gl9oeef0h7jmgpd7p [info] GET /
14:26:32.938 request_id=6bplk7dihh1kvv3gl9oeef0h7jmgpd7p [info] Sent 200 in 2ms
14:26:35.926 request_id=6gqno4k0l558blc1pkdrvsma4uffupht [info] GET /articles
14:26:35.928 request_id=6gqno4k0l558blc1pkdrvsma4uffupht [info] Sent 200 in 2ms
14:26:37.459 request_id=r6h0vqfgdpl3t01tljhdtopc729vspjm [info] GET /articles/new
14:26:37.459 request_id=r6h0vqfgdpl3t01tljhdtopc729vspjm [info] Sent 200 in 476µs
```

`"$@" -- "${1+$ARGS}"` というよくわからないログが気になりますが...

一応問題なく起動して、ブラウザからもアクセスできました。


## その他のサブコマンド

何もタスク名を指定せずに実行するとヘルプが出ました。

```
$ _build/dev/rel/blog/bin/blog
Usage: blog <task>

Service Control
=======================
start                          # start blog as a daemon
start_boot <file>              # start blog as a daemon, but supply a custom .boot file
foreground                     # start blog in the foreground
console                        # start blog with a console attached
console_clean                  # start a console with code paths set but no apps loaded/started
console_boot <file>            # start blog with a console attached, but supply a custom .boot file
stop                           # stop the blog daemon
restart                        # restart the blog daemon without shutting down the VM
reboot                         # restart the blog daemon
reload_config                  # reload the current system's configuration from disk

Upgrades
=======================
upgrade <version>              # upgrade blog to <version>
downgrade <version>            # downgrade blog to <version>
install <version>              # install the blog-<version> release, but do not upgrade to it

Utilities
=======================
attach                         # attach the current TTY to blog's console
remote_console                 # remote shell to blog's console
pid                            # get the pid of the running blog instance
ping                           # checks if blog is running, pong is returned if successful
pingpeer <peer>                # check if a peer node is running, pong is returned if successful
escript <file>                 # execute an escript
rpc <mod> <fun> [<args..>]     # execute an RPC call using the given MFA
rpcterms <mod> <fun> [<expr>]  # execute an RPC call using the given Erlang expression for args
eval <expr>                    # execute the given Erlang expression on the running node
command <mod> <fun> [<args..>] # execute the given MFA
describe                       # print useful information about the blog release


Custom Commands
=======================
No custom commands found.
```

ほとんどがシェルスクリプト経由で実行されているらしく、
山のようにシェルスクリプトがありました。

```
$ find _build -name '*.sh'
_build/prod/rel/blog/bin/blog_loader.sh
_build/prod/rel/blog/releases/0.0.1/blog.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/attach.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/command.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/console.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/describe.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/escript.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/eval.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/foreground.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/help.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/install.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/pid.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/ping.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/pingpeer.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/reboot.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/reload_config.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/remote_console.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/restart.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/rpc.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/rpcterms.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/start.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/stop.sh
_build/prod/rel/blog/releases/0.0.1/libexec/commands/unpack.sh
_build/prod/rel/blog/releases/0.0.1/libexec/config.sh
_build/prod/rel/blog/releases/0.0.1/libexec/env.sh
_build/prod/rel/blog/releases/0.0.1/libexec/erts.sh
_build/prod/rel/blog/releases/0.0.1/libexec/helpers.sh
_build/prod/rel/blog/releases/0.0.1/libexec/logger.sh
```

## 試しに Linux に持っていって動かしてみる

Linux 用の erts の設定などを全くしてないので、絶対に動かないと思いますが、
Linux に持っていって、動かないことを確認してみましょう。

ちなみにアーカイブのサイズは

```
$ du -sh blog.tar.gz
 15M    blog.tar.gz
```

でした。

```
$ scp blog.tar.gz linux:
$ ssh linux
linux:~$ mkdir blog
linux:~$ mv blog.tar.gz blog
linux:~$ cd blog/
linux:~$ tar xfvz blog.tar.gz
(略)
linux:~$ ls
bin  blog.tar.gz  erts-9.0  lib  releases
linux:~$ bin/blog
/home/tmaeda/blog/erts-9.0/bin/erlexec: 1: /home/tmaeda/blog/erts-9.0/bin/erlexec: Syntax error: "(" unexpected
```

あー、出ました！やっぱり動かないですね。

個人的にはクロスコンパイルみたいなやつは他に良い手段がないときに
最終手段として仕方なくやるものだと思っているので、今回はここは深追いしません。

Circle CIでビルドして、 ~~edeliver で~~本番Linuxサーバー上にデプロイというのが
今見えている最も実践的なデプロイ方法なんじゃないかと思っています。

（追記) edeliver も調べてみましたが、どうもいまいちでした。自作shスクリプトか、capistranoかansibleかなぁ...
##### edeliverのツライところ
- 巨大なbashスクリプトである。bashスクリプトの割には非常にがんばってると思うけど、bashスクリプトでこんなに大きなもの作っちゃいけないと思う。エラー処理とか、カスタマイズとかデバッグとか大変でしょ。
- 起動時に外から環境変数を渡す仕組みがない？ PORT=4000 みたいなやつ。


## まとめ

- Distillery でのビルドと起動が公式ドキュメントに従って問題なくできました。
- Distillery を利用することで、非常に多くのサブコマンドが生成されることがわかりました。
- Mac で(特に設定せずに)作ったアーカイブを Linux に持っていっても起動できないことが確認できました。(Mac上に Linux 用の erts を置いておいて、`rel/config.exs` にパスを指定してあげると Linux 用の erts が同梱されて、Linux 上で動くようになるらしいですけど、そもそもこれは筋悪だと思っているので、深追いはしません)
- Hot upgrade などが Distillery の醍醐味なんだと思いますが、それはまたの機会に。