Docker 環境で C# ASP.NET Core Webサービスを起動する

# Docker 環境で C# ASP.NET Core Webサービスを起動する

こんにちは、@studio_meowtoon です。今回は、WSL Ubuntu 24.04 の Docker 環境で C# ASP.NET Core Web アプリケーションをコンテナーとして起動する方法を紹介します。
![aspnet-core_on_docker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/23ef4a38-d739-71e2-43fa-4c7d549ab105.png)

## 目的

Windows 11 の Linux でクラウド開発します。

こちらから記事の一覧がご覧いただけます。

https://qiita.com/studio_meowtoon/items/6119ab05d8b13527efd8

## 実現すること

ローカル環境の Ubuntu の Docker 環境で、Dockerfile からビルドした C# ASP.NET Core Web サービスのカスタムコンテナーを起動します。

**DLL ファイル形式のアプリをコンテナーとして起動**
```mermaid
flowchart LR
    terminal --> kestrel
    subgraph Ubuntu
        subgraph Docker
            subgraph container[app-hello-aspnet-core]
                subgraph dotnet
                kestrel <--> app[WebApp.dll]
                end
            end
        end
    end
style Ubuntu fill:#FFBCA4, stroke:#E0460F
style Docker fill:#EEFDFF, stroke:#74B9DC
style dotnet fill:#DCFFDC, stroke:#2F872F
style container fill:#FFD7E4, stroke:#E13C73
style app fill:#ECECFF, stroke:#9674DC
style kestrel fill:#FFFFDE, stroke:#B4AE43
```

**実行環境**

|要素|概要|
|:--|:--|
|terminal|ターミナル|
|Ubuntu|OS|
|Docker|コンテナー実行環境|

**Web サービス コンテナー**

|要素|概要|
|:--|:--|
|app-hello-aspnet-core|カスタムコンテナー|
|dotnet|.NET 実行環境|
|kestrel|Web サーバー|
|WebApp.dll|.NET アプリケーション|

## 技術トピック

### Dockerfile とは？

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [Dockerfile](https://docs.docker.jp/engine/reference/builder.html#dockerfile)

:::note info
Dockerfile は、Docker コンテナーを構築するためのテキストファイルです。Docker コンテナーはアプリケーションやサービスを実行するための環境を含む軽量でポータブルな仮想化ユニットです。

|キーワード|内容|
|:--|:--|
|スクリプト形式|Dockerfile はシンプルなスクリプト形式で記述されるため、コンテナーのビルドプロセスを自動化することが容易です。|
|レイヤー構造|Docker イメージは Dockerfile の各命令が実行される際にレイヤーとして生成され、再利用やキャッシュが可能な構造となっています。|
|バージョン管理|Dockerfile はテキストベースであるため、コードと同様にバージョン管理システムで管理しやすいです。|
|ポータビリティ|Dockerfile により、アプリケーションとその依存関係が1つのコンテナーイメージにパッケージ化されるため、異なる環境間での移植性が高まります。|
|自動化と効率化|Dockerfile を使用することで、アプリケーションのビルドや環境構築を自動化できます。これにより、手動での作業時間やヒューマンエラーが減り、開発・デプロイプロセスが効率的になります。|
|再現性|Dockerfile はビルド手順を完全に定義するため、異なる環境で同じアプリケーションを再現できます。これにより、開発、テスト、本番環境間での一貫性が確保されます。|
|環境の分離|Docker コンテナーはホストシステムから分離されるため、アプリケーションの依存関係やライブラリの衝突を回避し、より安全な環境で実行できます。|
|拡張性|Dockerfile を使用することで、カスタムイメージを作成できます。このため、特定のニーズに合わせてカスタマイズされたコンテナーイメージを容易に作成できます。|
:::

</details>

## 開発環境

+ Windows 11 Home 23H2 を使用しています。

:::note info
[WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作しますので macOS の方も参考にして頂けます。  
:::

<details>

WSL (Microsoft Store アプリ版) [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/cd0c4a607d451dbf5430)

```sh
> wsl --version
WSL バージョン: 2.2.4.0
カーネル バージョン: 5.15.153.1-2
WSLg バージョン: 1.0.61
```

Ubuntu [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/cd0c4a607d451dbf5430)

```sh
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04 LTS
Release:        24.04
Codename:       noble
```

.NET SDK [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/d68031c91462f6808dff)

```sh
$ dotnet --list-sdks
8.0.107 [/usr/lib/dotnet/sdk]
$ dotnet --version
8.0.107
```

Docker [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/3bceee25ac67cc73ebbe)

```sh
$ docker --version
Docker version 27.0.3, build 7d4bcd8
```

</details>

:::note warn
この記事では基本的に **Ubuntu のターミナルで操作**を行います。**Vim を使用してコピペする方法**をはじめて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
:::

https://qiita.com/studio_meowtoon/items/7771ad48676926e41463

## 作成する Web アプリケーションの仕様

|No|エンドポイント|HTTPメソッド|MIME タイプ|
|:--|:--|:--|:--|
|1|/api/data|GET|application/json|

:::note info
**/api/data** というエンドポイントに対して HTTP GET リクエストを送信すると、JSON データがレスポンスされるシンプルな Web サービスを実装します。
**{"message":"Hello World!"}**
:::

## Hello World を表示する手順

### C# ASP.NET Core Web サービスの作成

こちらの関連記事で手順がご確認いただけます。

https://qiita.com/studio_meowtoon/items/1cdc65e5c6d24cc6128d

### プロジェクトフォルダーに移動

プロジェクトフォルダーに移動します。  
※ ~/tmp/WebApp をプロジェクトフォルダーとします。

```sh
$ cd ~/tmp/WebApp
```

### 設定ファイルの修正

ログ出力の書式を修正します。

```sh
$ vim appsettings.json
```

ファイルの内容

```json:appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft.AspNetCore": "Debug"
    },
    "Console": {
      "LogLevel": {
          "Default": "Debug",
          "Microsoft.AspNetCore": "Debug"
      },
      "FormatterName": "simple",
      "FormatterOptions": {
          "SingleLine": true,
          "TimestampFormat": "yyyy-MM-dd HH:mm:ss,fff "
      }
    }
  },
  "AllowedHosts": "*"
}
```

### アプリのビルド (※ 参考)

:::note warn

以下のコマンドで .NET アプリをビルドできます。
※ bin/Release/net8.0/WebApp.dll が作成されます。

下のコンテナーイメージをビルドする際には、同時にアプリもビルドされます。そのため、こちらのビルドコマンドは必須ではありません。

```sh
$ dotnet build \
    --configuration Release \
    --no-restore
```

ここまでの手順で、ローカル環境の **Ubuntu** に **DLL ファイル形式**のアプリをビルドすることができました。※ 実体は拡張子なしの WebApp ファイルになります。
:::

### コンテナーイメージの作成

Dockerfile を作成します。

```sh
$ vim Dockerfile
```

ファイルの内容

:::note info
こちらの Dockerfile は、[**Microsoft** から公開された内容](https://learn.microsoft.com/ja-jp/dotnet/core/docker/build-container?tabs=windows)です。
:::

```Dockerfile:Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
WORKDIR /App

# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "WebApp.dll"]
```

Docker デーモンを起動します。

```sh
$ sudo service docker start
```

:::note warn
Docker 環境をお持ちでない場合は、以下の関連記事から Docker Engine のインストール手順をご確認いただけます。
:::

https://qiita.com/studio_meowtoon/items/3bceee25ac67cc73ebbe

コンテナーイメージをビルドします。

```sh
$ docker build \
    --no-cache \
    --tag app-hello-aspnet-core:latest .
```

コンテナーイメージを確認します。

```sh
$ docker images | grep app-hello-aspnet-core
app-hello-aspnet-core    latest    deb99b026177    9 seconds ago    217MB
```

:::note info
ここまでの手順で、ローカル環境の **Docker** にアプリの**カスタムコンテナーイメージ**をビルドすることができました。
:::

### コンテナーを起動

ローカルでコンテナーを起動します。  
※ コンテナーを停止するときは ctrl + C を押します。

```sh
$ docker run --rm \
    --publish 8080:8080 \
    --name app-local \
    app-hello-aspnet-core
```

:::note info
ここまでの手順で、ローカル環境の **Docker** でアプリの**カスタムコンテナー**を起動することができました。
:::

### コンテナーの動作確認

別ターミナルから curl コマンドで確認します。

```sh
$ curl -v http://localhost:8080/api/data -w '\n'
```

出力

```sh
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /api/data HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Sat, 17 Aug 2024 02:09:12 GMT
< Server: Kestrel
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
{"message":"Hello World!"}
```

:::note info
ここまでの手順で、ターミナルに **{"message":"Hello World!"}** と表示され、**JSON データ**を取得することができました。
:::

コンテナーの状態を確認してみます。

```sh
$ docker ps
CONTAINER ID   IMAGE                   COMMAND               CREATED              STATUS              PORTS                                       NAMES
ce04d84a4fa5   app-hello-aspnet-core   "dotnet WebApp.dll"   About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   app-local
```

### コンテナーに接続

別ターミナルからコンテナーに接続します。

```sh
$ docker exec -it app-local /bin/bash
```

コンテナー接続後にディレクトリを確認します。
※ コンテナーから出るときは ctrl + D を押します。

```
# pwd
/App
# ls -lah
total 136K
drwxr-xr-x 1 root root 4.0K Aug 17 02:07 .
drwxr-xr-x 1 root root 4.0K Aug 17 02:09 ..
-rwxr-xr-x 1 root root  71K Aug 17 02:07 WebApp
-rw-r--r-- 1 root root  388 Aug 17 02:07 WebApp.deps.json
-rw-r--r-- 1 root root 8.5K Aug 17 02:07 WebApp.dll
-rw-r--r-- 1 root root  21K Aug 17 02:07 WebApp.pdb
-rw-r--r-- 1 root root  469 Aug 17 02:07 WebApp.runtimeconfig.json
-rw-r--r-- 1 root root  119 Jul 17 13:12 appsettings.Development.json
-rw-r--r-- 1 root root  414 Aug 17 01:51 appsettings.json
-rw-r--r-- 1 root root  482 Aug 17 02:07 web.config
```

top コマンドで状況を確認します。

```
# apt update
# apt install procps
# top
top - 02:11:39 up  1:52,  0 user,  load average: 0.03, 0.05, 0.01
Tasks:   3 total,   1 running,   2 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni, 99.9 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  15949.2 total,  14909.3 free,    856.1 used,    475.6 buff/cache
MiB Swap:   4096.0 total,   4096.0 free,      0.0 used.  15093.1 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
      1 root      20   0  262.2g  74728  63060 S   0.0   0.5   0:00.36 dotnet
     42 root      20   0    4188   3472   2964 S   0.0   0.0   0:00.02 bash
    232 root      20   0    8560   4632   2756 R   0.0   0.0   0:00.00 top
```

コンテナーの情報を表示してみます。

```cs
# cat /etc/*-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
```

:::note warn
このコンテナーは Debian GNU/Linux をベースに作成されています。つまり、Debian GNU/Linux と同じように扱うことができます。
:::

## まとめ

WSL Ubuntu の Docker 環境で、Dockerfile からビルドした C# ASP.NET Core Web サービスのカスタムコンテナーを起動することができました。

:::note warn
クラウド開発においては、**Dockerfile の理解**は重要です。自動ビルドツールもありますが、手動で書く必要があるケースもあります。**Ubuntu** を使うと **Linux の知識**も身に付きます。最初は難しく感じるかもしれませんが、徐々に進めていけば自信を持って書けるようになります。
:::

どうでしたか？　WSL Ubuntu で、C# ASP.NET Core Web アプリケーションを Docker 環境でコンテナーとして手軽に起動できます。ぜひお試しください。今後も .NET の開発環境などを紹介しますので、ぜひお楽しみにしてください。

## 推奨コンテンツ

https://qiita.com/studio_meowtoon/items/d3810d7f5329b7d0e831

## 関連記事

#### Java Spring Boot

https://qiita.com/studio_meowtoon/items/9c07e20b4124d8c5f972

## 参考資料

https://learn.microsoft.com/ja-jp/dotnet/core/docker/build-container?tabs=windows