【翻訳】「Releases - Rebar3」

# 翻訳元
- [Releases - Rebar3](https://www.rebar3.org/docs/releases)

以下本文

---

# リリース

リリースは、ビルドと実行が苦痛だったらダメ。私達は苦痛にならないようにベストを尽くした。必要なピースは全てそこに揃っている。

<br/>

---
:information_source: **リリースとターゲットシステムって何？**
リリースは Erlang VM を起動してプロジェクトを開始するために必要なアプリケーションのセット。これはリリースリソースファイル（ `.rel` ）で記述される。リリースリソースファイルは `.script` や `.boot` ファイルを作る。 boot ファイルはスクリプトファイルのバイナリ形式で Erlang Run Time System (ERTS) によって Erlang ノードを起動するために使われる。これはオペレーティングシステムを起動するようなもの。コマンドラインで `erl` を実行しても、 boot script は使われる。

ターゲットシステムは別のマシン（仮想またはそれ以外）で起動することができる Erlang システムで、よく ERTS もターゲットシステムと一緒にまとめられる。

詳細については『すごい Erlang ゆかいに学ぼう!』のリリースに関する章を参照。（『すごい Erlang ゆかいに学ぼう!』のリリースに関するドキュメントは reltool に依存している。）（『すごい Erlang ゆかいに学ぼう!』の本じゃなくて[コッチ](https://www.ymotongpoo.com/works/lyse-ja/ja/24_release_is_the_word.html)参照でも可。）

---

<br/>

---
:warning: **No Reltool**

rebar3 では reltool じゃなくて relx を使っている。 reltool はまだ Erlang/OTP に入っているので、自分で設定すれば使い続けることはできる。

---

# 入門

プロジェクトの `rebar.config` に `relx` セクションを追加する。

```erlang:Erlang
{relx, [{release, {<release name>, "0.0.1"},
         [<app>]},

        {dev_mode, true},
        {include_erts, false},

        {extended_start_script, true}]}.
```

`rebar3 release` を実行するとリリースをビルドし、 `_build/<profile>/rel/<release name>/bin/<release name>` 以下にノードを起動するスクリプトができる。

プロジェクトの `rebar.config` の `relx` セクションの下に `release` セクションは複数入れられる。
同じ設定を共有することなるリリース物を指定することができる。

```erlang:Erlang
{relx, [{release, {<release name>, "0.0.1"},
         [<app>]},
        {release, {<release name>, "0.1.0"},
         [<app>]},

        {dev_mode, true},
        {include_erts, false},

        {extended_start_script, true}]}.
```

または、独立した設定のリリースを指定することもできる。

```erlang:Erlang
{relx, [{release, {<release name>, "0.0.1"},
         [<app>],
         [{dev_mode, false},
          {include_erts, true}]},
        {release, {<release name>, "0.1.0"},
         [<app>],
         [{dev_mode, true}]}
       ]}.
```

`rebar3 release -n <release_name>` で特定のリリース物をビルドすることができる。

# 開発

開発中にアプリケーションへの全ての変更をすぐにリリース物で利用可能にしたい時がある。 `relx` にはそのために `dev_mode` というものがある。リリースするアプリケーションをリリース構成にコピーせずにシンボリックリンクを作成するので、 (TODO: 訳 Instead of copying the applications that make up the release to the release structure it creates symlinks, so compiling and restarting or loading the changed modules, is all that is necessary. )

リリースを構成するアプリケーションをリリース構造にコピーする代わりに、シンボリックリンクを作成するので、変更されたモジュールのコンパイルと再起動、またはロードがすべて必要です。

# 設定

## VM の設定

デフォルトでは `relx` はノード名と cookie を設定する基本的な `vm.args` ファイルが与えられる。オプションとその使用法の一覧は [Erlang のドキュメント](http://erlang.org/doc/man/erl.html)を見てね。

```erlang:Erlang
## Name of the node
-name {{release_name}}@127.0.0.1

## Cookie for distributed erlang
-setcookie {{release_name}}
```

カスタムした `vm.args` を使うには、通常プロジェクトのルートにある `config/` ディレクトリの中に置くか、 `rebar.config` の ‘レlx‘ セクションに次の行を追記する。

```erlang:Erlang
{vm_args, "config/vm.args"}
```

## アプリケーション設定

アプリケーション環境変数を渡すために `sys.config` がある。

```erlang:Erlang
[
  {<app_name>, [...]}
].
```

デフォルトの `sys.config` は何も設定されていないので、自分で作ったものを単に `rebar.config` の `relx` セクションに追加するだけで良い。

```erlang:Erlang
{sys_config, "config/sys.config"}
```

## 動的設定

`RELX_REPLACE_OS_VARS=true` を設定することによって `vm.args` と `sys.config` の両方のファイルがノードが起動している環境から現在の値に置き換えられ OS の環境変数に含めることができる。(XXX: 何を言っているのか意味不明) これはリリースのための `vm.args` と `sys.config` が次のようにポート上で listen 状態の WEB サーバを起動することを意味する。(XXX: 何を言っているのか意味不明)

```erlang:vm.args
-name ${NODE_NAME}
```

```erlang:sys.config
[
 {appname, [{port, "${PORT}"}]}
].
```

そして異なる名前の同じリリースの複数のノードを起動するために利用される。

```erlang:Shell
#!/bin/bash

export RELX_REPLACE_OS_VARS=true

for i in `seq 1 10`;
do
    NODE_NAME=node_$i PORT=808$i _build/default/rel/<release>/bin/<release> foreground &
    sleep 1
done  
```

---
:information_source: **sys.config の変数形式**

Erlang のリリース処理すステムの制限のため、 `sys.config` 内の環境変数は文字列でなければならないことに注意する。（例えば、 `${PORT}` ではなく `"${PORT}"` じゃないとダメ。）これは設定が rebar3 や relx ではない OTP のツールによって参照され、引用符で囲まれていない形式だと Erlang のファイル解析が中断してしまうため。

この値は動的なものであるため、使わないで前もってフィルタリングすることはできない。

変数が文字列以外（ atom や integer 等）の型でなければ_ならない_場合は、同じ制限はないので、 `vm.args` に `-<appname> http_port ${PORT}` を追加して設定を検討する。

---

---
:warning: **サポートされていない sys.config の機能**

もし、 `dev_mode` が `true` でオリジナルのコピーを上書きをしないように、この機能を使うには `sys.config` を異なるファイル名にコピーする必要がある。 Erlang は `sys.config` と名付けられたファイルに依存するため、もし `sys.config` 設定値の一覧に読み込みたい追加の設定ファイルの名前を含みたいなら、リリース物が起動に失敗する原因となる。

つまり、この機能を使いたいなら、 [OTP ドキュメント](http://erlang.org/doc/man/config.html)から次の例の文字列のようなファイル名を `sys.config` に**含まないように**しなければならない。

```erlang
[{myapp,[{par1,val1},{par2,val2}]},
 "/home/user/myconfig"].
```

---

# オーバーレイ

オーバーレイはターゲットシステムに含まれる定義ファイルとテンプレートの機能について示す。例えば、ノードや Procfile を管理のためのカスタムスクリプトは Heroku 上で実行するために必要。

```erlang:Erlang
{relx, [
    ...
    {overlay_vars, "vars.config"},
    {overlay, [{mkdir, "log/sasl"},
               {template, "priv/app.config", "etc/app.config"},
               {copy, "Procfile", "Procfile"}]}
]}.
```

relx は Mustache テンプレートシステムの全力で変数を展開している（ [mustache](https://github.com/soranoba/mustache) 参照）。全てのシンタックスのサポートのためにドキュメントは確認すべき。サポートされる変数を下に挙げる。

## 分割設定

より複雑な状況に対応するためにオーバーレイファイルを分割することができる。これを説明するには簡単な例を挙げる。

私達はアプリケーションをビルドし、プロダクトと開発のビルドで区別したい、オーバーレイ変数の `build` を `"prod"` か `"dev"` にすることによって。だから app.config ファイルはその設定でそれを含んで有効か無効にすることができる。(XXX: 日本語おかしい)

このために、3つのオーバーレイファイルを作る。

- `dev.config` - dev ブランチ用
- `prod.config` - prod ブランチ用
- `base.config` - ブランチ共有

dev ビルドでは `overlay_vars` として `dev.config` を使い、 prod ビルドでは `prod.config` を使う。

```erlang:base.config
{data_dir, "/data/yolo_app"}.
{version, "1.0.0"}.
{run_user, "root"}.
```

```erlang:dev.config
%% Include the base config
"./base.config".
%% The build we have
{build, "dev"}.
```

```erlang:prod.config
%% Include the base config
"./base.config".
%% The build we have
{build, "prod"}.
```

## 定義済みの変数
- _log_ : 現在のログレベルを次の形式で保持 `(<logname>:<loglevel>)`
- _output_dir_ : ビルドされたリリースの現在の出力ディレクトリ
- _target_dir_ : `output_dir` と同じ。下位互換性のためにある
- _overridden_ : オーバーライドされたアプリの現在のリスト（アプリ名のリスト）
- _goals_ : システム内のユーザー指定の目標のリスト
- _lib_dirs_ : ライブラリディレクトリのリスト、ユーザの指定したものとその中で使われているものの両方
- _config_file_ : システムで使用される設定ファイルのリスト
- _providers_ : この relx の実行に使用されるプロバイダ名のリスト
- _sys_config_ : sys config ファイルの場所
- _root_dir_ : 現在のプロジェクトのルートディレクトリ
- _default_release_name_ : relx を走らせた時の現在のデフォルトのリリース名
- _default_release_version_ : relx を走らせた時の現在のデフォルトのリリースバージョン
- _default_release_ : relx を実行した時の現在のデフォルトのリリース
- _release_erts_version_ : 使用中の ErlangRuntime System のバージョン
- _erts_vsn_ : `release_erts_version` と同じ（下位互換性のため）
- _release_name_ : 現在実行中のリリース
- _release_version_ : 現在実行中のバージョン
- _rel_vsn_ : `release_version` と同じ。後方互換性のためにある
- _release_applications_ : リリースに含まれるアプリケーションのリスト

# デプロイ可能

他のノードにコピーできるリリースをビルドするには、 `dev_mode` を切る必要があり、そのため、アプリケーションはシンボリックリンクではなくリリース `lib` ディレクトリにコピーされる。

```shell-session:shell
$ rebar3 release -d false
```

または、 `dev_mode` を切る profile を作る。

```erlang:Erlang
{profiles, [{prod, [{relx, [{dev_mode, false}]}]}]}.
```

## ターゲットシステム

ターゲットシステムは、 `dev_mode` 使用時に作成されるようなシンボリックリンクを持つことはできず、 ERTS をシステムに含めることが多いため、ターゲットにあらかじめインストールする必要はない。

```erlang:Erlang
{profiles, [{prod, [{relx, [{dev_mode, false}
                           ,{include_erts, true}]}]}]}.
```

今度は、ターゲットにコピーする圧縮されたアーカイブをビルドすることもできる。

```shell-session:shell
$ rebar3 as prod tar
===> Verifying default dependencies...
===> Compiling myrel
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          .../myrel/apps
          /usr/lib/erlang/lib
===> Resolved myrel-0.1.0
===> Including Erts from /usr/lib/erlang
===> release successfully created!
===> tarball .../myrel/_build/rel/myrel/myrel-0.1.0.tar.gz successfully created!
```

これで、 tarball `myrel-0.1.0.tar.gz` を別の互換システムにコピーして起動することができる。

```shell-session:shell
$ mkdir myrel
$ mv myrel-0.1.0.tar.gz myrel/
$ cd myrel
$ tar -zxvf myrel-0.1.0.tar.gz
$ bin/myrel console
```

# Ertsなし
ターゲット上で ERTS と `kernel` や `stdlib` のようなベースアプリケーションを使うためには、 `relx` 設定タプルの中で  `include_erts` と `system_libs` を `false` に設定する

```erlang:Erlang
{include_erts, false},
{system_libs, false},
...
```

# リリースでのソースコードを含ませる
デフォルトでは、リリースにはアプリケーションのソースファイルが含まれている（存在する場合）。
ソースファイルをインクルードしない場合は、 `include_src` を false にする。

```erlang:Erlang
{include_src, false}
```

# アプリケーションの除外
以下の指定で、特定のアプリケーションを出力リリースから削除することができる。

```erlang:Erlang
{exclude_apps, [app1, app2]}
```

# モジュールの除外
次の指定をすると、出力リリースからアプリケーションモジュールを削除できます。

```erlang:Erlang
{exclude_modules, [
    {app1, [app1_mod1, app1_mod2]},
    {app2, [app2_mod1, app2_mod2]}
]}.
```

# クロスコンパイル
`rebar3` の実行に使用しているバージョンではない Erlang Runtime System を組み込みたい場合、たとえば MacOSX 上に構築していて、 GNU / Linux バージョン用に構築された ERTS を含めたい場合は、 `relx` 設定タプルに `include_erts` に boolean の代わりに単純にパスを指定することができ、 `system_libs` にパスを指定する。

```erlang:Erlang
{include_erts, "/path/to/erlang"},
{system_libs, "/path/to/erlang"},
...
```

プロファイルでこれらのパスを使用すると、クロスコンパイルを簡単にセットアップできる。

# ブート、アップグレード、および検査
`relx` に備わっていて rebar3's のリリーステンプレートによって使われるようになっている拡張 start スクリプト（ `{extended_start_script, true}` ）はリリースを起動して接続するためのいくつかの方法を提供している。

ローカルでの開発のために `console` を使う。作っている時は `start` するかフォアグラウンドで実行したい。

`start` は `attach` コマンドで後で接続できるパイプを作る。 Erlang VM はこのモードではすべての出力行で `fsync` を呼び、そのため、 `foreground` があなたのユースケースの方が良いかもしれない。

`foreground` で開始されたノードでコンソールを開くために `remote_console` を使う。

## アップグレードとダウングレード
バージョンの更新や appup 生成チェックアウトを含む細かいワークフローのためにリチャード・ジョンズの [`relflow`](https://github.com/RJ/relflow) ツールが `rebar3` に組み込まれている。

リリースのインストール後の基本的なリリースのアップグレードでは、 `myrel` という名前のリリースが `v0.0.1` と `0.0.2` というバージョンであると仮定する。

- リリースアップグレードを生成する `rebar3 relup`
- インストール : 実行中のシステムにリリースをインストールすると、そのバージョンが展開されアップグレードされる : `bin/myrel install 0.0.1`
- アップグレード : バージョンが既に解凍されている場合は、単に `upgrade` を呼べばバージョンをアップグレードできる : `bin/myrel upgrade 0.0.2`
- ダウングレード：以前のバージョンにダウングレードするには、次の `downgrade` コマンドを使う : `bin/myrel downgrade 0.0.1`

# 参考文献
- [relx](http://github.com/erlware/relx)
- [relflow](http://github.com/RJ/relflow)
- Learn you some Erlang for great good! の [Releases](https://www.ymotongpoo.com/works/lyse-ja/ja/24_release_is_the_word.html) の章（ [すごい Erlang ゆかいに学ぼう!](https://estore.ohmsha.co.jp/titles/978427406912P) の「第21章 これぞリリース」の方がオススメ）
- OTP [リリース](http://www.erlang.org/doc/design_principles/release_structure.html)のドキュメント
- OTP [ターゲットシステム](http://www.erlang.org/doc/system_principles/create_target.html) のドキュメント