Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Erlang/OTP パッケージングコトハジメ

Erlang/OTP パッケージングコトハジメ

更新:2014-05-29
バージョン:0.2.0
作者:@voluntas
URL:http://voluntas.github.io/

rebar generate と node_package についてまとめました。

前提

Erlang/OTP:17.0
OS:Mac OS X 10.9.3
rebar:rebar 2.3.1 17 20140524_080240 git 2.3.1-5-g755c602-dirty

Erlang/OTP コンパイルオプション:

./configure --prefix=/opt/erlang/17.0 \
            --enable-smp-support \
            --enable-threads \
            --enable-darwin-64bit \
            --enable-vm-probes \
            --enable-kernel-poll \
            --enable-hipe \
            --with-dynamic-trace=dtrace \
            --without-javac \
            --enable-dirty-schedulers \
            --disable-native-libs \
            --disable-sctp

詳細については Erlang/OTP 17.0 コンパイルオプションについて を参照する事をお勧めする。

TODO

  • Ubuntu 14.04 でのサンプル
  • eunit_formatters や reloader などを有効にしていた場合に package に含めない方法

概要

reltool を頑張っていた時代から rebar generate の時代が来て、そして node_package の時代へ

Erlang のパッケージングは基本的に Erlang/OTP ランタイム自身も含んでパッケージングする手段が基本だ。

そのため、Erlang/OTP がインストールされている環境を用意する必要は特にない。

ここでは Erlagn/OTP で開発されたシステムをパッケージングする方法を提供する。

注意

Erlang/VM は OS 事にビルドをするという一般の手法が使われる。残念ながらクロスビルドは無い。

さらに、Erlang/OTP のコンパイル設定もそのまま引き継がれるため、SCTP 等ライブラリが必要なものを有効にしていた場合は 起動しない 、または 使用時にエラーがでる といった影響がある。

その辺りに注意して使用する必要がある。

手段

パッケージングの手段は基本的に reltool を使った方法しかない。

ただ reltool だけだと色々つらいので、 rebar のサポートを使う。 さらに node_package という basho が公開しているツールを使うことで rpm や deb ファイルを簡単に作る事ができるようになる。

最初に rebar を使ったパッケージング方法を学んだ後、 rpm などのパッケージングが作りたいのであれば node_package を覚えればいい。

rebar

パッケージングの基本である rebar generate の機能を紹介したい。

rebar generate は Erlang/OTP に最初から入っている reltool の機能をわかりやすくラッピングし、誰もが簡単に使えるようなコマンドに落とし込んで提供してくれている。

さらに reltool にはないテンプレートの機能を使うことで様々なパッケージングに対応することが出来る。

overlay_vars

rebar の generate で重要な機能の一つに overlay 機能がある。

overlay 機能は app.config や sys.config 等に対して template 的な役割が出来る。

overlay_vas の値で上書きしたい部分を "{{spam}}" の用にしておくと rebar generate overlay_vars=vars.config で rel/vars.config で値を指定しておくことが出来る。

rel/vars.config の例

{spam, "egg"}.

これを使う事で app.config の設定を上書きすることが出来る用になる。

ファイルを overlay_vars 対象とする場合は reltool.config の overlay 部分で template を定義する必要がある。

例えば app.config 、デフォルトは copy にすることが多いが template に変更することで、overlay_vars にて上書きすることが可能になる。

あとは rebar generate overlay_vars=vars.config とし、rel 以下にアプリ名でフォルダが出来る。そのフォルダを tar.gz で固めれば良い。

target_dir

もしフォルダの場所などを変更したい場合は target_dir を使う事が出来る。

$ rebar generate target_dir=...

target_dir を使う事で指定したフォルダにパッケージされたデータをまとめてくれる。

開発用や本番用などで target_dir を分けると良いだろう。

サンプル

app.config の値を vars.config にて上書きする例

reltool.config:

{overlay, [{template, "files/app.config"}, "etc/app.config"}]}.

vars.config:

{lager_async_threhold, 20}.

app.config

{lager, [
         {colored, true},
         {error_logger_hwm, 3000},
         {async_threshold, {{lager_async_threhold}}},
         {handlers, [
           {lager_console_backend, info},
           {lager_file_backend, [{file, "log/info.log"}, {level, info}, {date, "$D0"}, {count, 7}]},
           {lager_file_backend, [{file, "log/warning.log"}, {level, warning}, {date, "$D0"}]},
           {lager_file_backend, [{file, "log/error.log"}, {level, error}, {date, "$D0"}]}
           ]}
        ]},

コマンドの実行

$ rebar generate overlay_vars=var.config target_dir=/tmp

生成されたフォルダをそのままデプロイすれば良い。

node_package

https://github.com/basho/node_package

node_packege は basho が開発した rpm や deb さらには dmg を生成してくれる仕組みである。

このライブラリを使う事で rpm などのパッケージを簡単に作れるようになる。

これ自体は rebar と reltool を使っている。

ただし、ほぼドキュメントが無い事もあり、かなり使いこなすのにはコストがかかる。 上手く付けばかなり便利なため、以下にサンプルを示す。

注意点

このパッケージ手法は Git とかなり密接に連携しているため、Git 側の動作にも影響する。

以下に例を用意した、これをベースに解説していく

voluntas/pkgex

準備

まず、rebar の create-app や create-node は終わった状態である前提とする。

rebar.config の deps

rebar.config の deps に node_package を追加する。ここでは最新版を使用している。

https://github.com/voluntas/pkgex/blob/develop/rebar.config#L25

{deps, [
        {node_package,
         ".*", {git, "git@github.com:basho/node_package.git", {branch, "develop"}}},
        {lager,
         ".*", {git, "git@github.com:basho/lager.git", {branch, "master"}}}
       ]}.

Makefile

Makefile は node_package 専用の Makefile を使用する。

Makefile 自体は以下を参照する事。

https://github.com/voluntas/pkgex/blob/develop/Makefile

パッケージング関連の設定は以下を参照する事。

https://github.com/voluntas/pkgex/blob/develop/Makefile#L54

pkg.vars.config

pkg 自体の情報を設定する pkg.vars.config を用意する必要がある。

https://github.com/voluntas/pkgex/blob/develop/pkg.vars.config

pkg.vars.config に使える項目は node_package のドキュメントに書いてある

https://github.com/basho/node_package#required-variables-1

必須は全て記載し、オプションは基本的に記載する必要は無い。

この値が RPM や DEB ファイルなどのパッケージング情報として使われる。

var.config

reltool.config や他の files 以下のテンプレート用の設定をする vars.config を用意する必要がある。

https://github.com/voluntas/pkgex/blob/develop/rel/vars.config

デフォルトでは ulimit を 4096 以上に設定するしないとワーニングが出るため、あえて runner_ulimit_warn を 256 に設定してる

rebar.config の sub_dirs

rebar.config で注意する必要があるのは sub_dirs の rel を対象にする必要がある。

https://github.com/voluntas/pkgex/blob/develop/rebar.config#L3

reltool.config

OS 事の vars.config を上書きするために overlay_vars を指定する必要がある。

https://github.com/voluntas/pkgex/blob/develop/rel/reltool.config#L33

reltool.config では erl や nodetool を node_package と置き換える必要がある。

https://github.com/voluntas/pkgex/blob/develop/rel/reltool.config#L36

またバージョン自体を明確にしておくとよい。

https://github.com/voluntas/pkgex/blob/develop/rel/reltool.config#L7

vm.args

vm.args の node 名部分を {{node}} に変更する必要がある。

https://github.com/voluntas/pkgex/blob/develop/rel/files/vm.args#L2

不要なファイルを削除する

今回は files 以下は app.config と vm.args のみとした。

https://github.com/voluntas/pkgex/tree/develop/rel/files

それ以外は削除して問題無い。

git commit して git tag

以上で準備は整った。

node_package は Git と連動しているため tag が何も打たれていない状態だと動作しない。

そのため、ここまでを git で commit し、 git tag でタグを打とう。

ここでは git tag 0.0.0 としている。

$ git commit
$ git tag 0.0.0

実行

$ make package

上記コマンドを打つと package ディレクトリが生成され、その中に tag のバージョンのパッケージが自動で作成されていく。

長いが全てののログを貼り付けておく。Warning は消してある。

$ make package
==> node_package (get-deps)
==> goldrush (get-deps)
==> lager (get-deps)
==> rel (get-deps)
==> pkgex (get-deps)
mkdir -p package
rm -rf package/pkgex-0.0.0
git archive --format=tar --prefix=pkgex-0.0.0/ 0.0.0| (cd package && tar -xf -)
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C package/pkgex-0.0.0 deps
==> rel (get-deps)
==> pkgex-0.0.0 (get-deps)
Pulling node_package from {git,"git@github.com:basho/node_package.git",
                               {branch,"develop"}}
Cloning into 'node_package'...
Pulling lager from {git,"git@github.com:basho/lager.git",{branch,"master"}}
Cloning into 'lager'...
==> node_package (get-deps)
==> lager (get-deps)
Pulling goldrush from {git,"git://github.com/DeadZen/goldrush.git",
                           {tag,"0.1.6"}}
Cloning into 'goldrush'...
==> goldrush (get-deps)
mkdir -p package/pkgex-0.0.0/priv
git --git-dir=.git describe --tags >package/pkgex-0.0.0/priv/vsn.git
for dep in package/pkgex-0.0.0/deps/*; do \
             echo "Processing dep: ${dep}"; \
             mkdir -p ${dep}/priv; \
             git --git-dir=${dep}/.git describe --tags >${dep}/priv/vsn.git; \
        done
Processing dep: package/pkgex-0.0.0/deps/goldrush
Processing dep: package/pkgex-0.0.0/deps/lager
Processing dep: package/pkgex-0.0.0/deps/node_package
find package/pkgex-0.0.0 -depth -name ".git" -exec rm -rf {} \;
tar -C package -czf package/pkgex-0.0.0.tar.gz pkgex-0.0.0
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C package -f pkgex-0.0.0/deps/node_package/Makefile
echo "{app_version, \"0.0.0\"}." >> pkgex-0.0.0/deps/node_package/priv/templates/osx/vars.config
/Applications/Xcode.app/Contents/Developer/usr/bin/make -f pkgex-0.0.0/deps/node_package/priv/templates/osx/Makefile.bootstrap
/Users/voluntas/work/pkgex/rebar -v create \
                        template_dir=pkgex-0.0.0/deps/node_package/priv/templates \
                        template_vars=pkgex-0.0.0/pkg.vars.config template=osx
==> package (create)
ERROR: One or more files already exist on disk and were not generated:
        * "Makefile"
        * "vars.config"
To force overwriting, specify -f/--force/force=1 on the command line.
make -f Makefile
cd pkgex-0.0.0 && \
                OVERLAY_VARS="overlay_vars=../../vars.config" /Applications/Xcode.app/Contents/Developer/usr/bin/make rel
==> node_package (get-deps)
==> goldrush (get-deps)
==> lager (get-deps)
==> rel (get-deps)
==> pkgex-0.0.0 (get-deps)
==> node_package (compile)
==> goldrush (compile)
Compiled src/gr_param_sup.erl
Compiled src/gr_sup.erl
Compiled src/gre.erl
Compiled src/gr_manager_sup.erl
Compiled src/gr_counter_sup.erl
Compiled src/gr_manager.erl
Compiled src/gr_context.erl
Compiled src/gr_app.erl
Compiled src/gr_param.erl
Compiled src/gr_counter.erl
Compiled src/glc_ops.erl
Compiled src/glc.erl
Compiled src/glc_lib.erl
Compiled src/glc_code.erl
==> lager (compile)
Compiled src/lager_util.erl
Compiled src/lager_transform.erl
Compiled src/lager_sup.erl
Compiled src/lager_msg.erl
Compiled src/lager_handler_watcher_sup.erl
Compiled src/lager_handler_watcher.erl
Compiled src/lager_stdlib.erl
Compiled src/lager_trunc_io.erl
Compiled src/lager_default_formatter.erl
Compiled src/lager_format.erl
Compiled src/lager_console_backend.erl
Compiled src/lager_crash_log.erl
Compiled src/lager_file_backend.erl
Compiled src/lager_config.erl
Compiled src/lager_backend_throttle.erl
Compiled src/lager_app.erl
Compiled src/lager.erl
Compiled src/error_logger_lager_h.erl
==> rel (compile)
==> pkgex-0.0.0 (compile)
Compiled src/pkgex_app.erl
Compiled src/pkgex_sup.erl
==> node_package (compile)
==> goldrush (compile)
==> lager (compile)
==> rel (compile)
==> pkgex-0.0.0 (compile)
==> rel (generate)
mkdir -p packages
mkdir -p osxbuild
cd pkgex-0.0.0 && \
                cp -R rel/pkgex \
                   ../osxbuild/pkgex-0.0.0
cd osxbuild && \
                tar -czf ../packages/pkgex-0.0.0-OSX-i386.tar.gz \
                         pkgex-0.0.0
cd packages && \
           for tarfile in *.gz; do \
               shasum -a 256 ${tarfile} > ${tarfile}.sha \
           ; done

package 以下のディレクトリ構成は以下のようになっているはずだ。

Makefile
osxbuild/
packages/
    pkgex-0.0.0-OSX-i386.tar.gz
    pkgex-0.0.0-OSX-i386.tar.gz.sha
pkgex-0.0.0/
pkgex-0.0.0.tar.gz
vars.config

packages 以下の pkgex-0.0.0-OSX-i386.tar.gz が生成された Mac OS X 向けのバイナリファイルだ。

環境によってパッケージの生成を変えてくれる。これを CentOS でやれば rpm が Debian でやれば deb が生成される。

開発時のパッケージング

毎回タグを打つわけにも行かないだろう。 node_package はタグ以外のパッケージングも対応している。

かなり高機能だ。0.0.0 の後ろの 1 というのはタグを打ってからのコミット数だ。 さらにその後ろにショートハッシュが付く。

それでパッケージングが生成されようになる。

$ make package
... 省略
mkdir -p package
rm -rf package/pkgex-0.0.0.1.g7fad516
git archive --format=tar --prefix=pkgex-0.0.0.1.g7fad516/ 0.0.0-1-g7fad516| (cd package && tar -xf -)
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C package/pkgex-0.0.0.1.g7fad516 deps

この状態で生成された Mac OS X 用のパッケージ。

pkgex-0.0.0.1.g7fad516-OSX-i386.tar.gz
pkgex-0.0.0.1.g7fad516-OSX-i386.tar.gz.sha

起動

package ディレクトリの package にバイナリが出来ていますのでそれをコピーすれば動作する。

/tmp にファイルを持っていって起動する例:

$ tar xvfz pkgex-0.0.0.8.g6351c09-OSX-i386.tar.gz
$ cd pkgex-0.0.0.8.g6351c09/
$ ./bin/pkgex console
config is OK
-config /tmp/pkgex-0.0.0.8.g6351c09/bin/../etc/app.config -args_file /tmp/pkgex-0.0.0.8.g6351c09/bin/../etc/vm.args -vm_args /tmp/pkgex-0.0.0.8.g6351c09/bin/../etc/vm.args
Exec:  /tmp/pkgex-0.0.0.8.g6351c09/bin/../erts-6.0/bin/erlexec -boot /tmp/pkgex-0.0.0.8.g6351c09/bin/../releases/0.0.0/pkgex               -config /tmp/pkgex-0.0.0.8.g6351c09/bin/../etc/app.config -args_file /tmp/pkgex-0.0.0.8.g6351c09/bin/../etc/vm.args -vm_args /tmp/pkgex-0.0.0.8.g6351c09/bin/../etc/vm.args              -pa /tmp/pkgex-0.0.0.8.g6351c09/bin/../lib/pkgex-patches -- console
Root: /tmp/pkgex-0.0.0.8.g6351c09/bin/..
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

23:54:21.416 [info] Application lager started on node 'pkgex@127.0.0.1'
23:54:21.416 [info] Application pkgex started on node 'pkgex@127.0.0.1'
Eshell V6.0  (abort with ^G)
(pkgex@127.0.0.1)1>

起動コマンドには幾つか例が書いてあるので参考にされると良い

$ ./bin/pkgex
Usage: pkgex «command»
where «command» is one of the following:
    { help | start | stop | restart | ping | console | attach
      attach-direct | ertspath | chkconfig | escript | version | getpid
      top [-interval N] [-sort { reductions | memory | msg_q }] [-lines N] } |
      config { generate | effective | describe VARIABLE } [-l debug]

Run `pkgex help` for more detailed information.

Erlang/VM 向けの top コマンドが使えるので start で起動した後に実行すると色々見ることが出来る。

$ ./bin/pkgex start
% ./bin/pkgex top

========================================================================================
 'pkgex@127.0.0.1'                                                         14:56:16
 Load:  cpu         0               Memory:  total       17920    binary        688
        procs      64                        processes    4591    code         7485
        runq        0                        atom          331    ets           372

Pid            Name or Initial Func    Time    Reds  Memory    MsgQ Current Function
----------------------------------------------------------------------------------------
<5816.3.0>     erl_prim_loader          '-'  341697  142736       0 erl_prim_loader:loop
<5816.25.0>    code_server              '-'  115471  101408       0 code_server:loop/1
<5816.11.0>    kernel_sup               '-'   54309  197424       0 gen_server:loop/6
<5816.0.0>     init                     '-'   18383   42312       0 init:loop/1
<5816.6.0>     error_logger             '-'    6453    5920       0 gen_event:fetch_msg/
<5816.44.0>    release_handler          '-'    5825   58144       0 gen_server:loop/6
<5816.57.0>    application_master:s     '-'    5706   42272       0 application_master:l
<5816.7.0>     application_controll     '-'    4805   55328       0 gen_server:loop/6
<5816.32.0>    erlang:apply/2           '-'    3412  142880       0 shell:get_command1/5
<5816.59.0>    lager_event              '-'    2712   12104       0 gen_event:fetch_msg/
========================================================================================

ubuntu でのパッケージングサンプル

書きかけ

  • Erlang/OTP 17.0 インストール済み
$ sudo aptitude install devscripts

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment