DEV Community

gumi TECH for gumi TECH Blog

Posted on

Elixir: アプリケーションをパッケージ化する

本稿は「Elixir アプリケーションをパッケージ化しよう」をもとに加筆・補正し、文章を整えました。

Elixirアプリケーションを本番サーバーで動かすときにはパッケージ化するとよいでしょう。パッケージ化の利点やその方法、注意すべき点などについてご説明します。

パッケージ化とは

Elixirのパッケージ化とは、つぎのようなファイルを集めて、ほぼ単体で起動するようにひとつのディレクトリにまとめることです。そのためのツールとしては、今はDistillery一択でしょう。

  • 依存しているアプリケーションやライブラリのbeamファイル
  • 設定ファイル
  • Elixir本体のbeamファイル
  • ERTSとよばれるErlangランタイム
  • アプリケーションを起動するためのスクリプト

パッケージ化の利点

パッケージ化する利点は、そのサーバーにErlangとElixirを入れる必要がなくなる、ということに尽きます。

  • ErlangやElixirを入れる必要がないので、サーバーを構築するためのAnsibleやAMIをつくる作業が楽になります。
  • サーバー内のErlangやElixirのバージョンを更新しなくてよいので、インフラ担当との調整が要りません。
  • デプロイするためにgitからソースをもってきて起動といったことをせずに済み、zipファイル1個転送すれば動かせます。
  • 仕組みがとても単純になるので、デプロイシステム全体を理解する手間が減ります。

ErlangとElixirが要りませんので、ほぼ何も入っていないAlpineLinuxですら、必要なパッケージはmuslncurses-libszlibbashだけになります1。これらのパッケージを入れておけば、パッケージ化したElixirアプリケーションはそのサーバーで動作します。

パッケージ化する方法

基本的にはDistilleryのドキュメント「Getting Started」にしたがって進めれば問題ありません。

重要なのは、その環境に入っているOSやErlangやElixirのバージョンでパッケージがつくられるということです。そのため、本番と同じOSの上でパッケージ化する必要があります。

そのためにビルド用のサーバーをつくり、そこでパッケージ化するという手もあります。けれど、Dockerでビルドするとお手軽です。パッケージをビルドするためのイメージと、それを使ってパッケージ化するスクリプトを書いておけば、誰でも簡単にローカルでパッケージがつくれるようになるのが利点です2

パッケージ化するときの注意点

Distilleryでパッケージ化すると、MixExUnitというライブラリが入りません。そのため、実行時にMixExUnitを使うと、それらのモジュールがないことによるエラーが起こります3

たとえば、つぎのコードはmix runでは正しく動きますが、パッケージ化して起動するとエラーになります。

defmodule Foo do
  def f() do
    # テスト時は :foo を返す
    if Mix.env() == :test do
      :foo
    else
      :bar
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

これは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
Enter fullscreen mode Exit fullscreen mode

こうすれば、コンパイル時にMix.env/0が評価され、どちらかの関数だけが残ります。実行時にはMix.env/0が使われないのでエラーは起こりません。パッケージ化しするに時々忘れがちですので、気をつけましょう。

また、パッケージ化するとmix yacto.migrateのようなMixのコマンドは打てません。そのため、本番データベースのマイグレーションをどうやるかが問題になります。これは「Running migrations」にあるように、Mixは使わずにマイグレーションが実行できるスクリプトをつくり、それをパッケージ化したバイナリ経由で呼び出すのがよいでしょう。

このように少し手間はかかるものの、その後のデプロイやサーバー管理が手軽にできるようになります。Elixirアプリケーションはパッケージ化することがお勧めです。


  1. bashはDistilleryが要求します。それ以外は、ErlangVMを動かすために必要です。ただし、ビルドフラグによっても変わります(たとえば--disable-dynamic-ssl-libを指定しなかった場合、OpenSSLなどのライブラリが必要になるでしょう)。 

  2. gimiではprod.secret.exsは用いず、環境変数(envパッケージ)を使っているので、シークレットなデータを知らないためにパッケージ化できないといったことは起こりません。 

  3. これで問題が出たときも、ローカルでパッケージ化できるようにしてあると比較的簡単にデバッグできます。 

Top comments (0)