読者です 読者をやめる 読者になる 読者になる

Heroku 上で WebMachine (Erlang) を動かす

heroku コマンドが入っていない場合は gem install heroku で入ります。

まずは webmachine を持ってきて、webmachine ベースのアプリを new_webmachine.sh で作ります。

$ cd /tmp
$ git clone git://github.com/basho/webmachine
$ cd webmachine
$ make
$ ./scripts/new_webmachine.sh heroku_webmachine /tmp
$ cd /tmp/heroku_webmachine
$ make

それが終わったら、git 環境を作って heroku インスタンスを生成します。
その後、Erlang アプリが動く buildpack を設定に指定します。
heroku-webmachine というのは今回使っている名前です、基本的には自由に指定して下さい。

$ git flow init
$ heroku create heroku-webmachine -s cedar
$ heroku config:add BUILDPACK_URL=http://github.com/heroku/heroku-buildpack-erlang.git

erl 自体は入っているので、あとはそのままさくっと Procfile を用意します。

web: erl -pa ebin deps/*/ebin -noshell -boot start_sasl -s reloader -s heroku_webmachine 

WebMachine ではポート番号が固定になってしまっているので、環境変数からポート番号を取得するような仕組みに変更します。ついでに常に 0.0.0.0 アドレスで開くようにしてしまいます。

%% @spec init([]) -> SupervisorTree
%% @doc supervisor callback.
init([]) ->
    %% Ip = case os:getenv("WEBMACHINE_IP") of false -> "0.0.0.0"; Any -> Any end,
    {ok, Dispatch} = file:consult(filename:join(
                         [filename:dirname(code:which(?MODULE)),
                          "..", "priv", "dispatch.conf"])),
    Port = list_to_integer(os:getenv("PORT")),
    io:format("start web server on port ~p~n", [Port]),
    WebConfig = [
                 {ip, "0.0.0.0"},
                 {port, Port},
                 {log_dir, "priv/log"},
                 {dispatch, Dispatch}],
    Web = {webmachine_mochiweb,
           {webmachine_mochiweb, start, [WebConfig]},
           permanent, 5000, worker, [mochiweb_socket_server]},
    Processes = [Web],
    {ok, { {one_for_one, 10, 10}, Processes} }.

あとは保存して、heroku の master に push します。git flow を使っているので develop ですが普通は master:master で問題無いはずです。

$ git push heroku develop:master
Counting objects: 19, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (16/16), done.
Writing objects: 100% (19/19), 104.89 KiB, done.
Total 19 (delta 0), reused 0 (delta 0)

-----> Heroku receiving push
-----> Fetching custom buildpack... done
-----> Erlang app detected
-----> Building with Rebar
       ==> build_388qu6ci88xko (get-deps)
       Pulling webmachine from {git,"git://github.com/basho/webmachine","HEAD"}
       Initialized empty Git repository in /tmp/build_388qu6ci88xko/deps/webmachine/.git/
       ==> webmachine (get-deps)
       Pulling mochiweb from {git,"git://github.com/mochi/mochiweb",{tag,"1.5.1"}}
       Initialized empty Git repository in /tmp/build_388qu6ci88xko/deps/mochiweb/.git/
       ==> mochiweb (get-deps)
       ==> mochiweb (compile)
       Compiled src/mochinum.erl
       Compiled src/mochiweb_socket.erl
       Compiled src/mochiweb.erl
       Compiled src/mochiweb_echo.erl
       Compiled src/mochilists.erl
       Compiled src/mochiweb_response.erl
       Compiled src/mochiglobal.erl
       Compiled src/mochiweb_http.erl
       Compiled src/mochiweb_mime.erl
       Compiled src/mochiweb_charref.erl
       Compiled src/reloader.erl
       Compiled src/mochifmt_std.erl
       Compiled src/mochifmt_records.erl
       Compiled src/mochiweb_multipart.erl
       Compiled src/mochiweb_headers.erl
       Compiled src/mochiweb_socket_server.erl
       Compiled src/mochijson2.erl
       Compiled src/mochiweb_cover.erl
       Compiled src/mochiweb_io.erl
       Compiled src/mochiweb_cookies.erl
       Compiled src/mochijson.erl
       Compiled src/mochiweb_sup.erl
       Compiled src/mochihex.erl
       Compiled src/mochiweb_app.erl
       Compiled src/mochilogfile2.erl
       Compiled src/mochiutf8.erl
       Compiled src/mochiweb_acceptor.erl
       Compiled src/mochiweb_request_tests.erl
       Compiled src/mochitemp.erl
       Compiled src/mochiweb_util.erl
       Compiled src/mochiweb_skel.erl
       Compiled src/mochiweb_request.erl
       Compiled src/mochifmt.erl
       Compiled src/mochiweb_html.erl
       ==> webmachine (compile)
       Compiled src/webmachine.erl
       Compiled src/webmachine_perf_logger.erl
       Compiled src/wrq.erl
       Compiled src/webmachine_error_handler.erl
       Compiled src/wmtrace_resource.erl
       Compiled src/webmachine_deps.erl
       Compiled src/webmachine_resource.erl
       Compiled src/webmachine_mochiweb.erl
       Compiled src/webmachine_dispatcher.erl
       Compiled src/webmachine_sup.erl
       Compiled src/webmachine_multipart.erl
       Compiled src/webmachine_util.erl
       Compiled src/webmachine_request.erl
       Compiled src/webmachine_app.erl
       Compiled src/webmachine_logger.erl
       Compiled src/webmachine_router.erl
       Compiled src/webmachine_decision_core.erl
       ==> build_388qu6ci88xko (compile)
       Compiled src/heroku_webmachine.erl
       Compiled src/heroku_webmachine_resource.erl
       Compiled src/heroku_webmachine_app.erl
       Compiled src/heroku_webmachine_sup.erl
-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 3.4MB
-----> Launching... done, v5
       http://heroku-webmachine.herokuapp.com deployed to Heroku

あとは、 http://heroku-webmachine.herokuapp.com にアクセスして貰えば動いていることがわかります。

感想

かなり簡単に起動できてビックリしました。いつも Mochiweb をそのまま触っているので WebMachine はほとんど触ったことが無く、はまるかな?と思ったりしましたが別にはまること無くさくっと出来てしまいました。

Heroku で Erlang が動くと言うことは、Erlang + Web を色々やってみたくなりますね。ということで次は Heroku が提供している DB とつないで何かしてみようと思います。