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

しばやん雑記

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

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

Azure Web Apps Docker

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 を使った方が簡単なケースが多そうです。

Surface Pro 4 に Windows 10 Creators Update をクリーンインストールしてみた

Windows Surface

MacBook Pro の Boot Camp 環境だと Creators Update へのクリーンインストールが問題になるらしいので、仕方なくサブ環境の Surface Pro 4 を先に Creators Update に更新することにしました。

価格改定で安くなった時に買った Surface Pro 4 が活躍です。

Visual Studio 2017 のインストールとユーザープロファイルを作り直したかったので、クリーンインストールにしています。何となく USB ドライブ作ってますが、最近だと要らないのかも。

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

MSDN から ISO を落としておきましたが、同じものを Windows 10 のダウンロードページから落とせる気がします。ISO をマウントしてコピーするだけなので簡単です。

Surface Pro 4 のクリーンインストールする前に、必要なドライバーをダウンロードしておきます。検索したら、丁度 Creators Update と同じタイミングで新バージョンがリリースされていました。

Creators Update 向けにドライバも色々とアップデートされたみたいです。

割と未だにブルースクリーンが頻発するので、そろそろ改善して欲しい気がします。

Surface Pro 4

  • Surface System Aggregator Firmware (v103.1610.256.0) resolves screen brightness issue when devices come out of sleep.
  • Intel(R) Precise Touch Device (v1.2.0.83) improves system stability and performance.
  • Surface Integration (v1.1.121.0) adjusts system hibernation defaults.

ダウンロードセンターから Pro 4 の場合は SurfacePro4_Win10_15063_1701601_0.msi をダウンロードすれば良いみたいです。基本的に zip をダウンロードするより msi の方が簡単です。

Download Surface Pro 4 Drivers and Firmware from Official Microsoft Download Center

インストールを始めると、噂通り Cortana が喋ってきて少し煩かったので、途中からミュートにして進めました、セットアップ時に Wi-Fi に接続してアップデート確認とか昔はなかった気がしました。

大体 15 分ぐらいでインストールは終わった気がします。

f:id:shiba-yan:20170408195140p:plain:w700

ダウンロードしておいた Surface Pro 4 のドライバーをインストールすると、同時に UEFI もアップデートされました。なので再起動必須で少し時間がかかりました。

ドライバーインストール後 Wi-Fi が繋がると、更に Windows Update でドライバーがアップデートされたっぽいです。Windows Update の履歴が分類別になってわかりやすくなりました。

f:id:shiba-yan:20170408194941p:plain:w600

当然ながら Surface Pen / Type Cover も問題なく使えるようになってます。そろそろ Surface Dial 対応のアップデートとか来て欲しいですが、もう来ない気もしてきました。

f:id:shiba-yan:20170408194952p:plain:w550

まだ Visual Studio 2017 を入れたぐらいですが、トラックパッドのジェスチャーが多くなった気がします。

他にも High DPI 周りが良くなったらしいので、Surface Pro 4 を使って体験したいです。

Azure Storage Queue で遅延キューを利用する

Azure

あまり Azure で使っているのを見たことはないのですが、Azure Storage Queue でも指定した時間が経過した後に Dequeue 可能になるようがメッセージを追加することが出来ます。

.NET Storage SDK には制約が書いてなかったですが、REST API のリファレンスにはありました。

Optional. If specified, the request must be made using an x-ms-version of 2011-08-18 or newer. If not specified, the default value is 0. Specifies the new visibility timeout value, in seconds, relative to server time. The new value must be larger than or equal to 0, and cannot be larger than 7 days. The visibility timeout of a message cannot be set to a value later than the expiry time. visibilitytimeout should be set to a value smaller than the time-to-live value.

Put Message | Microsoft Docs

API Version が 2011-08-18 より新しい必要がありますが、最新の SDK を使っていれば問題ないです。

そして試してはいないですが、秒単位で最大 7 日まで指定可能です。注意点としては TTL の値より小さくしないといけないようです。

実際に Queue にメッセージを追加して動作を確認してみます。違いは AddMessage を呼び出すときに initialVisibilityDelay を指定するかどうかだけです。TimeSpan なので秒以下も指定できますが無視されます。

var storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=***;AccountKey=***");
var queueClient = storageAccount.CreateCloudQueueClient();

var queue = queueClient.GetQueueReference("sample");

queue.CreateIfNotExists();

// そのままメッセージを追加する
queue.AddMessage(new CloudQueueMessage("kosmosebi"));

// initialVisibilityDelay として 30 秒を指定して追加する
queue.AddMessage(new CloudQueueMessage("statemachine"), initialVisibilityDelay: TimeSpan.FromSeconds(30));

Queue に追加されたメッセージは Azure Storage Explorer を使うと簡単に確認できます。同じような名前で古いアプリもあるので、間違えないように以下のリンクを貼っておきました。*1

Microsoft Azure Storage Explorer

Azure Storage Explorer では非表示状態になっているメッセージが存在する場合には、左下に表示されている数がずれるようになってます。

この場合は通常のメッセージが 1 つと非表示状態のメッセージが 1 つ存在しています。

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

大体 30 秒が経過した後に読み込み直すと、2 つのメッセージが表示されます。

2 つのメッセージの Insertion Time が同じになっていることから、後から追加されたわけではないことが分かりますね。これで手軽に処理を遅らせることが出来ます。

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

アプリケーションやワーカーなどで Thread.Sleep などで無駄な待ちをさせることなく、5 秒だけ処理を遅らせたいみたいな場合には、遅延キューを使えば簡単に仕組みを変えずに実現できます。

メッセージ単位で initialVisibilityDelay を指定すると、当然ながら FIFO が崩れます。注意したいです。