ASP.NET Core コンテナで WebApp を作り、コンテナ外からアクセスする

ASP.NET Core SDK コンテナを動かす でコンテナ内にソーステンプレートを作成することができるところまでは確認できた。 今回はテンプレートから Web アプリを動かし、コンテナ外からアクセスしてみる。

今回はまだ外部のドライブをマウントせず、内部で変更をしてみるだけ。 基本的なコマンドの説明は

にまとめた。

参考:

外部からアクセスできるようにポート引数を加える

コンテナ内部で作成した WebApp に外部からアクセスできるように、ポート設定の引数を設定する。 転送するポートは今回のチュートリアルの設定を使う。

Once the command completes, browse to http://localhost:5000

5000 を利用するらしいのでコンテナ外の 5000 とコンテナ内の 5000 をつなげることにした。 よって、

$ docker run --rm -it -p 5000:5000 dotnetsdk3.1alpine3.12 
/ #

このように実行した。

チュートリアルに沿ってアプリを作成する

前回同様に /home 以下にディレクトリを作ってその中でテンプレートからプロジェクトを生成する。 今回は webApp というテンプレートを利用するらしい。

Create your app

In your terminal, run the following commands:

dotnet new webApp -o myWebApp --no-https
cd myWebApp

この引数に関しての解説は以下

What do these commands mean?

The dotnet new command creates a new application.

  • The webApp parameter selects what template to use when creating your app.
  • The -o parameter creates a directory named myWebApp where your app is stored.
  • The --no-https flag specifies not to enable HTTPS.

The cd myWebApp command puts you into the newly created app directory.

webApp
webApp というテンプレートを利用する
-o myWebApp
myWebApp というディレクトリをコマンドを実行したディレクトリの下に作成し、そこにプロジェクトを生成する
--no-https
https 機能を有効化しない

また、生成されたプロジェクトに関しても簡単な解説が入っている。

What files were created?

Several files were created in the myWebApp directory, to give you a simple web application that is ready to run.

  • Startup.cs contains all the settings and configurations.
  • The myWebApp/Pages directory contains some example web pages for the application.
  • myWebApp.csproj defines what libraries are referenced etc.
Startup.cs
プロジェクトの全ての設定が入っている
myWebApp/Pages
アプリケーション向けにいくつかのサンプルページが入っている
myWebApp.csproj
どのライブラリを参照するか定義している

ではこのコードを内部で実行してみる。 既にコンテナは動作しているので、

# cd home/
/home # dotnet new webApp -o myWebApp --no-https
Getting ready...
The template "ASP.NET Core Web App" was created successfully.
This template contains technologies from parties other than Microsoft, see https://aka.ms/aspnetcore/3.1-third-party-notices for details.

Processing post-creation actions...
Running 'dotnet restore' on myWebApp/myWebApp.csproj...
  Determining projects to restore...
  Restored /home/myWebApp/myWebApp.csproj (in 150 ms).

Restore succeeded.

テンプレートの生成ができた。 myWebApp に移動する

/home # cd myWebApp
/home/myWebApp #

アプリを実行してアクセスしてみる

In your terminal, run the following command:

dotnet run

Once the command completes, browse to http://localhost:5000

動作させてみる

# dotnet run
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Address not available'.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/myWebApp

http://localhost:5000 にアクセスしてみるが、繋がらない。

接続エラーになる。

念の為、ホストマシンからcurlで確認してみましょう。 Empty reply from server エラーです。

$ curl 'http://localhost:8000/'
curl: (52) Empty reply from server

やってみると確かに Empty reply from server エラーになる。

$ curl localhost:5000
curl: (52) Empty reply from server

このページに原因らしきものと解決策も載っていた。

tl;dr

(問題)
webアプリをdockerで立ててアクセスしたら ERR_EMPTY_RESPONSE エラーになった
(原因)
containerの外からリクエストが来るのにアプリがlocalhostでLISTENしている
(解決)
アプリの設定を0.0.0.0でLISTENするよう変更する

では 0.0.0.0 からのリクエストを処理するように変更すればよさそうだ。

ホスト側からアクセス可能にする為”微調整”

これからコンテナ側でビルド&実行するWebアプリケーションを、 ホスト側(つまり外部マシン)からアクセス可能とする修正を行います。 dotnet new -t Web で自動生成されたソース中の「Program.cs」ファイルに「.UseUrls(“http://0.0.0.0:5000”)」の1行を追記します。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .UseUrls("http://0.0.0.0:5000")  // 追記!!!
                .Build();

            host.Run();
        }
    }
}

dotnet restore / run

dotnet restoredotnet run コマンドを実行します。

dotnet restore
dotnet run

restoreは、このアプリケーションに必要な依存関係ファイルを、プロジェクト内にリストアします。 runは、このアプリケーションをビルド&実行します(ビルドだけ行う場合は dotnet build とします)。

これをやってみる。まずは Program.cs を編集する。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace myWebApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder
		    .UseStartup<Startup>()
		    .UseUrls("http://0.0.0.0:5000"); //追加
                });
    }
}

そしたら dotnet restoredotnet run をやってみる。

# dotnet restore
  Determining projects to restore...
  All projects are up-to-date for restore.
/home/myWebApp # dotnet run
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://0.0.0.0:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/myWebApp

受け付けるアドレスが http://localhost:5000 から http://0.0.0.0:5000 に変化している。 いけそうな気がする。

接続できた!