Dockerでnginx + ASP.NET Core 2.0のWebサーバ環境を構築する
Docker for WindowsでDockerの使い方がなんとなく分かってきたので、nginxとASP.NET Core 2.0を使ったWebサーバとアプリケーションサーバの環境を構築してみたいと思います。
動作確認レベルなので基本的には難しいことには手を出さずにdocker hubで提供されているテンプレートをベースにしてブラウザからDocker上に構築したサイトへアクセス可能かどうかだけを確認します。
目次
- 使用するイメージとコンテナの数について
- ASP.NET CoreプロジェクトやDocker関連ファイルの構成
- ASP.NET CoreのWebアプリケーション作成から配置まで
- Docker Composeファイルの作成(docker-compose.yml)
- Dockerfileファイルの作成(Dockerfile)
- nginx.confファイルの作成
- Dockerの実行
- 動作確認
- 最後に
- 参考リンク
使用するイメージとコンテナの数について
使用するイメージはdocker hubで公開されている「nginx:latest」と「aspnetcore:latest」の2つです。
コンテナ数については、Webサーバ(nginx)とアプリケーションサーバ(ASP.NET Core)で構成されたシステムにするので、それぞれコンテナを1つずつの計2つ作成します。
本当はDBサーバを追加して3つにしたかったのですが、一度にやろうとすると上手くいかないことが多いので今回は除外しています。
ASP.NET CoreプロジェクトやDocker関連ファイルの構成
大体、以下のような感じです。
c ├ docker │ └ test │ ├ app │ │ ├ publish │ │ └ Dockerfile │ ├ nginx │ │ └ nginx.conf │ └ docker-compose.yml │ └ work └ vs2017projects └ WebApplicationTest1 ├ WebApplicationTest1.sln └ WebApplicationTest1 ├ WebApplicationTest1.csproj └ bin └ Release └ PublishOutput
ASP.NET CoreのWebアプリケーション作成から配置まで
Visual Studio 2017を起動してプロジェクトの新規作成を選択します。
ASP.NET Core Webアプリケーションを選択してOKボタンをクリックすると使用するCoreフレームワークのバージョンや初期テンプレートが選択できるので、今回は「Webアプリケーション(MVC)」を選んでプロジェクトを作成します。
作成されたプロジェクトの構成は以下のようになっていると思います。
まず、デフォルトではlocalhostからのアクセスからしか許可されていないので、Webアプリケーションを外部に公開する設定を追加します。
上記、エクスプローラーの「Program.cs」を開いて、「UseUrls()」を追記します。ポート番号は任意の番号でOKですが、以降の手順は「5000」番で行っていますので変更する場合は適宜読み替えてください。
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:5000/")
.UseStartup<Startup>()
.Build();
単純な動作確認であれば上記の外部公開設定だけでいいのですが、今回は特定のサブディレクトリにアクセスされた時のみASP.NET CoreのWebアプリケーションを実行させるようにするので、リリースビルド(公開)時のみbaseタグによるURLの設定を追加して、ライブラリやCSS、画像などの外部ファイルのパスの先頭に付加されているチルダとスラッシュを削除して単純な相対パスでの指定に変更します。(ソースの修正はサブディレクトリでアクセスする場合のみ必要。ホスト名やIPアドレスだけ、またはサブドメインでアクセスして動作確認をする際は発行処理まで読み飛ばしてください。)
「Views/Shared/_Layout.cshtml」を以下のように修正。
...
<environment exclude="Development">
<base href="/wwwroot-aspnetcoretest/" target="_self"/>
...
<link rel="stylesheet" href="css/site.min.css" asp-append-version="true" />
</environment>
...
<environment exclude="Development">
...
<script src="js/site.min.js" asp-append-version="true"></script>
</environment>
...
続いて「Views/Home/index.cshtml」のSVGファイル参照パスからもチルダとスラッシュを削除します。
...
<img src="images/banner1.svg" alt="ASP.NET" class="img-responsive" />
...
<img src="images/banner2.svg" alt="Visual Studio" class="img-responsive" />
...
<img src="images/banner3.svg" alt="Package Management" class="img-responsive" />
...
<img src="images/banner4.svg" alt="Microsoft Azure" class="img-responsive" />
...
今回はサブディレクトリ名として「aspnetcoretest」を指定するので、「Startup.cs」のapp.UseMvc()を以下のように修正します。
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "aspnetcoretest/{controller=Home}/{action=Index}/{id?}");
});
ついでにデバッグ実行時にも同様な動作とするため、「プロジェクトのプロパティ > デバッグ > Webサーバーの設定 > アプリURL」の設定を以下のように変更します。
http://localhost:62443/aspnetcoretest
デバッグ実行の動作確認で問題がなければ、発行処理を行います。(プロジェクトを右クリック > 発行 > フォルダー選択 > 発行開始)
発行が終了すると出力先のフォルダにファイルが作成されています。
最後に出力されたファイルを移動します。(Dockerでマウントするフォルダの場所を発行処理の出力先フォルダにするのであればファイルの移動は不要)
今回は「WebApplicationTest1 > bin > Release > PublishOutput」の全ファイルを「docker > test > app > publish」配下にすべてコピーして以降の作業を行います。
Docker Composeファイルの作成(docker-compose.yml)
複数のコンテナを作成・管理する場合、通常のdockerだけでは不便なのでdocker-composeを利用します。
Windowsの場合、Docker for Windowsをインストールしていれば最初からdocker-composeコマンドが使えるので、新たにインストールする必要はありません。
使い方も簡単でdocker-composeコマンド実行するフォルダ配下に「docker-compose.yml」を用意します。
今回の動作確認で使うdocker-compose.ymlファイルの中身は以下の通りです。
version: '3'
services:
app:
build:
context: ./app
dockerfile: Dockerfile
web:
image: nginx:latest
ports:
- 8080:80
links:
- "app"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./app/publish/wwwroot:/usr/share/nginx/html/wwwroot-aspnetcoretest
versionは指定する番号によって書き方が異なります。(Compose file version 3 reference | Docker Documentation)
ASP.NET Coreで構成されたアプリケーションサーバはちょっと指定が複雑なので、コンテナの作成に「app」フォルダ配下にある「Dockerfile」を参照するように指定しています。
nginxについてはローカルのブラウザからアクセスする際のポート(posts)の指定とリバースプロキシでアプリケーションサーバにアクセスしないといけないので、生成されたコンテナのnginx.confを事前にこちらで修正したものに置き換える(volumes)ようにしています。
Volumesの2つ目に指定しているコマンドは、ASP.NET Coreプロジェクトを発行した際に「wwwroot」配下に出力されるファイルを、Webサーバ(nginx)側で参照できる階層にマウントしています。(このコマンドはサブディレクトリでアクセスした際にcss、js、svgといったwwwroot配下のファイルが参照できなかったので、Webサーバ側(nginx)に配置したものです。暫定対応に近いのでアプリケーションサーバから参照できるなら必要ありません。サブディレクトリでのアクセスを止めたら正常に参照できたので、VisualStudioの設定やURLの記述に問題があるものと思います。)
Dockerfileファイルの作成(Dockerfile)
FROM microsoft/aspnetcore:latest
#RUN apt-get update && apt-get install -my wget gnupg
#RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
#RUN apt-get install -y build-essential nodejs
WORKDIR /app
COPY publish .
ENV ASPNETCORE_URLS http://+:5000
EXPOSE 5000
ENTRYPOINT ["dotnet", "WebApplicationTest1.dll"]
動作確認用に作成したプロジェクトでは問題ありませんでしたが、Node.jsが使われているWebアプリケーションプロジェクト(AngularやReactベースのテンプレート)を使っていた場合、上記のコマンドではNode.jsがインストールされていないせいかエラーが出ます。
その場合は、コメントにしているコマンドを有効にして実行してください。(centos系であればgnupgのインストールはおそらく不要)
nginx.confファイルの作成
user nginx;
worker_processes 1;
events {
worker_connections 1024;
}
http {
# include /etc/nginx/conf.d/*.conf;
upstream app_servers {
server app:5000;
}
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /aspnetcoretest {
proxy_pass http://app_servers/aspnetcoretest;
proxy_redirect off;
}
}
}
見やすいようにログやその他の細かい設定は省いています。
サブドメインの設定を行う場合、「server_name」にサブドメインを含んだドメインを指定します。詳しくは「nginxのサブドメインでrailsの複数アプリを運用 - mikami's engineer diary」を参照。
Dockerの実行
作成したdocker-compose.ymlファイルを実行するには、コマンドプロンプトやWindows PowerShellを起動して該当ファイルが置かれているフォルダへ移動した後に以下のコマンドを実行します。
docker-compose up -d --build
コマンドが正常に終了するとコンテナが稼働します。
以下はKitematicで稼働後のコンテナを表示したものです。
稼働中のコンテナへ接続するコマンド。
docker-compose exec web /bin/bash
停止するコマンド。
docker-compose stop
その他のdocker-compose用のコマンドはこちら(docker-compose コマンドまとめ - Qiita)を参照。
動作確認
最後に
サブディレクトリでアクセスするサーバを切り替えるようにしたせいでかなりハマってしまいましたが、最終的にはサブドメインで切り替えると思うので、ちょっとした徒労感があります。
この設定で問題ないのかかなり不安なので、最終的には色々と見直しをするかもしれませんが、とりあえず動作したので今回はよしとします。