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

しばやん雑記

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

Docker Compose を使って DB 付きの ASP.NET アプリケーションを実行する

ASP.NET Docker

ASP.NET MVC アプリケーションは microsoft/aspnet イメージを使うことで簡単に Windows Containers で動作しましたが、実際のアプリケーションには大抵 DB がセットなので、DB を含めた形でアプリケーションを Docker で動かしてみました。

SQL Server 2016 も Docker Hub でイメージが公開されているので、これを使っていきます。

アプリケーションと DB のコンテナ両方を立ち上げる必要があるので、管理には Docker Compose を使います。依存関係を定義できるので、管理が非常に簡単になります。

Docker Compose の新しいフォーマットで書いてみたところ、コンテナの起動時にエラーになってしまいましたが、以下のサンプルに含まれる定義を参考にして解消できました。

networks の設定を追加しておかないと、現在の Windows Containers では問題になるようです。これもまた WinNAT の制約っぽいです。

作成した docker-compose.yml は以下になります。web と db の 2 つを定義してあります。

version: '2'

services:
  web:
    build: ./app
    depends_on:
      - "db"
    ports:
      - "8080:80"

  db:
    image: microsoft/mssql-server-windows-express
    ports:
      - "1433:1433"
    volumes:
      - "C:/temp/:C:/temp/"
    environment:
      - sa_password=P@ssw0rd
      - ACCEPT_EULA=Y
      - attach_dbs="[{'dbName':'SampleDB','dbFiles':['C:\\temp\\AdventureWorksLT2012_Data.mdf']}]"

networks:
  default:
    external:
      name: nat

web は Dockerfile に基づいてイメージを作成するようにしてあります。DB は attach_dbs でアタッチしたい DB ファイルを指定しておき、コンテナ起動後に SampleDB という名前で使えるようにしてあります。

この docker-compose.yml があるディレクトリで docker-compose up -d を実行すると、ビルドが行われた後にコンテナが依存関係に従って起動されます。

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

用意した ASP.NET アプリケーションは DB の内容を一覧表示するだけの、とても単純なものです。

毎回 IP アドレスを docker inspect で取得するのが面倒になったので、別マシンから確認してみました。

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

上の例ではプリコンパイル済みの ASP.NET アプリケーションを使いましたが、Dockerfile を工夫してプロジェクトフォルダをマウントし、サイトの物理パスを書き換えると開発しながら実行することもできます。

FROM microsoft/aspnet:4.6.2

RUN %windir%\system32\inetsrv\appcmd set vdir "Default Web Site/" -physicalPath:"C:\app"

appcmd を使って Default Web Site の物理パスを C:\app に変更しています。

このままだと IIS に設定したパスにはディレクトリすら存在しないので、docker-compose.yml 側で ASP.NET プロジェクトのディレクトリをマウントするように設定を追加します。

services:
  web:
    build: .
    depends_on:
      - "db"
    ports:
      - "8080:80"
    volumes:
      - "C:/app/WebApplication2/:C:/app/"

これでコンテナを起動すると ASP.NET プロジェクトのパスをサイトのルートとして IIS が起動するので、ビューを変更してリロードすると再コンパイルが行われて画面に反映されるようになります。

過去プロジェクトの環境を維持するのが面倒でしたが、Docker Compose を使えば DB のファイルを保持しておくだけで、簡単に維持が出来そうです。

Windows Containers を使って既存の ASP.NET MVC アプリケーションを動かす

ASP.NET Docker

Azure App Service の Linux 版が Docker に対応したり、Azure Container Registry がプレビューになったりと、Docker と Container に対応しておくと色々幸せになれそうなので、既存の ASP.NET アプリケーションに絞って調べることにしました。

Azure Container Service は Windows Containers 対応がプライベートプレビューになっていますし、ASP.NET 4.6 アプリケーションを Windows Containers 対応にしておくと有利になりそうです。

今後は App Service でも Windows Containers 対応が来る可能性もありますし、対応しておいて損はないと思います。対応させるための手間もほとんどかかりません。

既に Docker Hub で公開されている IIS イメージを使って ASP.NET アプリケーションは動かしてますが、もう少し掘り下げていくことにします。

Docker Hub に公開されている ASP.NET 向けのイメージは .NET Framework 3.5 と 4.6.2 向けの 2 つが公開されてます。分かりにくいことに ASP.NET Core も混ざっているので、注意が必要です。

ビルドに使われている Dockerfile のリポジトリは公開されています。

ありがたいことに ASP.NET MVC アプリケーションを Docker で動かす方法もドキュメントとして公開されています。関係ないですが docs.microsoft.com はかなり見やすくて良いですね。

このドキュメント通りで問題ないですが、少し冗長な部分があったので Dockerfile をもっとシンプルに書き換えて、Windows Containers で動かしてみました。

適当に ASP.NET MVC アプリケーションを作成し、Dockerfile を追加します。

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

Dockerfile には以下のように記述します。microsoft/aspnet イメージは IIS に ASP.NET 4.5 の追加や ENTRYPOINT の指定を行ってくれているので、アプリケーションを wwwroot にコピーするだけで動きます。

FROM microsoft/aspnet:4.6.2

COPY . /inetpub/wwwroot

COPY コマンドで現在のディレクトリにあるファイルを全て wwwroot にコピーするようにします。

プロジェクトに追加した Dockerfile は、プロパティからビルドアクションをコンテンツに変えておきます。こうしないと発行時にファイルがコピーされません。

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

アプリケーション側の準備はたったこれだけで終わりました、非常に簡単ですね。URL Rewrite や ARR が必要な場合には Web PI 経由でインストールしたり、MSI を実行したりと追加しないといけませんが、そのイメージを作ってしまえば済む話です。

このアプリケーションの Docker イメージを作成するために、発行プロファイルを作成していきます。

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

イメージを作るためにはファイルシステムに必要なファイルを書き出す必要があるので、発行方法としてファイルシステムを選んで出力先を適当に選びます。

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

Razor ビューもすべてプリコンパイルするようにして、起動時のパフォーマンスを改善します。

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

これで発行を行うと Dockerfile を含む全てのファイルが出力されます。あとはこのファイルを元に Docker コマンドを使ってイメージを作成するだけです。

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

イメージの作成は docker build コマンドを使います。あっという間に完了します。

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

本来なら作成したイメージを Docker Hub や Azure Container Registry に追加して、ACS や ECS などのオーケストレーションツールを使う形になると思いますが、両方とも対応していないのでローカルで行います。

イメージを実行するために docker run コマンドを使います。

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

イメージの起動後に IP アドレスを取得して、ブラウザからアクセスするとページが表示されます。

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

Visual Studio Tools for Docker の Windows Containers 対応が来ると簡単に対応できるようになりそうですが、Visual Studio 2017 待ちになりそうです。あと、いい加減に WinNAT の対応を行ってほしい気持ちです。

Azure App Service や AWS Elastic Beanstalk で Windows Containers が使えるようになると、かなり利用が簡単になると思うので対応を期待してます。

Windows Server 2016 の Windows Containers と Docker を使って IIS と ASP.NET を動かしてみた

Windows IIS ASP.NET Docker

Windows Server 2016 が MSDN からダウンロード出来るようになっていたので、Service Fabric Cluster 用に買った Intel NUC にインストールしてみました。

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

Hyper-V 上に入れた 2016 で Windows Containers を試したとき、1 日経ってもコンテナが起動しなかったのでホスト OS に Windows Container をインストールして再度試しました。

MSDN のドキュメントも更新されているようなので、Docker を含んだセットアップは手順通り行いました。

ドキュメントにある .NET Core のサンプルはあっさり動作したので、前に Hyper-V 上だと実行に失敗した microsoft/iis イメージを実行してみます。

既に Windows Container と IIS を使って ASP.NET を動作させる方法が色んなところで紹介されてます。

ASP.NET アプリケーションを用意するのは正直面倒だったので、とりあえず IIS のデフォルトページが表示されるところまでやります。

イメージをそのまま pull して、実行するだけという簡単なコマンドです。

docker pull microsoft/iis

docker run -d -p 80:80 microsoft/iis

pull には物凄く時間がかかりますが、一度イメージを作成してしまえば起動は高速です。docker run を実行してから数秒でコンテナが起動しました。

docker ps で実行中のコンテナを確認できます。ポートの設定も同時に見れるので便利です。

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

これでコンテナと同時に IIS も起動しているので、ブラウザで見るといつものページが表示されます。

ここまで時間は 30 分ぐらいかかりましたが、9 割がイメージのダウンロードと作成でした。

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

理由はよくわかりませんでしたが、コンテナホストから localhost は見れませんでした。別のマシンからは表示されたので、実際にはあまり問題にならない気はします。

実行中のコンテナには docker exec を使えば入ることが出来ます。コンテナの ID が必要なので、予め docker ps を実行してコピーしておきます。

docker exec -i -t CONTAINER_ID cmd

powershell を指定してもいいのですが、背景色が狂ってしまって見にくかったのでとりあえず cmd で行きます。これを実行すると、コンテナに入ることが出来ます。

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

コンテナホストは日本語 OS ですが、コンテナの中は英語になっていることが分かります。IIS がインストールされたコンテナなので inetpub がありますが、コンテナホストには存在していません。抜け出すには exit と入力するだけです。

機嫌よくなってきたので ASP.NET も簡単なアプリを用意して動かしてみることにしました。こっちも先人の知恵を頼りに Dockerfile を用意してイメージを作成します。

SHELL で powershell を使うようにすると、コマンドレットがそのまま使えるので便利ですね。ASP.NET の実行に必要な機能をインストールしておきます。

FROM microsoft/iis

SHELL ["powershell"]

RUN Install-WindowsFeature NET-Framework-45-ASPNET ; \
    Install-WindowsFeature Web-Asp-Net45

COPY . C:\\inetpub\\wwwroot

CMD ["ping", "-t", "localhost"]

何もしないとコンテナがすぐ終わってしまうので、終わらないような処理を最後に書いておきます。これは他にもっと良い手があるのではないかと思います。

Dockerfile をビルドした ASP.NET アプリケーションと同じディレクトリに置いて、docker build を実行してイメージを作成します。

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

これも 2 回目以降はキャッシュが使われるので非常に高速です。

後はこれまで通り docker run に作成したイメージ ID を渡せば、そのイメージが起動します。

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

ブラウザでアクセスすると、ASP.NET アプリケーションが実行されているのを確認できます。マシン名は Windows Containers によって適当に付けられているみたいです。

普通の Windows Server と IIS が動いているので、Dockerfile に必要な IIS 拡張をインストールする処理を書けば、URL Rewrite や ARR も問題なく使えると思います。Docker の理解が深まりました。