ODBC ドライバーに依存した ASP.NET Framework アプリを Azure App Service に移行する


#はじめに
（本記事は2020年10月の情報をもとに作成されています）
オンプレにある既存の社内システム等をクラウド移行する際に検討することの1つとして、IaaS に移行するか PaaS に移行するかの選択があると思います。IaaS と PaaS ともにメリットや制約がある中で PaaS を採用し、ビジネスを進める判断をすることも少なくないと思います。しかしながら、アプリが OS の機能等に深く依存している場合など、PaaS にアプリを移行できず、IaaS 上の仮想マシン等に移行せざるを得ないことも考えられます。そこで解決策の一つとして、アプリをコンテナ化して、OS 依存の部分をコンテナに入れ込み、PaaS でコンテナを運用することを考えてみます。
Azure の App Service では、Windows コンテナのサポートは長らく Preview として提供されましたが、[Ignite 2020 の発表](https://news.microsoft.com/ignite-2020-book-of-news/#142-azure-app-service-updates-include-new-cost-savings-options-windows-container-support-github-actions-integration)で、App Service の Windows コンテナサポートが一般提供（GA）となったので、今回はこちらを利用して、オンプレで稼働している社内システムの Azure PaaS への移行例を考えてみたいと思います。


今回は以下の画像のように、オンプレ環境で稼働する IIS サーバ上の ODBC に依存した ASP.NET Framework アプリを、アプリの変更を最小限に Azure の PaaS である App Service（Webapp）に移行する例を取り上げます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/33a7dbf1-dc2d-8ca9-0ebd-b14c2bb7ebcb.png)


#既存の ASP.NET Framework アプリをコンテナ化する
現在持っている ASP.NET Framework アプリを Visual Studio で開発している場合、簡単な手順を踏むだけでアプリを Windows コンテナ化することができます。Visual Studio 2019・Visual Studio 2017（バージョン15.7以降）をお使いの場合は、Visual Studio Installer で必要なコンポーネントを入れ、 Docker Desktop を用意するだけで Docker サポートを利用可能です。（詳細は https://docs.microsoft.com/ja-jp/visualstudio/containers/overview?view=vs-2019 ）余談ですが、ASP.NET Framework アプリは Linux コンテナには対応しておらず、Windows コンテナのみ利用できます。
実際に Docker サポートを利用する際は、以下の画像のように、コンテナ化したい ASP.NET Framework プロジェクトを開き、ソリューションエクスプローラーから Docker サポートを追加する操作をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/00b48d33-1621-fe36-b1bb-46a4fb781e74.png)

Docker サポートを追加すると、Docker for Windows の起動チェックが入り、起動していない場合や Linux コンテナが起動している場合は Windows コンテナを起動させます。その後、プロジェクト内に以下のような Dockerfile が自動生成され、Docker コンテナのイメージ作成の準備は完了します。

```dockerfile:Dockerfile
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019
ARG source
WORKDIR /inetpub/wwwroot
COPY ${source:-obj/Docker/publish} .
```

この時点で、ASP.NET Framework アプリの Windows コンテナ化が完成しているのですが、この状態ではただアプリが Windows で動いているだけなので ODBC に依存したアプリはデータベースへ接続できません。次に ODBC ドライバーをコンテナ内にインストールする処理を Dockerfile 内に追加します。手元の Windows 等では以下のような Powershell の Add-OdbcDsn 等を用いて、ODBC のインストールをすると思いますが、Dockerfile 上でその処理をそのまま書くとうまく動かずハマるので注意が必要です。

```powershell:Powershell
Add-OdbcDsn -Name "DSNNAME" -DriverName "PostgreSQL Unicode" -DsnType "User" -Platform "32-bit" -SetPropertyValue @("Server=SERVERNAME.com","Database=DBNAME","SSLMode=require","Username=SOMEONE")
```

以下が、実際の Dockerfile での記述例です。RUN コマンドで Powershell を指定し -command の後ろに通常の Powershell コマンドを実行する方法ではなく、`SHELL ["powershell", "-command"]` を利用して `RUN` コマンドから直接 Powershell コマンドを書くようにするとエラー無くイメージ作成が可能です。

```dockerfile:Dockerfile
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019
ARG source
WORKDIR /inetpub/wwwroot
COPY ${source:-obj/Docker/publish} .

SHELL ["powershell", "-command"]

#PostgreSQL 対応 ODBC ドライバーのダウンロード
ADD https://ftp.postgresql.org/pub/odbc/versions/msi/psqlodbc_12_01_0000-x86.zip /
ADD https://ftp.postgresql.org/pub/odbc/versions/msi/psqlodbc_12_01_0000-x64.zip /

#zip ファイルの展開とドライバーのインストール
RUN Expand-Archive -Path c:\psqlodbc_12_01_0000-x86.zip -DestinationPath c:\odbc\ ; \
    Start-Process c:\odbc\psqlodbc_x86.msi -Wait
RUN Expand-Archive -Path c:\psqlodbc_12_01_0000-x64.zip -DestinationPath c:\odbc64\ ; \
    Start-Process c:\odbc64\psqlodbc_x64.msi -Wait

#RUN powershell -command を利用するとパラメータ指定の部分でエラーとなる
#RUN powershell -command Add-OdbcDsn -Name "DSNNAME" -DriverName "PostgreSQL Unicode" -DsnType "User" -Platform "32-bit" -SetPropertyValue @("Server=SERVERNAME.com","Database=DBNAME","SSLMode=require","Username=SOMEONE")

#32bit
RUN Add-OdbcDsn -Name 'DSNNAME' -DriverName 'PostgreSQL Unicode' -DsnType 'System' -Platform '32-bit' -SetPropertyValue @('Server=SERVERNAME.com','Database=DBNAME','SSLMode=require','Username=SOMEONE')
#64bit
RUN Add-OdbcDsn -Name 'DSNNAMEx64' -DriverName 'PostgreSQL Unicode(x64)' -DsnType 'System' -Platform '64-bit' -SetPropertyValue @('Server=SERVERNAME.com','Database=DBNAME','SSLMode=require','Username=SOMEONE')
```
あとは、ビルドを実施しローカルでコンテナアプリが実行されることが確認できると思います。

#コンテナ化したアプリをコンテナレジストリにアップロードし App Service で公開
ODBC ドライバーに依存した ASP.NET Framework アプリをコンテナ上で実行することができましたので、アプリを PaaS である App Service にデプロイする準備をします。今回は、コンテナのイメージを Azure Container Registry にプッシュし、そこから App Service へ自動デプロイがされるように構成します。（もちろん、イメージのプッシュ先を Docker Hub にしても同様のことが実現できます）
コマンドラインで Docker コマンドから Azure Container Registry へイメージをプッシュしても良いのですが、今回は Visual Studio を利用して Azure Container Registry へコンテナイメージをプッシュします。

ソリューションエクスプローラーで、コンテナ化するアプリのプロジェクトを右クリックし、メニューから「発行…」を選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/e60f30e8-9af1-c4d1-1938-6b583d8988e0.png)

次に発行先として Docker Container Registry をクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/05747037-24c6-50e9-4646-11225ec259f0.png)

Azure コンテナレジストリーを選択し、イメージをプッシュしたい Azure Container Registry をお持ちのサブスクリプションの中から選択してください。ここでは、Microsoft アカウントのログイン等が求められる場合があります。また、お持ちの Azure サブスクリプションに Azure Container Registry が無い場合は、Azure ポータル上や Visual Studio 上で作成してください。(Azure Container Registry の作成方法はこちら： https://docs.microsoft.com/ja-jp/azure/container-registry/container-registry-get-started-portal )
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/a0f50dbd-6d94-7f87-2fd6-158e82efb33e.png)

Azure Container Registry へイメージをプッシュする準備ができましたら、「発行」ボタンを押し、イメージのプッシュを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/4369e7d4-683e-085a-df49-6cfff96a6139.png)

次に、実際にアプリを動かす App Service を作成します。[Ignite 2020 の発表](https://news.microsoft.com/ignite-2020-book-of-news/#142-azure-app-service-updates-include-new-cost-savings-options-windows-container-support-github-actions-integration)で Windows コンテナサポートが Premium V3 SKU でサポートされたとのことですので、今回はそちらを利用したいと思います。(App Service
関連のアップデートの詳細については[こちら](https://techcommunity.microsoft.com/t5/apps-on-azure/migrate-modernize-net-applications-with-azure/ba-p/1696499)をご参照ください)
ポータル上で App Service の作成を選択し、OS が Windows の Docker コンテナーを作成する設定を選択してください。Preview 期間中は PC2～PC4 と呼ばれる Windows コンテナ用の App Service Plan SKU があったのですが、今回のアップデートで他と同じ Premium V3 SKU を選択するようになっています。（逆に Windows コンテナは Premium V3 インスタンスでしか現在作成できません。検証などは11月から設定される Dev/Test 価格を利用すると価格を抑えつつ検証が可能かと思われます。）
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/ab26cf00-d36f-d806-ed1b-646765f6f99f.png)

次の Docker タブでは、App Service で動かすコンテナのイメージソースを指定します。今回は先ほど作成した Azure Container Registry を指定してください。あとは既定の設定で App Service をデプロイしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/098c1c59-aa43-a615-ba8a-2d231573d3fe.png)

App Service のデプロイ後、ポータルの「コンテナーの設定」から、App Service でホストするコンテナのイメージを指定できます。また、「継続的なデプロイ」をオンにすると、イメージが更新されるたびに App Service で動くコンテナのイメージも自動的に更新できるように設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161850/158af626-c92f-b45d-3043-bb50ba848fa0.png)

これで、ODBC ドライバーに依存した ASP.NET Framework アプリを App Service 上で動かすことができました。



#おわりに
今回は、App Service Premium V3 SKU のインスタンスを利用し、ODBC ドライバーに依存した ASP.NET Framework アプリを Windows コンテナとして動かしました。既存のシステムをクラウドへ移行する手段として柔軟性や経済性に優れている PaaS を利用し、コンテナで動かすといったことが選択肢に考えられるようになったのは良いニュースだと思いました。
また App Service Premium V3 SKU では、リージョン VNET 統合や、Private Link といったアプリを閉域環境で動かすオプションも利用できますので、そちらも検討いただければと思います。

（本記事は2020年10月の情報をもとに作成されています）