本稿は「Elixir アプリケーションをパッケージ化しよう」をもとに加筆・補正し、文章を整えました。
Elixirアプリケーションを本番サーバーで動かすときにはパッケージ化するとよいでしょう。パッケージ化の利点やその方法、注意すべき点などについてご説明します。
パッケージ化とは
Elixirのパッケージ化とは、つぎのようなファイルを集めて、ほぼ単体で起動するようにひとつのディレクトリにまとめることです。そのためのツールとしては、今はDistillery一択でしょう。
- 依存しているアプリケーションやライブラリのbeamファイル
- 設定ファイル
- Elixir本体のbeamファイル
- ERTSとよばれるErlangランタイム
- アプリケーションを起動するためのスクリプト
パッケージ化の利点
パッケージ化する利点は、そのサーバーにErlangとElixirを入れる必要がなくなる、ということに尽きます。
- ErlangやElixirを入れる必要がないので、サーバーを構築するためのAnsibleやAMIをつくる作業が楽になります。
- サーバー内のErlangやElixirのバージョンを更新しなくてよいので、インフラ担当との調整が要りません。
- デプロイするためにgitからソースをもってきて起動といったことをせずに済み、zipファイル1個転送すれば動かせます。
- 仕組みがとても単純になるので、デプロイシステム全体を理解する手間が減ります。
ErlangとElixirが要りませんので、ほぼ何も入っていないAlpineLinuxですら、必要なパッケージはmuslとncurses-libs、zlib、bashだけになります1。これらのパッケージを入れておけば、パッケージ化したElixirアプリケーションはそのサーバーで動作します。
パッケージ化する方法
基本的にはDistilleryのドキュメント「Getting Started」にしたがって進めれば問題ありません。
重要なのは、その環境に入っているOSやErlangやElixirのバージョンでパッケージがつくられるということです。そのため、本番と同じOSの上でパッケージ化する必要があります。
そのためにビルド用のサーバーをつくり、そこでパッケージ化するという手もあります。けれど、Dockerでビルドするとお手軽です。パッケージをビルドするためのイメージと、それを使ってパッケージ化するスクリプトを書いておけば、誰でも簡単にローカルでパッケージがつくれるようになるのが利点です2。
パッケージ化するときの注意点
Distilleryでパッケージ化すると、MixやExUnitというライブラリが入りません。そのため、実行時にMixやExUnitを使うと、それらのモジュールがないことによるエラーが起こります3。
たとえば、つぎのコードはmix runでは正しく動きますが、パッケージ化して起動するとエラーになります。
defmodule Foo do
def f() do
# テスト時は :foo を返す
if Mix.env() == :test do
:foo
else
:bar
end
end
end
これはMix.env/0を実行時に使っているからです。コンパイル時にはMix.env/0が使えるので、以下のように改めればよいでしょう。
defmodule Foo do
# def f() do
# テスト時は :foo を返す
if Mix.env() == :test do
def f() do
:foo
end
else
def f() do
:bar
end
end
end
こうすれば、コンパイル時にMix.env/0が評価され、どちらかの関数だけが残ります。実行時にはMix.env/0が使われないのでエラーは起こりません。パッケージ化しするに時々忘れがちですので、気をつけましょう。
また、パッケージ化するとmix yacto.migrateのようなMixのコマンドは打てません。そのため、本番データベースのマイグレーションをどうやるかが問題になります。これは「Running migrations」にあるように、Mixは使わずにマイグレーションが実行できるスクリプトをつくり、それをパッケージ化したバイナリ経由で呼び出すのがよいでしょう。
このように少し手間はかかるものの、その後のデプロイやサーバー管理が手軽にできるようになります。Elixirアプリケーションはパッケージ化することがお勧めです。
Top comments (0)