tekitoumemo’s diary

C#、.NET系の技術ブログを書いています。みんなの洋楽ランキングを運営しています。

Azure App Service on Linuxで.Net Coreアプリを公開

https://msdnshared.blob.core.windows.net/media/2017/05/1-TryAppLinuxLanding.png

.Net Coreアプリ作ったのならLinuxで公開したい!って思ったものの、あまり必要性が感じられなかったので手付かずだったのですが値段見たらまぁびっくり!

Linux

f:id:tekitoumemo:20181010214208p:plain

3000円近くも変わるじゃん!前はほぼ値段変わらなかったのになぜにこんな差が。。まぁそんなこんなでみんなの洋楽ランキングLinuxサーバに移行計画を立てました。PaaSだからGithubブランチ指定してすんなり行くと思いきや、まったくダメで情報も全然無くて結構大変だったので丁寧に書いておきます。

Web Appをたてる

OSはLinux、公開はコード、ランタイムスタックは.Net Core 2.1で。Dockerの方が値段安いっぽいけどちゃんと調べてないから次回へ(たぶんやる)。しかも今ならB1インスタンスが1ヶ月無料なのでやりたい放題っす。
f:id:tekitoumemo:20181010215008p:plain

Githubのブランチからデプロイ

Github、Bitbucket、その他もろもろから合ったものを選んでください。
f:id:tekitoumemo:20181010221240p:plain
ブランチにPushされたら勝手にデプロイされます。

エラーが出る

f:id:tekitoumemo:20181010221727p:plain
はい、ダメでした。原因を探ります。失敗したところをクリックすると以下の画面が表示されます。ログを表示をクリックします。
f:id:tekitoumemo:20181010222118p:plain
f:id:tekitoumemo:20181010222210p:plain
「Object reference not set to an instance of an object」とでます。おなじみのメッセージですが、意味不明です。これはプロジェクトにsln(ソリューション)ファイルを含めるとkuduが解析出来ないのでダメみたいです。slnを消してプロジェクトを一つにすれば問題ないのですが、テストやライブラリなど複数のプロジェクトがあることが多いのでプロジェクトを一つにする方法はイケてませんし、マルチプラットフォームの意味がないですね。みんなの洋楽ランキングもDapperの自作拡張ライブラリ、定期更新系のAPIライブラリ、テストなどプロジェクトが分かれているので一つにする選択肢はありません。これを回避する方法があります。

ちなみにkuduとは

f:id:tekitoumemo:20181010223638p:plain
Kudu is the engine behind git deployments in Azure App Service.
Kuduは、Azure App Serviceのgitデプロイメントの背後にあるエンジンです。(翻訳ママ)

.deploymentファイルとCustom Deployment Scriptを設置する

Custom Deployment Scriptを準備

deploy.shファイルのWebApplication1はプロジェクトに合わせて変えてください。deploy.shはシェルスクリプトなんで名前はなんでもよいです。

#!/bin/bash

# ----------------------
# KUDU Deployment Script
# Version: 1.0.13
# ----------------------

# Helpers
# -------

exitWithMessageOnError () {
  if [ ! $? -eq 0 ]; then
    echo "An error has occurred during web site deployment."
    echo $1
    exit 1
  fi
}

# Prerequisites
# -------------

# Verify node.js installed
hash node 2>/dev/null
exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment."

# Setup
# -----

SCRIPT_DIR="${BASH_SOURCE[0]%\\*}"
SCRIPT_DIR="${SCRIPT_DIR%/*}"
ARTIFACTS=$SCRIPT_DIR/../artifacts
KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"}

if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then
  DEPLOYMENT_SOURCE=$SCRIPT_DIR
fi

if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then
  NEXT_MANIFEST_PATH=$ARTIFACTS/manifest

  if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then
    PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH
  fi
fi

if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then
  DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot
else
  KUDU_SERVICE=true
fi

if [[ ! -n "$KUDU_SYNC_CMD" ]]; then
  # Install kudu sync
  echo Installing Kudu Sync
  npm install kudusync -g --silent
  exitWithMessageOnError "npm failed"

  if [[ ! -n "$KUDU_SERVICE" ]]; then
    # In case we are running locally this is the correct location of kuduSync
    KUDU_SYNC_CMD=kuduSync
  else
    # In case we are running on kudu service this is the correct location of kuduSync
    KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync
  fi
fi

if [ "x$DEPLOYMENT_TEMP" = x ]; then
    DEPLOYMENT_TEMP=/tmp/`date +%s`
    CLEAN_LOCAL_DEPLOYMENT_TEMP=true
fi

if [ "x$CLEAN_LOCAL_DEPLOYMENT_TEMP" = xtrue ]; then
    rm -rf "$DEPLOYMENT_TEMP"
    mkdir "$DEPLOYMENT_TEMP"
fi
##################################################################################################################################
# Deployment
# ----------

echo Handling ASP.NET Core Web Application deployment.

# 1. Restore nuget packages
dotnet restore "WebApplication1/WebApplication1.csproj"
exitWithMessageOnError "dotnet restore failed"

# 2. Build and publish
dotnet publish "WebApplication1/WebApplication1.csproj" --output "$DEPLOYMENT_TEMP" --configuration Release
exitWithMessageOnError "dotnet publish failed"

# 3. KuduSync
"$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_TEMP" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh"
exitWithMessageOnError "Kudu Sync failed"


##################################################################################################################################
echo "Finished successfully."
.deploymentファイルを準備

.deploymentファイルはデプロイ時に実行されるスクリプトを記述するファイル(正直よくわかってない)で先ほど準備したCustom Deployment Scriptを指定します。フルパスにしないとNot Foundが出るのでちゃんと指定します。

[config]
command = /home/site/repository/deploy.sh

準備が出来たらPushしてください。

Custom Deployment Scriptは以下を参考に
github.com

再度デプロイする

次はデプロイが成功するはずなので、サイトを見に行きます。
f:id:tekitoumemo:20181010230041p:plain
そうするとサイトが立ち上がりません。
f:id:tekitoumemo:20181010230126p:plain
MVCテンプレ作ってデプロイしたらちゃんと動いたので、謎です。

スタートアップ ファイルを指定する

[アプリケーションの設定]からスタートアップ ファイルを指定します。ここで重要なのは、各フレームワークによって指定の仕方が違います。.Net Coreは以下の通りです。こんな記述方法知らんがな。

dotnet <myapp>.dll

ここにフレームワーク毎の指定方法が書いてあります。
docs.microsoft.com

サイトを確認する(二度目)

f:id:tekitoumemo:20181010230857p:plain
はい。動いたけど動いていません(え
心折れそうになったんですが、一つ心当たりが合ったのでそれを実施しました。

.Net Coreのバージョンを下げる

以前の記事で.Net Coreのバージョンを2.1.5にあげました。
tekitoumemo.hatenablog.com
公式ではApp Service反映してるよ!って言ってたのですがエラーの内容から怪しいのでバージョン指定なしでプロジェクトファイルの内容を変更します。

<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.5" />
↓
<PackageReference Include="Microsoft.AspNetCore.App" />

何も指定しないと2.1.1になるみたいです。
f:id:tekitoumemo:20181010232833p:plain
はい、確認しましょう。

サイトを確認する(三度目)

f:id:tekitoumemo:20181010233033p:plain
よっしゃー!ざっと見た感じ、Reactも動いてるしいい感じですね!もうちょっと動作確認したり、Coreのバージョンを下げたのでそれに伴ってNugetのバージョンを下げる必要がありそうです。また、移行する時間、告知、メンテナンス中のページとか作らなきゃいけないですので今月いけるかな〜?って感じです。

さいごに

記事では流れで書いているので簡単そうに見えますが、昨日の夜から今日も仕事でしたが適当にタスク2つぐらい終わらせてあとはずっと調べてました(クビ。開発もMacでやってるしWEBサーバーもマルチプラットフォームで実現出来たのでサービス開始から5ヶ月でようやく完全マルチプラットフォーム化実現しそうです。一応、Windowsでも動くような構成にしてるので(Windows機ないからわかりませんが)どの環境からも開発できるようになりました。.Net CoreのリリースノートにApp Serviceも反映したよって書いてあったのですがAzure App Service on Linuxは完全別物なんですね。3000円浮くし、application insightsとかゆくゆくはKubernetesとか試して見ようかなと思います。最後に参考になったサイトのリンクを貼っておきます。

Deploying ASP.NET Core to App Service on Linux – Honza's Blarg
Azure web app on linux deployment failed on deploy.ssh - Stack Overflow
Azure App Service on Linux の FAQ | Microsoft Docs