00:00:00

Heroku Gauche
(あるいは好きな言語なんでも)

Lightweight Language Diver 2014

久井 亨 Toru Hisai @torus

Notes

自己紹介

  • 久井 亨(ひさい とおる)
  • 都内のゲーム制作会社のサーバサイドエンジニア
    • 普段は Node.js
  • 一応 CPAN author(3 個だけ)

Notes

あらすじ

  1. Heroku のしくみ
  2. Docker でビルド
  3. Gauche でウェブアプリ

Notes

(関係者の方いたらツッコミお願いします)

Notes

Heroku

  • Y Combinator から生まれた PaaS
  • Git でスマートにデプロイ
    • git push heroku master
  • アメリカ西海岸でブイブイいわせたい

Notes

様々な言語、フレームワークに対応

Notes

しかし

  • Gauche はない
  • 他の Scheme 処理系もない

Notes

Notes

Y Combinator にかぶれる

Notes

Notes

Notes

The Celadon Cedar Stack

  • Heroku のデフォルトスタック
    • ベース OS: Ubuntu 10.04
    • ライブラリ
    • 言語実行ランタイム
  • この上にのせれば動く……!

Notes

Slug

Notes

Slug

  • 実行可能な Cedar アプリケーションを tar アーカイブしたもの
  • 作成時の約束はこれだけ:
    • ディレクトリ名:app
    • コマンド:tar czfv slug.tgz ./app
      • ./ が重要!

Notes

アーカイブ

Notes

Cedar Stack に載せる

Notes

Notes

ビルド/デプロイ/リリース

  • Git は使わない
    • Slug を作る
    • Web API でアップロード
    • Web API でリリース

Notes

Ubuntu 10.04 でコンパイル

  • Mac や Ubuntu 14.04 でコンパイルしても動かない
    • バイナリの形式が違う
    • glibc のバージョンが違う
  • heroku run bash はまどろっこしい
    • One-off dyno は別料金がかかる
  • そこで……

Notes

Notes

Docker を使うと簡単

  • Dockerfile を作るだけ

Notes

Dockerfile

仮想マシンにいろいろインストールして
イメージを作る。

  • Ubuntu 10.04
  • Gauche 0.9.4 & HEAD
  • Gauche-makiki
  • Gauche-gl

Notes

Dockerfile - Ubuntu 10.04

FROM ubuntu:10.04
MAINTAINER Toru Hisai <toru@torus.jp>

RUN apt-get update -y
RUN apt-get install -y wget gcc
RUN apt-get install -y zlib1g-dev slib
RUN apt-get install -y make autoconf

Notes

Dockerfile - Gauche 0.9.4

WORKDIR /tmp
RUN wget http://prdownloads.sourceforge.net/
                        gauche/Gauche-0.9.4.tgz
RUN tar xvfz Gauche-0.9.4.tgz

WORKDIR Gauche-0.9.4
RUN ./configure
RUN make
RUN make check
RUN make install

Notes

Dockerfile - Gauche HEAD

(あらかじめ GitHub からクローンしておく)

ADD Gauche /tmp/Gauche
WORKDIR /tmp/Gauche
RUN ./DIST gen
RUN ./configure --prefix=/opt/gauche
RUN make
RUN make check
RUN make install
ENV PATH /opt/gauche/bin:$PATH

Notes

Dockerfile - Gauche-makiki

(あらかじめ GitHub からクローンしておく)

ADD Gauche-makiki /tmp/Gauche-makiki
WORKDIR /tmp/Gauche-makiki
RUN ./DIST gen
RUN ./configure --prefix=/opt/gauche
RUN make
RUN make check
RUN make install

Notes

Dockerfile - Gauche-gl

(あらかじめ GitHub からクローンしておく)

ADD Gauche-gl /tmp/Gauche-gl
WORKDIR /tmp/Gauche-gl
RUN ./DIST gen
RUN ./configure --prefix=/opt/gauche
RUN make
RUN make check
RUN make install

Notes

Dockerfile - バイナリ生成

エントリーポイントでバイナリをダンプする。

WORKDIR /opt
ENTRYPOINT tar cf - gauche

Notes

イメージのビルドと起動

$ docker build -t gauche_heroku_app .
$ docker run gauche_heroku_app |\
                 (cd app && tar xvf -)

Notes

Gauche でウェブアプリ

Notes

必要な物

  • Gauche の開発版
    • プロダクション環境でも最新版を使いたい
    • ビルドに Gauche のリリース版が必要
  • Gauche-makiki
    • Sinatra 風ウェブフレームワーク
  • Gauche-gl
    • ベクトル計算に使用

Notes

Gauche-makiki

(use makiki)

(define-http-handler "/render.ppm"
  (^[req app]
    (random-source-randomize! default-random-source)
    (let ([param-size (request-param-ref req "size")]
          [param-frame (request-param-ref req "frame")])
      (let ([opt-size (if param-size #`"-s ,param-size" "")]
            [opt-frame (if param-frame #`"-f ,param-frame" "")]
            [outfile #`"out,(random-integer 1000000).jpg"])
        (respond/ok req
                    (with-output-to-string
                      (lambda ()
                        ((global-variable-ref raytracer-mod 'main)
                         `(self ,@(string-split opt-size #/\s+/)
                                ,@(string-split opt-frame #/\s+/)))))
                    :content-type "image/x-portable-pixmap")))))

Notes

リリースまでの道のり

  • Slug を作る
  • process_types を考える
  • Slug をアロケート
  • Slug をアップロード
  • 環境変数の設定
  • リリース

Notes

Slug を作る

slug.tgz: $(SOURCES) ../docker/gauche/app/gauche
    rm -rf app
    mkdir app
    cp -R ../docker/gauche/app/gauche app/gauche
    cp -R $(SOURCES) app/
    tar cfz $@ ./app
  • Docker で作った app ディレクトリ
  • アプリケーション

をコピーしてアーカイブ。

Notes

process_types

  • Procfile の内容に相当するもの
{"process_types":
  {"web":"./gauche/bin/gosh
      -I ./gauche/share/gauche-0.9/0.9.4/lib
      -I ./gauche/share/gauche-0.9/site/lib
      -I ./gauche/lib/gauche-0.9/0.9.4/
                         x86_64-unknown-linux-gnu/
      -I ./gauche/lib/gauche-0.9/site/
                         x86_64-unknown-linux-gnu/
      -I ./
      index.scm --port=$PORT"}}

Notes

Slug をアロケート

slug.json: slug.tgz
    curl -X POST \
    -H 'Content-Type: application/json' \
    -H 'Accept: application/vnd.heroku+json; version=3' \
    -d '{"process_types":{"web":"./gauche/bin/gosh \
        -I ./gauche/share/gauche-0.9/0.9.4/lib \
        -I ./gauche/share/gauche-0.9/site/lib \
        -I ./gauche/lib/gauche-0.9/0.9.4/x86_64-unknown-linux-gnu/ \
        -I ./gauche/lib/gauche-0.9/site/x86_64-unknown-linux-gnu/ \
        -I ./ index.scm --port=$$PORT"}}' \
    -n https://api.heroku.com/apps/$(APPNAME)/slugs > $@

Notes

レスポンス:Slug についての情報

{
  "blob":{
    "method":"put",
    "url":"https://s3-external-1.amazonaws.com/herokuslugs/heroku.com/v1/7e4d9819-833f-4aec-9d6f-af112eacd530?AWSAccessKeyId=AKIAJWLOWWHPBWQOPJZQ&Signature=Wu5b7n7S6NgxBYGXolq6AdBoqSY%3D&Expires=1406388246"
  },
  "buildpack_provided_description":null,
  "commit":null,
  "created_at":"2014-07-26T14:24:06Z",
  "id":"7e4d9819-833f-4aec-9d6f-af112eacd530",
  "process_types":{
    "web":"./gauche/bin/gosh -I ./gauche/share/gauche-0.9/0.9.4/lib -I ./gauche/share/gauche-0.9/site/lib -I ./gauche/lib/gauche-0.9/0.9.4/x86_64-unknown-linux-gnu/ -I ./gauche/lib/gauche-0.9/site/x86_64-unknown-linux-gnu/ -I ./ index.scm --port=$PORT"
  },
  "size":null,
  "updated_at":"2014-07-26T14:24:06Z"
}

Notes

Slug アップロード

upload-slug: slug.json
    curl -X PUT \
    -H "Content-Type:" \
    --data-binary @slug.tgz \
    `gosh extract-slug-url.scm < slug.json`
  • extract-slug-url.scm は先のレスポンスから bloburl を取り出す
    • https://s3-external-1.amazonaws.com/herokuslugs/...

Notes

環境変数の設定

  • 環境変数 LD_LIBRARY_PATH を設定
    • Gauche のライブラリがリンクできるように
    • 相対パスになってるのがミソ
$ heroku config:set LD_LIBRARY_PATH=./gauche/lib \
    --app=$APPNAME

Notes

リリース

release: upload-slug
    curl -X POST \
    -H "Accept: application/vnd.heroku+json; version=3" \
    -H "Content-Type: application/json" \
    -d '{"slug":"'`gosh extract-slug-id.scm \
                                    < slug.json`'"}' \
    -n https://api.heroku.com/apps/$(APPNAME)/releases
  • extract-slug-id.scm は先のレスポンスから Slug の ID を取り出す
    • 7e4d9819-833f-4aec-9d6f-...

Notes

デモ

(Slug のアップロードとリリース)

Notes

レイトレーサの原理

Notes

分散レイトレーシング

  • スクリーンを分割してレンダリング
  • ベクトル計算に Gauche-gl を使用

Notes

Dyno

  • Dyno を増やすと簡単にスケールアウト
  • 秒単位で料金精算
    • $.05/時間
    • 1 アプリにつき 750 dyno 時間/月は無料
    • One-off dyno は別途料金がかかる

Notes

Notes

別の方法

  • Buildpack を作る
    • Git でデプロイできるようになる
    • しょっちゅうリビルドする場合は却って面倒

Notes

まとめ

  • Heroku は割となんでも動かせる
  • Docker を使えばビルドもらくちん
  • 使わないときはこまめに Dyno を消しておく
    • 料金が節約できる
  • ソースコード:
    • https://github.com/torus/raytracer
    • https://github.com/torus/gauche-heroku-cedar

Notes