【Docker】.Net Coreアプリのコンテナ化

# 1. はじめに
この記事では

- .Net CoreでサンプルWeb APIを作成し
- Dockerを使ってコンテナ化し
- ブラウザからAPIに接続する

ための手順を解説します。Webアプリケーションでも手順はほぼ同じです。
実際に手を動かしてみてください。

Dockerがどんなものかのなんとなくのイメージを他記事で掴んでから見るといいと思います。

[公式ドキュメント](https://docs.microsoft.com/ja-jp/dotnet/core/docker/build-container?tabs=windows)には、コンソールアプリケーションのコンテナ化のチュートリアルがあります。

## 必須コンポーネント

- [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download)
現在どの SDK を使っているか確認するには、ターミナルで`dotnet --info` コマンドを使います。必ず3.1以上にしてください。

- [Docker Community Edition](https://www.docker.com/products/docker-desktop)
Dockerをインストールしていない人はここから
# 2. サンプルWeb APIの作成
まずはAPIを作成しますが、ここが分からない人がコンテナ化しようとはしないと思うのでさらっと流します。
デプロイしたいAPIやアプリがある場合は、3. から読んでください。

1.　Visual Studioの立ち上げ

2.　新規プロジェクトの作成

3.　ASP.NET Core Webアプリケーションを選択

4.　プロジェクト名の命名（ここでは**SampleApi**としています）

5.　APIを選択
ここでAPIが作成されます。すでにサンプルAPIができていて、天気予報を返すAPIのようです。
起動すると
https://localhost:44315/weatherforecast
へ接続され、以下の天気予報のjsonが返ってきます。

```json
[{"date":"2020-05-16T07:27:11.1199412+00:00","temperatureC":-2,"temperatureF":29,"summary":"Mild"},{"date":"2020-05-17T07:27:11.1233617+00:00","temperatureC":-4,"temperatureF":25,"summary":"Hot"},{"date":"2020-05-18T07:27:11.1233692+00:00","temperatureC":-14,"temperatureF":7,"summary":"Mild"},{"date":"2020-05-19T07:27:11.1233696+00:00","temperatureC":25,"temperatureF":76,"summary":"Balmy"},{"date":"2020-05-20T07:27:11.1233697+00:00","temperatureC":25,"temperatureF":76,"summary":"Bracing"}]
```


6.　Web APIの発行
上のツールバーからビルド→SampleApiの発行をクリック
発行先の選択でフォルダーを選択してプロファイルを作成ボタンをクリック
発行ボタンをクリック
`SampleApi/bin/Release/netcoreapp3.1/publish/`ディレクトリに`SampleApi.dll`など、その他ファイルが発行されていることを確認します。

# 3. Web APIのコンテナ化
作業の流れは以下です。

1. Dockerfileの作成
2. Dockerfileを用いてコンテナイメージを作成
3. コンテナの作成・起動

## 1. Dockerfileの作成 と 2. コンテナイメージの作成
**" .csproj" が含まれるディレクトリに** "Dockerfile" という名前のファイルを作成します。これは拡張子のないただのDockerfileというファイルです。
このDockerfileをテキストエディタで開き、以下のように記述します。

``` Dockerfile:Dockerfile
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
```

‘`mcr.microsoft.com/`はMicrosoft Container Repository(MCR)を指しており、Microsoft公式のDocker Hubです。
そこの`dotnet/core/`にある`aspnet`というコンテナイメージのバージョン`3.1`を取ってくるという感じです。

この状態で一度ターミナルで**Dockerfileがあるリポジトリに移動し**、以下のコマンドを入力しましょう。
以降の処理は必ずDockerfileのあるディレクトリで行ってください。

```
docker build -t sample-image -f Dockerfile .
```
このコマンドによって、Docker により Dockerfile 内の各行が処理されます。

- `-t sample-image`は、イメージ（正しくはリポジトリ名）にはsample-imageという名前を付けてね。
- `-f Dockerfile`は、Dockerfileというの名前のファイルを実行してね。（先ほど作ったDockerfile名と一致させる）
- `.`は現在のフォルダで検索してね。

という意味です。

このコマンドが終了したら`docker images`を実行し、以下のように2つのイメージがあることを確認します。

```
docker images
REPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
sample-image                           latest              e6780479db63        4 days ago          190MB
mcr.microsoft.com/dotnet/core/aspnet    3.1                 e6780479db63        4 days ago          190MB
```
IMAGE IDが2つとも被っています。これは言ってしまえば、ただ名前をsample-imageにしただけでなにも変わっていないからです。

ここで再びDockerfileをテキストエディタで開き、2行目以降に以下の記述を追加しましょう。

```Dockerfile:Dockerfile
COPY bin/Release/netcoreapp3.1/publish/ App/
WORKDIR /App
ENTRYPOINT ["dotnet", "SampleApi.dll"]
```
- 1行目は、現在の作業ディレクトリ下の`bin/Release/netcoreapp3.1/publish/`（サンプルAPIが発行された場所）を**コンテナ内の**`/App`フォルダにコピーしてね。
- 2行目は、**コンテナ内の**作業ディレクトリを`/App`に変更してね。
- 3行目は、**コンテナ内の**現在のフォルダで、dotnetコマンドでSampleApi.dllを起動してね。

という意味です。

もう一度`docker build -t sample-image -f Dockerfile .`を実行し、`docker images`を実行しましょう。
すると以下のようになります。

```
docker images
REPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
sample-image                           latest              cd11c3df9b19        41 seconds ago      190MB
mcr.microsoft.com/dotnet/core/aspnet    3.1                 e6780479db63        4 days ago          190MB
```

IMAGE IDが変わっていることが分かると思います。
`mcr.microsoft.com/dotnet/core/aspnet`は公式が配布している.Net Coreアプリのためのコンテナイメージで、それに自分のAPIを載せたコンテナイメージがsample-imageです。

## コンテナの作成・起動

コンテナの作成と起動は、`docker create`と`docker start`で行いますが、`docker run`とすると2つとも一気にやってくれます。
また、`docker run`でしか使えないオプションを使うのでこちらを用いましょう。

以下のコマンドを実行します。

```
docker run -d -p 80:80 --name sample-container
```

- `-d`はバックグラウンドで実行してね。
- `-p 80:80`は自分のPCの80番ポートと起動したコンテナの80番ポートを接続してね
- `--name sample-container`は作成・起動するコンテナにはsample-containerと名付けてね

という意味です。

## APIへの接続

これでコンテナが起動し、localhostの80番ポートに接続したため、
http://localhost/weatherforecast/
へ接続するとAPIの実行結果が返ってきます。

```json
[{"date":"2020-05-16T07:27:11.1199412+00:00","temperatureC":-2,"temperatureF":29,"summary":"Mild"},{"date":"2020-05-17T07:27:11.1233617+00:00","temperatureC":-4,"temperatureF":25,"summary":"Hot"},{"date":"2020-05-18T07:27:11.1233692+00:00","temperatureC":-14,"temperatureF":7,"summary":"Mild"},{"date":"2020-05-19T07:27:11.1233696+00:00","temperatureC":25,"temperatureF":76,"summary":"Balmy"},{"date":"2020-05-20T07:27:11.1233697+00:00","temperatureC":25,"temperatureF":76,"summary":"Bracing"}]
```

# 4. さいごに
業務で使う機会があり、今どきdockerが使えないのはまずいので使えるようにしました。
Dockerがどんなものかイメージがついていないと分かりにくいと思うのでそこは他の記事で補完してください。

ご質問等あればお気軽にどうぞ。
Twitter → [@ruemura3](https://twitter.com/ruemura3)