UbuntuにDockerを用いASP.NET Core Webアプリをデプロイする方法

# はじめに
Dockerを学習しており何かアウトプットしてみたいと考えていました。
ちょうど使わなくなったPCがあったためそれにUbuntuをインストールし、Dockerを用いデプロイしてWebサーバを作成してみました。
WebサーバにはASP.NET Core .NET6で作成したWebアプリをデプロイし、他のPCからアクセスできるような環境を構築します。

# 環境
最終的に構築したいのは以下のような環境です。
![4c683c9f-b279-d1f6-321e-0673a6747075.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/7f3464f4-4935-1c21-904f-0c2272c373c3.png)



- **Nginx：** リバースプロキシとして動作し、受け取ったリクエストをASP.NET Core Webアプリケーションに転送する
- **.NET：** Nginxから転送されたリクエストを処理し、必要なデータを取得して結果を返却する
- **Dockerコンテナ：** Nginx、ASP.NET Core WebアプリケーションはそれぞれDockerコンテナとして動作し、Ubuntu 上で実行される
- **クライアントPC：** ユーザーがWebブラウザなどを使用してWebアプリケーションにアクセスするPC(テスト用)

# 環境構築の流れ
以下の流れで進めていきます。

1. Webアプリ作成（開発用PC）
1. DockerCompose.ymlファイルを作成（開発用PC）
1. コンテナ起動確認（開発用PC）
1. DockerHubにDockerイメージをプッシュ(開発用PC)
1. Ubuntuのインストール（サーバ用PC）※本記事では解説しません
1. Dockerをインストール（サーバ用PC）
1. コンテナ起動確認（サーバ用PC）

### 前提
- 開発用PCにDockerDesktopがインストールされていること
- サーバ用PCにUbuntuがインストールされていること

上記を前提として次の章で詳細を説明していきます。


## Webアプリ作成（開発用PC）

①VisualStudio2022を開き新規プロジェクト作成
　今回はASP.NET Core Webアプリのテンプレートを選択し、次へ
![450dfd75-152d-5622-b151-b2a30bb4dbd2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/182b98f2-c4af-50c9-e58c-fa0604d0f8e2.png)


②プロジェクト名を入力して、次へ

③フレームワークの選択画面を以下に注意して、作成

:::note info 
- ”Dockerを有効にする”チェックボックスをONにしておきます
- DockerOSを”Linux”に選択しておきます
:::
![22ecaf48-5767-357d-d31c-28cc8a0678f2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/20cb7da2-9fe7-4f7e-c009-2eb40e922a1c.png)


④プロジェクトが作成されるのでF5キーでデバッグ実行して以下のようなサンプル画面が出ればWebアプリの作成完了
![11366d61-c649-a434-8745-c097f90dc89c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/2cb9fb56-c6b2-ef03-8c7d-f4f2ee44a664.png)


:::note warn 
Docker Desktopを起動していないとエラーになるので起動しておきましょう
:::

また、slnファイルと同階層にDockerFileがあることも確認しておきましょう(いじる必要はありません)
![cfaa93c9-b14f-d469-6e14-b31441a92609.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/27f62573-e93d-d415-53b9-5f57a5dd034c.png)



# DockerCompose.ymlファイルを作成（開発用PC）
開発用PCでDockerCompose.ymlファイルを作成します。
DockerFileと同階層に作成します。
今回はサーバで稼働する.NETアプリへのリクエストをNginxで受け付けるような構成になっていますので、DockerCompose.ymlにNginxと.NETの情報を記述していきます。
また、サーバ用PCからDockerHub経由でDockerイメージをプルするため`your-dockerhub-username/your-webapp-image` にはご自身のDockerHubのユーザ名とイメージ名(任意の名前)を入力してください。
```docker:docker-compose.yml
version: '3.4'

services:
  webapp:
    build:
      context: .
      dockerfile: Dockerfile  
    image: your-dockerhub-username/your-webapp-image:latest
    ports:
      - "8080:80"

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - webapp
```

さらにNginxの設定ファイルを作成します。
こちらもDockerFileと同階層で大丈夫です。
```conf:nginx.conf

events {
    worker_connections 1024;
}

http {
    upstream webapp {
        server webapp:80;
    }

    server {
        listen 80;

        server_name your_domain_or_ip;

        location / {
            proxy_pass http://webapp;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
```

# コンテナ起動確認（開発用PC）
起動前にディレクトリの構造が以下のようになっていることを確認します。
```:ディレクトリ構造
/YourProject
├── docker-compose.yml
├── Dockerfile
├── nginx.conf
└── YourWebApp.csproj
```
コマンドプロンプトを開きプロジェクトファイルがあるディレクトリに移動します。
```:コマンドプロンプト
cd /path/to/YourProject
```
さらに以下を実行します。
これによりコンテナがバックグラウンドで起動しリクエストを待ち受ける状態になります。
```:コマンドプロンプト
docker-compose up --build -d
```

次にブラウザにて以下を開きます。
```
http://localhost:8080
```
VisualStudioでデバッグ実行で表示された画面と同じ画面が表示されていれば正しくコンテナが起動できています。
![11366d61-c649-a434-8745-c097f90dc89c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/c02eba79-2376-8411-424e-428b82c2c3eb.png)


# DockerHubにDockerイメージをプッシュ(開発用PC)
開発用PCにてDockerの起動が確認できたところで、サーバ用PCで同じDockerイメージをプルするためにDockerHubにプッシュしておきます。

```:イメージのビルド
docker build -t your-dockerhub-username/your-webapp-image:latest .
```
```:Docker Hub にログイン
docker login
```
```:イメージのプッシュ
docker push your-dockerhub-username/your-webapp-image:latest
```
以上で開発用PCでの作業は完了です。
以降はサーバ用PCでの作業となります。

# Ubuntuのインストール（サーバ用PC）
本記事では解説しませんが、サーバ用PCにUbuntuをインストールします。
私は以下の記事を参考にしました。
下記記事以外にもいろいろあると思うので各自わかりやすい記事を参照すればいいと思います。

https://zenn.dev/himura/articles/ac77dc4853bbb7

# Dockerをインストール
サーバ用PC(Ubuntu)にてDockerのインストールを行います。
以下のコマンドを実行します。

```:Dockerのインストール
sudo apt update
sudo apt install docker.io
```
```:Dockerのサービスを起動し、ブート時に自動起動するように設定
sudo systemctl start docker
sudo systemctl enable docker
```
```:Docker Composeのインストール
sudo apt install docker-compose
```

続いてプロジェクトディレクトリを作成し、カレントディレクトリを作成したディレクトリに移動させます。

```:プロジェクトディレクトリの作成
mkdir ~/YourProject
```
```:カレントディレクトリの移動
cd ~/YourProject
```

続いてdocker-compose.yml ファイルの作成を行います。

```:docker-compose.yml ファイルの作成
nano docker-compose.yml
```
上記コードを実行すると`nano`というエディタが開くので↓のコードを貼り付けてCtrl + O(保存)　⇒　Enter　⇒　Ctrl + X(終了)
```:docker-compose.yml
version: '3.4'

services:
  webapp:
    image: your-dockerhub-username/your-webapp-image:latest
    ports:
      - "8080:80"

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - webapp
```

:::note info 
開発用PCで作成したdocker-compose.yml ファイルとの違いは、以下の部分が無くなっている点です。
```
build:
context: .
dockerfile: Dockerfile
```
開発用PCにおいてこの部分は、DockerFileからイメージを作成するというコードでしたが、
サーバ用PCではイメージはDockerHubからプルしてくるので上記の部分は不要となります。
:::

続いてnginx.conf ファイルの作成を行います。
```:nginx.conf ファイルの作成
nano nginx.conf
```
上記コードを実行すると`nano`というエディタが開くので↓のコードを貼り付けてCtrl + O(保存)　⇒　Enter　⇒　Ctrl + X(終了)
これは開発用PCで作成したnginx.conf ファイルと全く同じコードです。
```:nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream webapp {
        server webapp:80;
    }

    server {
        listen 80;

        server_name your_domain_or_ip;

        location / {
            proxy_pass http://webapp;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
```

続いてDockerHubにログインしイメージをプルします。
`your-dockerhub-username/your-webapp-image` にはご自身のDockerHubのユーザ名とイメージ名(開発用PCでプッシュしたときの名前)を入力してください。
```:
docker login
docker pull your-dockerhub-username/your-webapp-image:latest
```

# コンテナ起動確認（サーバ用PC）

最後にDocker Compose を使用してコンテナを起動
これによりコンテナがバックグラウンドで起動しリクエストを待ち受ける状態になります。

```:docker-composeでコンテナ起動
docker-compose up -d
```

開発用PCからサーバ用PCにアクセスしちゃんとデプロイされているかを確認します。
```:開発用PCブラウザからアクセス
http://your_domain_or_publicip:8080
```
VisualStudioでデバッグ実行で表示された画面と同じ画面が表示されていれば正しくサーバ用PCでもコンテナが起動できています。
![11366d61-c649-a434-8745-c097f90dc89c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/d0e2dc40-1ee8-1f6a-4aff-e191997d1ba6.png)


# まとめ
初めてLinuxにデプロイしてみましたが、Dockerを使用すれば思いのほか簡単でした。
本当はSQLServerからデータを取得して表示させるWebアプリを作成したのですが、DB周りも含めると記事が長くなりすぎるため割愛しました。
次回はDB周りも含めた記事を投稿したいです。