Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

DockerでHerokuでmrubyが動いたぞ!!1

dockerを使ってHerokuにアプリを簡単にデプロイできる感じの仕組みができた(という説明であってるのかよくわからないけど)そうなので、試してみた。

github.com

動かしているのは、単になんか変な文字列を表示するだけのアプリ。

以下に、手順を示す。

動かすまでの手順

herokuコマンドなどの準備

herokuクライアントを入れる。

$ brew install heroku
==> Downloading https://s3.amazonaws.com/assets.heroku.com/heroku-client/heroku-client-3.32.0.tgz
🍺  /usr/local/Cellar/heroku-toolbelt/3.32.0: 818 files, 7.4M, built in 7 seconds

boot2dockerでdockerが動いていることを確認(boot2dockerについてはどこか適当なとこを見てください)。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

dockerプラグインを入れる。

$ heroku plugins:install heroku-docker
Installing plugin heroku-docker... done
updating...done. Updated to 3.36.0

helpを見てみるね。

$ heroku help docker
Usage: heroku docker

  Use Docker to build and deploy Heroku apps

Additional commands, type "heroku help COMMAND" for more details:

  docker:clean    #  clean up docker images
  docker:exec     #  run command in development Docker container
  docker:init     #  create Dockerfile for app
  docker:release  #  create and release slug to app
  docker:start    #  start Docker app container

ディレクトリを作る。

$ mkdir mruby-app-on-heroku-using-docker
$ cd mruby-app-on-heroku-using-docker
$ git init

実行環境の準備

まずはDockerfileを作成。言語が判定できたらそれ用のファイルが作られるが、今回の場合は空ディレクトリなので、ミニマルなものが作られる。

$ heroku docker:init
Wrote Dockerfile (minimal)
$ cat Dockerfile
FROM heroku/cedar:14

RUN useradd -d /app -m app
USER app
WORKDIR /app

ENV HOME /app
ENV PORT 3000

RUN mkdir -p /app/heroku
RUN mkdir -p /app/src
RUN mkdir -p /app/.profile.d

WORKDIR /app/src

ONBUILD COPY . /app/src
ONBUILD EXPOSE 3000

これを、あとで書くコードを動かすために、以下のように変更します(# install mrubyのとこを足しただけ)。dockerまだよくわかってない(ONBUILDとか)ので、おかしいかも。

FROM heroku/cedar:14

RUN useradd -d /app -m app

# install mruby
WORKDIR /app
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -y update
RUN apt-get -y install git
RUN git clone https://github.com/mruby/mruby.git
COPY ./build_config.rb /app/mruby/build_config.rb
RUN cd mruby && ./minirake

USER app
WORKDIR /app

ENV HOME /app
ENV PORT 3000

RUN mkdir -p /app/heroku
RUN mkdir -p /app/src
RUN mkdir -p /app/.profile.d

WORKDIR /app/src

ONBUILD COPY . /app/src
ONBUILD EXPOSE 3000

Procfileも作ります。

web: /app/mruby/bin/mruby /app/src/server.rb $PORT

コード

コードを書きます。

queue = %w[生 麦 生 米 生 卵]

server = SimpleHttpServer.new(
  server_ip:     "0.0.0.0",
  port:          ARGV[0] || 3000,
  document_root: "./",
)

server.location "/" do |r|
  content = ""

  while rand > 0.1 do
    char = queue.shift
    content << char
    queue.push(char)
  end

  server.response_body = "#{content}\n"
  server.create_response
end

server.run

mruby用の設定ファイル(build_config.rb)を最小限で作っておく(dockerコンテナ上にコピーする)。

MRuby::Build.new do |conf|
  toolchain :gcc
  conf.gembox "default"

  conf.gem github: "iij/mruby-pack"
  conf.gem github: "iij/mruby-io"
  conf.gem github: "iij/mruby-socket"
  conf.gem github: "mattn/mruby-http"
  conf.gem github: "matsumoto-r/mruby-simplehttpserver"
end

動かす && デプロイ

準備が終わったら、以下のコマンドでdockerを起動(最初はもっといろいろ出るけど、最終的には以下の通りの表示)。

$ heroku docker:start
building image...
Sending build context to Docker daemon 36.35 kB
Sending build context to Docker daemon
Step 0 : FROM heroku-docker-56ce9cd475f9adbdf3bf82829f2b391b
# Executing 2 build triggers
Trigger 0, COPY . /app/src
Step 0 : COPY . /app/src
Trigger 1, EXPOSE 3000
Step 0 : EXPOSE 3000
 ---> Running in 352b1fd7659c
 ---> 2733aaefdd11
Removing intermediate container cd1c25741202
Removing intermediate container 352b1fd7659c
Successfully built 2733aaefdd11

starting container...
web process will be available at http://192.168.59.103:3000/

アクセスしてみる。

$ curl http://192.168.59.103:3000/
生麦生米

$ curl http://192.168.59.103:3000/
生卵生麦生米生卵生麦生米生卵生

$ curl http://192.168.59.103:3000/
麦生米生

ちゃんと表示されましたね。

では、デプロイしてみよう。その前に、Heroku上でアプリを作る。

$ heroku create
Enter your Heroku credentials.
Email: kentarok@gmail.com
Password (typing will be hidden):
Creating pacific-refuge-5105... done, stack is cedar-14
https://pacific-refuge-5105.herokuapp.com/ | https://git.heroku.com/pacific-refuge-5105.git
Git remote heroku added

んでもってリリース。

$ heroku docker:release
creating local slug...
building image...
Sending build context to Docker daemon 36.35 kB
Sending build context to Docker daemon
Step 0 : FROM heroku-docker-56ce9cd475f9adbdf3bf82829f2b391b
# Executing 2 build triggers
Trigger 0, COPY . /app/src
Step 0 : COPY . /app/src
Trigger 1, EXPOSE 3000
Step 0 : EXPOSE 3000
 ---> Running in b699aa35853c
 ---> 56fdb53d58fa
Removing intermediate container 87ea104c42ea
Removing intermediate container b699aa35853c
Successfully built 56fdb53d58fa
creating remote slug...
uploading slug...
releasing slug...

以下のURLにアクセスしてみる。

$ curl https://pacific-refuge-5105.herokuapp.com/
卵生麦生米生卵生麦

$ curl https://pacific-refuge-5105.herokuapp.com/
生米生

$ curl https://pacific-refuge-5105.herokuapp.com/
卵生麦生米生卵生麦生米

ちゃんと表示されましたね。やった!

よくわからないこと

  • ほんとは、$ heroku docker:startした時に表示されるhttp://192.168.59.103:3000/にアクセスするとローカルで見えるはずなのだけど、どうもProcfileの実行時に$PORTがわたってないぽかった。Heroku上ではちゃんとしてる。
  • DockerfileWORKDIR /app/srcとしているのに、Heroku上では、Procfile相対パスだとファイル名が解決できてなくて、絶対パスにしたらいけた。

追記: deeeeeeeeeetさんが教えてくれたよ(↑のコード(server.rb)もあわせて修正)。

まとめ

  • Dockerを使って、ローカル開発環境をいい感じにしつつ、Herokuにも簡単にアプリを公開できるようになった
  • 公式のドキュメントではRubynodeの解説しかないけど、普通になんでも動く。
  • mrubyでアプリを作って動かしてみた。
  • ハマったところはちょっとあったけど、総じて簡単だった。便利。

参考リソース