ASP.Net coreの開発環境をDockerで作成する

## 経緯
APIを c#で作成したいと思い立ち、フレームワークである.Net Coreを使用しAPI開発をしようと思ったのがやり始めたきっかけです。

.Net CoreでAPI開発をしようとしていて、Dockerの開発環境を作成したいと考えている方の参考になればと思っています。

## はじめに
今回の記事では、

1. .Net Coreの開発環境をDockerfileを記述し作成する。
2. リアルタイムでコードの変更が反映されるようにする。
3. Dbコンテナも作成し、接続する。
4. apiを叩いて動作確認。

おまけ. マルチステージビルドで軽量化イメージを作成する。

という流れで解説します。

## Dockerfileの作成

今回は、便宜上ファイル名をDockerfile.developとさせていただきます。
また、自分のプロジェクト名はapiMyAppです。

```Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:5.0
WORKDIR /src
COPY apiMyApp.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet dev-certs https --clean && dotnet dev-certs https -t
```
ここでは、dotnetコマンドを使用するため、mcr.microsoft.com/dotnet/sdk:5.0 をベースイメージとします。
また、ディレクトリをsrcに移動し、ローカル内のcsprojファイルをコンテナ内にコピーします。
その後、csprojファイルをもとに、dotnet restoreコマンドで必要なパッケージをダウンロード。
その後、ローカルにあるプロジェクトファイル全てをコンテナ内に移動させます。
最後は、api通信を開発環境で行うためのコマンドを打ちます。(ニュアンスが違ってましたらすいません。)

これで、Dockerfileの完成です。

次はdocker-compose.ymlファイルです。

## docker-compose.ymlの作成
docker-compose.ymlファイルを作成します。

```docker-compose.yml
version: '3.8'
services:
  app:
    container_name: net-app
    build:
      context: .
      dockerfile: Dockerfile.develop
    ports:
      - 5000:5000
      - 5001:5001
    networks:
      - net-net
    depends_on:
      - db
    volumes:
      - .:/src
    command: dotnet watch run

  db:
    container_name: net-db
    platform: linux/x86_64
    image: mysql:5.7
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: mysql
      MYSQL_USER: user
      MYSQL_PASSWORD: secret
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/init:/docker-entrypoint-initdb.d
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    networks:
      - net-net

networks:
  net-net:
    driver: bridge

```

.Net Coreのコンテナ名をnet-app、Databaseのコンテナ名をnet-dbと今回は設定しています。

ここで、ホットリロードの設定を行っているのが、net-appコンテナ内の

```docker-compose.yml
    volumes:
      - .:/src
    command: dotnet watch run
```

の部分です。

* volumesで、ローカルのコードと、コンテナ内のコードを同期させる。
* commandsで、コンテナが立ち上がった際にホットリロードできるコマンドをうつ。

この二つ書いておけば、コンテナが立ち上がった際にプロジェクトが起動し、開発中はホットリロードされます。

DBコンテナも記述していますが、おのおのc#のコード内で接続できるよう記述してみてください。
詳しくは記述しませんが、.Net CorからDbコンテナに繋げる際、苦労した点としては、serverの部分がlocalhostでなくコンテナ名　を記述してやらないと繋がらなかったところです。(本題とは外れるので飛ばします。)

DB接続できたら、api通信できているかどうか確認してみてください。

### マルチステージビルド
最後に、本番環境ようの軽量イメージをマルチステージビルドを使用して作成します。

マルチステージビルドをすることによって、プロジェクトの規模にもよりますが、
1GB → 400MB ぐらいまで軽量化することができました。

以下、Dockerfileです。

```Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY apiMyApp.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT [ "dotnet", "apiMyApp.dll" ]
```

順番に説明すると、
AS baseの部分では、.net coreのアプリを実行できるイメージを取得しているステージです。

AS buildでは、プロジェクトをビルドするステージです。

最後に、AS finalでは、AS baseで作成した実行環境とAS buildで作成したビルドを使用してアプリを動かすステージです。

このようにステージを分けることでイメージの大きさを小さくし、本番環境むきのイメージを作成することができます。

### 最後に
c#レベルのプレーンなプログラミング言語に触れた方が他の言語への移りが容易になるんじゃないかと思ってます。

### 参考
https://www.youtube.com/watch?v=ZXdFisA_hOY&t=8832s

https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/net-core-net-framework-containers/official-net-docker-images