しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

App Service on Linux を Heroku っぽく使う Runtime Stack を作成してみた

App Service on Linux のカスタム Docker Image を利用していると、やっぱり Heroku のように foreman を使ったプロセス管理が使いたくなってきました。

Heroku では Procfile をルートに用意しておくと、いい感じにランタイムが読み込んで実行してくれます。

2 月に試した時には Ruby on Rails アプリケーションの実行が上手く出来ませんでしたが、最近 Hanselman が動かしていたので試してみます。

Runtime Stack の Dockerfile やスクリプトもいい感じに公開されていたので、参考しながら利用します。

帝国兵殿曰く、Built-in の Runtime Stack に対しては特殊処理が入っているらしいので、独自の Runtime Stack を作る場合には少し手間がかかります。そのままの Dockerfile を使ってビルドしても上手くいきません。

なので多少カスタマイズした Dockerfile を用意しました。基本的な部分は変わりませんが WORKDIR を設定してみたり、ENTRYPOINT を追加してみたりしています。あと foreman のインストールを追加しています。

FROM ruby:2.3.3

COPY startup.sh /bin/

RUN apt-get update -qq \
    && apt-get install -y nodejs --no-install-recommends \
    && chmod 755 /bin/startup.sh

RUN gem uninstall -i /usr/local/lib/ruby/gems/2.3.0 bundler
RUN gem install bundler --version "=1.13.6"

RUN gem install rubygems-bundler
RUN gem regenerate_binstubs
RUN gem install --no-user-install foreman
RUN gem install --no-user-install passenger

WORKDIR /home/site/wwwroot

EXPOSE 3000

ENTRYPOINT ["/bin/startup.sh"]

エントリポイントとして実行するスクリプトは、ほぼ Ruby の Built-in Stack と同じものを用意しました。

最後に Procfile のチェックとポートを指定しての実行を行っています。

#!/bin/bash
cd /home/site/wwwroot

if [ -n "$SECRET_KEY_BASE" ]
  then
    echo 'Secret key base present'
  else
    echo 'Generating a secret key base'
    export SECRET_KEY_BASE=$(ruby -rsecurerandom -e 'puts SecureRandom.hex(64)')
fi

if [ -n "$RAILS_ENV" ]
  then
    echo 'RAILS_ENV set to $RAILS_ENV'
  else
    echo 'RAILS_ENV not set, default to production'
    export RAILS_ENV='production'
fi

echo 'Removing any leftover pids if present'
rm -f tmp/pids/* ;

bundle config --local path "vendor/bundle"
if bundle check --path "vendor/bundle" | grep satisfied
  then
    echo 'dependency check passed'
  else
    echo 'missing dependencies, try redeploying'
    exit -1
fi

echo 'running bundle install --local --deployment'
bundle install --local --deployment

foreman check
foreman start -p 3000

作成した Docker Image は Docker Hub に push した後に、ポータルから設定をしておきます。

f:id:shiba-yan:20170417011740p:plain

最後に作成しておいたテンプレそのままの Rails アプリケーションに対して Procfile を追加します。この辺りは Heroku で使う場合とほぼ変わらない形で問題ないです。

bundle exec を経由して、ポートを指定するのが重要です。

web: bundle exec rails server -p $PORT

Git を使ってデプロイ後、起動には少し時間はかかりますが空の Rails ページが表示されました。

RAILS_ENV が production になっているので、多少味気ない表示ですが動いているので問題ないですね。

f:id:shiba-yan:20170417011651p:plain

最後に Kudu を使って Docker のログを確認してみると、ちゃんと foreman を使ってアプリケーションが起動されていることが確認できます。

web という名前でサーバーが立ち上がっています。

f:id:shiba-yan:20170417013737p:plain

当然ながら web 以外にも常時起動するタイプのアプリケーションを、追加で動かすことも可能です。

App Service on Linux では Docker Swarm が使えないので Supervisord などを使ってきましたが、foreman を使った方が簡単なケースが多そうです。