しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

App Service の Japan East / West にも Windows Server 2016 がデプロイされていました

手持ちの App Service を確認したところ、初期に Japan East に作成した App Service が Windows Server 2016 にアップグレードされていました。数日前に Japan West にはデプロイされていたので、Japan East でも開始されたみたいです。

ちゃんと Windows Server 2016 と .NET Framework 4.7.1 になっています。

f:id:shiba-yan:20171223010156p:plain

今回の OS アップグレードはペアリージョンで同時には行わないと宣言されていたので、既に Japan West に関しては完了していると考えて良さそうです。East はスタンプによってはまだ 2012 のままです。

アップグレードに伴い基本的な変更点に関しては、前回 West Central US で試した時のエントリを参照してください。ちなみに HTTP/2 は Japan East / West では予定通り無効になっています。

普段使いしていた App Service が Windows Server 2016 になったので、アプリケーションの互換性を少し見ておこうかなという気持ちになりました。

In/Out IP アドレスは変わるのか?

僕の尊敬する田口社長が Windows Server 2016 へのアップグレードに伴って IP アドレスが変わるのか心配していたので、2016 にアップグレードされた Web App で確認しておきました。

App Service Plan は S2 を使っていて、A レコードを当てていたので確認は簡単です。変更なしです。

f:id:shiba-yan:20171223010531p:plain

地味に気になるのが Outbound IP ですが、こちらもフォーラムで公開されている IP と現在の IP を比較したところ、変更はされていませんでした。なので安心してアップグレードを待てばよいでしょう。

恐らく大半の人は Windows Server 2016 にアップグレードされたことに気が付かないはずです。

2012 と 2016 で設定の違いはない

運よく Japan East に Windows Server 2012 と 2016 の Web App が用意できたので、applicationHost.config 周りで Diff を確認してみましたが、特に変化はありませんでした。

1 点挙げると、Azure App Service のランタイムバージョンが 2016 の方が新しくなっていたので、不具合の修正などが行われている可能性があります。

TCP Fast Open は無効

HTTP/2 よりも互換性面で影響が大きそうだったので有効化はされていないと思ってましたが、一応軽く確認だけしておきました。TCP Fast Open は無効となっています。

f:id:shiba-yan:20171223022016p:plain

Windows Server 2016 の Networking Stack 自体がもうちょっと検証されないと難しそうな気もしますが、今後に期待ということで適当にまとめたいと思います。

Azure Functions Runtime を Intel NUC にインストールした

自宅で Windows Server 2016 用として動かしていた Intel NUC を流用して、Windows 10 Pro をインストールし直し Azure Functions Runtime の環境に作り変えました。

Windows Server 2016 より Windows 10 Pro の方が FCU が扱いやすいので、個人的にお勧めしてます。ドキュメントには Creators Update と書いてましたが、FCU でも問題なく動きました。

インストールの詳細な手順はドキュメントに任せて、自分がはまった部分だけ軽く書いておきます。

Azure Functions Runtime をインストールして、セットアップを行っている途中に SQL Server と接続する必要があります。ドキュメントには書いてないですが、TCP を有効にしないと繋がらないみたいでした。

サーバー名も最初 localhost や .\SQLEXPRESS など試行錯誤しましたが、SQL Browse サービスが動いてないので名前付きインスタンスは TCP で使えず、結局マシン名だけで良いという結論でした。

f:id:shiba-yan:20171219234614p:plain

書いてある通りに sysadmin の権限を持ったログインを作っておく必要があります。データベースの prefix は空っぽで問題なかったのでそのままにしました。

後は設定を順番にポチポチしていけばはまることなく完了します。最後にポータルを開けば完了です。

f:id:shiba-yan:20171219234646p:plain

Function Portal は Windows 認証を使っているみたいなので、Windows へのログインユーザーとパスワードで入れます。Windows 認証をアプリではあまり使ったことないですが、地味に便利。

ログインすると、Azure Portal っぽさある画面になります。

f:id:shiba-yan:20171219234705p:plain

書いてある通りに、最初にサブスクリプションを作成します。将来的には Function の上限をサブスクリプション単位で指定できるのかもしれないですが、今は単なる入れ物っぽいです。

選べる項目も DefaultPlan しかないので、適当に名前を付ければ OK です。

f:id:shiba-yan:20171219234734p:plain

ローカルマシンに対する処理なので、一瞬で作成などは完了するのが新鮮です。

サブスクリプションを作成したら Function App を作成します。この辺りからは普通の Azure Functions と変わりないですが、作成時に Function Runtime のバージョンを選べます。

f:id:shiba-yan:20171219234749p:plain

.NET Framework を選んだ方が選べるトリガーが多いですが、例によって Server Core で実行されるので多少重いです。.NET Core の方は Nano Server なので有利ではあります。

f:id:shiba-yan:20171222115512p:plain

ちなみに HttpTrigger 系はありません。なので多少デバッグが行いにくいですが、大体の場合は TimerTrigger で動作を確認すればよい感じです。

実際に TimerTrigger な Function を作成すると、いろいろと興味深いログが出力されています。

f:id:shiba-yan:20171222115736p:plain

今の App Service のように ACL でサンドボックスを頑張るのではなく、Docker を利用して環境への依存を減らしつつ、Hyper-V Containers を使った高度な分離まで実現出来ているようです。

同時にインストールされる Command Pronpt ショートカットを管理者として起動すれば、Docker コマンドを使ってもうちょっと中身を詳細にみることが出来ます。

f:id:shiba-yan:20171222115819p:plain

Creators Update を対象としているので、FCU からの軽量化されたイメージが使えていないのは残念ですが、Azure Functions Runtime に App Service の未来を見た気がしました。

Windows Containers ベースの App Service への期待が個人的に高まっています。

Cosmos DB の SQL クエリパフォーマンスを調査する

仕事で Cosmos DB を使っていますが、最近は RU の消費が気になってきて、実際に投げたクエリがどのように実行されているのか知りたくなったので、例によっておーみさんに聞きました。

実行計画とはいかなくとも、非常に参考になるメトリックを返してくれるようになっているみたいです。

インデックスが本当に使われているのかどうかも、このメトリックから読み取れるようになってます。

ドキュメントを読めば大体わかりますが、FeedOptions で PopulateQueryMetrics = true とするとレスポンスにクエリの実行にかかった諸々の時間やデータサイズなどが返ってきます。

百聞は一見に如かずということで、適当なデータを作成して試してみました。まずは普通にインデックスが効いているであろうというケースです。

RDB でもインデックスを普通に作れば、Index Seek で引けるはずですね。

var feedOptions = new FeedOptions
{
    MaxItemCount = 1,
    EnableCrossPartitionQuery = true,
    PopulateQueryMetrics = true
};

var documentQuery = Client.CreateDocumentQuery<MemberDocument>(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), feedOptions)
                            .Where(x => x.Email == "test-1@example.com")
                            .AsDocumentQuery();

var response = await documentQuery.ExecuteNextAsync<MemberDocument>();

foreach (var item in response.QueryMetrics)
{
    var data = JsonConvert.SerializeObject(item.Value, Formatting.Indented);
}

インデックスの作成ポリシーはデフォルトのままなので、当然ながら Email に対してもインデックスが作成されています。それではインデックスが実際に使われているのかを確認してみます。

QueryMetrics の中身を表示するのが面倒だったので、適当に JSON にしたものを貼り付けておきます。

{
  "TotalTime": "00:00:00.0006100",
  "RetrievedDocumentCount": 1,
  "RetrievedDocumentSize": 853,
  "OutputDocumentCount": 1,
  "IndexHitRatio": 1.0,
  "QueryPreparationTimes": {
    "CompileTime": "00:00:00.0000600",
    "LogicalPlanBuildTime": "00:00:00.0000200",
    "PhysicalPlanBuildTime": "00:00:00.0000300",
    "QueryOptimizationTime": "00:00:00"
  },
  "QueryEngineTimes": {
    "IndexLookupTime": "00:00:00.0003000",
    "DocumentLoadTime": "00:00:00.0000200",
    "WriteOutputTime": "00:00:00.0000200",
    "RuntimeExecutionTimes": {
      "TotalTime": "00:00:00.0000100",
      "SystemFunctionExecutionTime": "00:00:00",
      "UserDefinedFunctionExecutionTime": "00:00:00"
    }
  },
  "Retries": 0
}

データの意味はドキュメントとキー名を見ればわかると思います。インデックスが使われているかどうかは IndexHitRatio と IndexLookupTime の値を見れば良いです。それぞれが 1.0 と 0.3ms となっているので、インデックスはちゃんと使われています。

ちなみに Time で終わるキーの値が 00:00:00 の場合は実行されていない扱いです。なので今回の場合は QueryOptimizationTime や Function の呼び出しが該当します。

Cosmos DB のインデックス周りは優秀みたいで、効かないかと思った条件でも割とインデックスが使われていました。しかし、SQL で言う LIKE の場合はスキャンになるみたいなので試しました。

var feedOptions = new FeedOptions
{
    MaxItemCount = 1,
    EnableCrossPartitionQuery = true,
    PopulateQueryMetrics = true
};

var documentQuery = Client.CreateDocumentQuery<MemberDocument>(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), feedOptions)
                            .Where(x => x.FirstName.Contains("kazuakix98"))
                            .AsDocumentQuery();

var response = await documentQuery.ExecuteNextAsync<MemberDocument>();

foreach (var item in response.QueryMetrics)
{
    var data = JsonConvert.SerializeObject(item.Value, Formatting.Indented);
}

こういう条件の場合は Azure Search を使えといわれそうですが、適当に試した感じではこれぐらいしかスキャンにならなかったので勘弁してください。

そして QueryMetrics の中身は以下の通りです。IndexHitRatio と IndexLookupTime に注目。

{
  "TotalTime": "00:00:00.0008900",
  "RetrievedDocumentCount": 100,
  "RetrievedDocumentSize": 85643,
  "OutputDocumentCount": 1,
  "IndexHitRatio": 0.01,
  "QueryPreparationTimes": {
    "CompileTime": "00:00:00.0000800",
    "LogicalPlanBuildTime": "00:00:00.0000400",
    "PhysicalPlanBuildTime": "00:00:00.0000300",
    "QueryOptimizationTime": "00:00:00"
  },
  "QueryEngineTimes": {
    "IndexLookupTime": "00:00:00",
    "DocumentLoadTime": "00:00:00.0003200",
    "WriteOutputTime": "00:00:00.0000200",
    "RuntimeExecutionTimes": {
      "TotalTime": "00:00:00.0002100",
      "SystemFunctionExecutionTime": "00:00:00.0000400",
      "UserDefinedFunctionExecutionTime": "00:00:00"
    }
  },
  "Retries": 0
}

全くインデックスが使われていないことが分かります。その代わりにスキャンが行われているので、DocumentLoadTime に割と時間がかかっていることも見て取れますね。

RetrievedDocumentCount が 100 となっているので、1 件を返すために 100 件をスキャンしていることも分かります。これだと RU も消費するし、時間もかかってくるので改善が必要となります。

RU と同じように Application Insights に送りたいのですが、PopulateQueryMetrics のオーバーヘッドがどのくらいなのかわからないため、ちょっとローカルのみで検証して様子見です。

Windows Server 2016 になった Azure App Service を試す

GitHub の Issue を眺めていたら、West Central US の App Service には Windows Server 2016 をデプロイしたと書いてあったので、早速新しく Web App をデプロイして試していました。

中の人曰く、West Central US をテストの場として使っているみたいです。ちゃんと 2016 です。

f:id:shiba-yan:20171212225301p:plain

軽く触ってみましたが、当然ながら構成は全く同じです。なので互換性を気にする程ではないです。

Kudu API に OS の名称とビルド番号を返す機能が追加されたので、それを使って使われているバージョンを詳細に取ってきました。この辺りは予告通りですね。

14393.1794.amd64fre.rs1_release(bryant).171110-1651

ちまちま確認するのはアレなので、GitHub に置いてあるバージョンなどをいい感じに表示するアプリをデプロイして、サクッと確認してみました。

f:id:shiba-yan:20171212230532p:plain

f:id:shiba-yan:20171212231112p:plain

ちゃんと .NET Framework 4.7.1 がインストールされています。App Service で動かしているアプリが 2016 で動くか心配な場合は、West Central US で試して見ると良いでしょう。

さて、アナウンスでは HTTP/2 対応は後回しと書いてありましたが、West Central US にデプロイしたアプリを確認すると、既に HTTP/2 が有効になっていました。

f:id:shiba-yan:20171212230500p:plain

気になったので確認すると、West Central US だけ先行して有効にしたらしいです。なので、今後グローバルでロールアウトされる場合には HTTP/2 は無効な状態となるはずです。

他に変更された部分がないか気になったので、Qualys の SSL Server Test を実行しました。このリージョンは HTTP/2 が有効なので ALPN が対応になってます。

f:id:shiba-yan:20171212230043p:plain

そして HTTP/2 で必要な暗号スイートである TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 が追加されています。この辺りは HTTP/2 が無効になっていても影響を受けない気がしますね。

f:id:shiba-yan:20171212225933p:plain

後は ECC 向けに secp384r1 曲線が追加されてました。Windows Server 2016 で追加された感あります。

f:id:shiba-yan:20171212230137p:plain

TCP Fast Open が有効になっているかとか気になりますが、確認がめんどくさかったのでやりません。数年振りとなるプラットフォーム側のアップデートなので、今後の展開にも期待しています。

Azure App Service が Windows Server 2016 に段階的にアップグレードされます

12/4 から App Service のホスト OS が Windows Server 2012 R2 から Windows Server 2016 へアップグレードされているらしいです。とはいえ非常にゆっくりロールアウトするらしいので、実際に 2016 なスケールユニットが使えるようになっているかはわかりません。

詳細はさとうなおきさんがブログで書いてるので、そっちを読むと良いです。日本語です。

Azure App Service、Azure FunctionsのWindows Server 2016へのアップグレード | S/N Ratio (by SATO Naoki (Neo))

ちなみに自分はまだ 2016 になったスケールユニットを引き当てていません。いろんなリージョンに App Service を作って試しましたが、リージョンが公開されていないと辛いですね。

f:id:shiba-yan:20171209234103p:plain

某社の T 田さんからメッセージで「互換性とか大丈夫なんすか?」みたいなことを聞かれたので、今のところ分かっている情報をベースに軽くまとめておくことにします。

IIS が 8.5 から 10.0 に

Windows Server 2016 へのアップグレードと同時に IIS もこれまでの 8.5 から 10.0 にアップデートされます。公式サイトで新機能が紹介されてますが、基本的には HTTP/2 だけです。

スケールユニットが 2016 にアップデートされても、そのタイミングでは HTTP/2 は解放されないようです。

フロントにいる ARR もアップデートされるので、グローバルで有効化するタイミングを合わせたいという理由なのかも知れません。

URL Rewrite も新しいバージョンがリリースされているので、そういった部分も一気に更新されてくる可能性がありそうです。実際に 2016 のスケールユニットを引き当ててから確認予定です。

2016 から TCP Fast Open など、ネットワークスタックにアップデートが行われていますが、アプリケーション側で対応できるものではないですし、アプリケーションの動作が変わる部分ではないので除外します。

.NET Framework も 4.7.1 に

今回の 2016 へのアップグレードと同時に .NET Framework 4.7.1 もインストールされます。特に書いてなかったのですが、コメントで聞いてみたら 4.7.1 も入ると教えてくれました。

むしろ OS のアップグレードよりも .NET Framework のアップデートの方が注意したい部分ですね。とはいえ 4.7 から 4.7.1 は特に互換性に影響の出る内容はなさそうなので、個人的には特に確認はしないです。

ASP.NET 周りのアップデートも多いので、万全を期すためには Visual Studio 2017 15.5 と .NET Framework 4.7.1 SDK の環境で、予め動作確認をしておけば良いでしょう。

とりあえず、早く 2016 が動いているスケールユニットを引きたいです。

Azure Functions and Web Jobs Tools のアップデートが失敗するのを直した

Visual Studio 2017 の 15.5 が出たので、やっと Azure Functions の新しいツールがインストール出来ると楽しみにしてましたが、無情にも謎のエラーが出てアップデートできませんでした。

インストールの途中ぐらいで以下の画像のようなエラーが出てしまいます。

エラーログには Azure Functions のツールをアンインストールしろと書いてますが、Visual Studio Installer からアンインストールすると Azure 開発周りもごっそり削除する割に、結局直らなかったので最悪です。

どうしようもないので Visual Studio Gallery の Q&A を見たら、同じ状況の人と回答を発見しました。割と前から発生していたようで、GitHub の Issue が割と伸びていました。

正直この Issue も解決したのかしてないのかわからない感じですが、エラーログからアンインストール出来ない拡張のパスを拾ってきて、そのディレクトリを削除するとアップデート出来るようになりました。

以下のようにディレクトリ名はランダムなので、エラーログから間違えないように拾ってきます。

f:id:shiba-yan:20171207004220p:plain

削除後には Visual Studio を起動して、機能拡張のアップデートを確認すると良いです。そこでアップデートか、もしくはインストールを実行すれば最新版が正しく入りました。

少しイレギュラーな対応をしてしまったので、動作に問題がないか少し不安でしたが、ちゃんと .NET Core 向けの Azure Functions が作れるようになっていたので問題なさそうです。

3 回ぐらい Azure 開発周りの再インストールを繰り返してしまったので、忘れないように残します。

Surface Book 2 でもアップデートを試しましたが、こっちはすんなりとアップデートが行えたので、特定のバージョンが入っている環境でのみ発生する問題のようでした。

Premium V2 が選べない App Service Plan が存在する

タイトルの通りですが、大昔に作った Japan East の App Service Plan を何となくスケールさせようかとしたら、Premium V2 がグレーアウトして選べなくなっていました。

f:id:shiba-yan:20171205163953p:plain

Premium V2 について知りたい方は、Public Preview の時に書いたエントリがあるので、こっちも参考にしてください。今は GA してますが、基本的に変わっていないはずです。

価格は GA してもこれまでの Premium と同じなのに、パフォーマンスは格段に向上しているので移行しない理由は全くありません。Premium を使っている場合は今すぐ移行しましょう。

話を戻します。グレーアウト部分に分かりにくいですが、理由が書いてあります。

Premium V2 is not supported for this scale unit. Please consider redeploying or cloning the App

要するに今の App Service Plan が載っているスケールユニットには、Premium V2 用のインスタンスが入っていないようです。なので Premium V2 を使うためには App Service の再デプロイやクローンを行って、スケールユニットを変える必要があります。

スケールユニットを変更するというのは地味に大変な作業です。サポートに変更リクエストを依頼できる噂もありますが、実行されるスケールユニットが変わると IP アドレスが変わります。A レコードを使っている場合、Outbound IP アドレスを使って制限をかけている場合などは手間がかかります。注意しましょう。

今ある App Service Plan に Premium V2 がデプロイされることを期待しますが、これから新しく作る App Service で Premium V2 を使う予定がある場合には、作成時に Premium V2 を選ぶようにしましょう。

f:id:shiba-yan:20171205165809p:plain

新規作成時に Premium V2 を選んでおけば、当然ながらデプロイされているスケールユニットが優先的に割り当てられるので、変更することがあっても安心して使えます。

今すぐに必要ない場合は、作成後にスケールを下げておけば良いです。後から変更するのは大変なので、予め考えておくか無条件で Premium V2 を選んで作成するのが良いかもしれません。

Application Insights に Cosmos DB で消費された RUs を送信すると非常に捗った話

仕事で Cosmos DB を使ってアプリケーションを書きましたが、最近はあらかじめ割り当てておいた RU を突き抜けることがあって原因の調査を行っていました。

その時に Cosmos DB のメトリックだけではコレクション別でしか RU を確認出来ず、Application Insights では処理時間しか取得されておらず不便だったので、自前で消費した RU を送信するようにしました。

RU を送信する処理は Repository のベースクラスに仕込んだので、少しの修正だけで済みました。

上で挙げたサンプルクラスに以下のような処理を追加して、適当なタイミングで呼び出しているだけです。RU 以外にも送っても良い気がしますが、今回は RU だけで十分でした。

TelemetryClient はサンプルなので DI を使って直接渡しましたが、適当にインターフェースを用意した方が Application Insights への依存関係を含めずに済むのでスマートかもしれません。

protected async Task<IList<T>> ExecuteQueryAsync<T>(IDocumentQuery<T> documentQuery, [CallerMemberName] string methodName = null)
{
    var requestCharge = 0.0;
    var list = new List<T>();

    while (documentQuery.HasMoreResults)
    {
        var response = await documentQuery.ExecuteNextAsync<T>();

        requestCharge += response.RequestCharge;

        list.AddRange(response);
    }

    TrackRequestCharge(requestCharge, methodName);

    return list;
}

private void TrackRequestCharge(double requestCharge, [CallerMemberName] string methodName = null)
{
    Telemetry.TrackEvent($"Executed operation {CollectionId}.{methodName} in {requestCharge} RUs", new Dictionary<string, string>
        {
            { "Collection", CollectionId }
        },
        new Dictionary<string, double>
        {
            { "Request units", requestCharge }
        });
}

ExecuteQueryAsync に関しては前回用意してなかったですが、モリス先輩がタイミングよく書いていたので参考にして組み込みました。

複数回 ExecuteNextAsync を呼び出す可能性があるので RU は集計するようにしてます。

そんなこんなでアプリケーションを実行してみると、カスタムイベントとして Application Insights に Cosmos DB で消費された RUs と実行したメソッド情報が表示されます。

サンプルなのでデータの偏りがなく、RU が一定になっているのでありがたみは感じないかもしれません。

f:id:shiba-yan:20171204230014p:plain

しかし実際のアプリケーションでの調査では、このカスタムイベントと Application Insights の Session Timeline が非常に強力でした。処理の流れが時系列で簡単に表示できる、最高に素晴らしい機能です。

組み合わせることで、どのページからの呼び出しで RU を過剰に消費しているか一目で確認出来ました。

f:id:shiba-yan:20171204230728p:plain

ちなみに、カスタムプロパティとしてコレクション名を送信しているので、Metrics Explorer から簡単にコレクション単位での RU 消費をグラフにすることが出来ます。

f:id:shiba-yan:20171204224345p:plain

グルーピングを設定しないと、関係なく集計してしまってあまり意味がありません。

実際に設定すると、以下のような表示になります。一目で状況を把握することが出来ますね。

f:id:shiba-yan:20171204225749p:plain

Cosmos DB は RU の消費状態を把握し、最適化を行うかが重要だと再認識しました。そのためには組み込みのメトリックだけでは不十分で、APM と上手く組み合わせると幸せになれるという話です。

実際に仕事で作ったアプリケーションで発生していた RU の過剰消費は一瞬で解決しました。それは余計なデータまで読みに行くという、単純なバグだったというオチでした。

Azure AD B2C を ASP.NET Core で使うと頻繁にログアウトするのを直す

Azure AD B2C を使ってログイン処理を実装した ASP.NET Core なアプリケーションが、何故か頻繁にログアウトしてしまうので調べてました。これもまた地味にはまったポイントです。

とりあえず OpenIdConnect な Middleware のコードを読んで調べました。

どうも Azure AD B2C 側で設定されている期限を優先している気配がありました。

最初は AddCookie で何も設定していないからかと思いましたが、ソースコードを調べた結果デフォルトは 14 日になっていたので、設定自体は問題ないことが分かりました。

前に Azure AD 自体のセッションが 1 時間で切れると聞いたことがあったので、期間を伸ばすしかないのかなーと思ってましたが、ぶちぞう RD が解決策を提示してくれました。流石 Azure 界の抱かれたい男 No.1。

設定を確認すると、確かに UseTokenLifetime = true となっていました。

元々 Azure AD B2C のログイン処理は GitHub のサンプルコードを参考に実装したので、サンプルコードの方を確認すると UseTokenLifetime = true となっていました。

https://github.com/Azure-Samples/active-directory-b2c-dotnetcore-webapp/blob/core2.0/WebApp-OpenIDConnect-DotNet/OpenIdConnectOptionsSetup.cs#L47

ドキュメントコメント曰く、UseTokenLifetime はデフォルトでは false らしいです。サンプルコードはアクセストークンを使う部分があるので、true にしていたみたいです。

設定を変えて、再度ログインすると 14 日有効なクッキーが発行されました。

f:id:shiba-yan:20171129010837p:plain

単にログイン用として使う場合は false にしておく方が良いですが、アクセストークンをログイン中の任意のタイミングで使う場合には true にすると自動的にログアウトされるので便利でしょう。

そういえば LINE Login が OpenID Connect に対応した時にも true にしていました。

LINE Login のアクセストークンは 30 日間有効なので、AD B2C のように問題にはならないはずです。

Web サービスのログインが 1 時間で毎回切れるとか、さすがにこっちが切れそうになるのでサンプルコードにコメントぐらい書いておいてほしかったというのが本音です。気を付けましょう。

Azure Container Services (AKS) のデプロイで苦労した話

ここ数日は AKS のクラスター作成と戦っていたので、ARM ベースでいろいろと調べていました。例によって忘れそうなので、ちゃんとメモしておくことにします。

AKS の最新情報を知りたければ、GitHub を追っかけておけば OK です。

ちなみに以下のエントリで使うために、クラスターを作っていた時の話です。

基本的に Windows と Linux のハイブリッドなクラスターしか作ってないので、話としては偏っているのでそのあたりはあしからず。

West US 2 / UK West は新規デプロイ停止

デプロイ完了していた West US 2 のクラスターが Failed になって止まっていたので、新しくデプロイしようとしても必ず失敗するとか、まあいろいろとはまっていました。

調べていたら GitHub にアナウンスが上がっていました。

https://github.com/Azure/AKS/blob/master/annoucements/service_outage_2017-11-09.md

何らかの障害で West US 2 は新規のクラスター作成を受け付けていません。UK West はおそらくキャパシティの問題で、こちらも作成は出来ない状態となっています。

既に作成済みのクラスターがある場合でも、ステータスが Failed になっている場合は作り直す必要があるかもしれません。自分の場合はどうしても復活しなかったので作り直しました。

失敗後に同じ名前の AKS を作ると挙動が怪しい(気がする)

適当に作成したリソースグループに対して West US 2 に AKS をデプロイしようとして、キャパシティの問題でエラーになった後、再度同じ名前でデプロイすると別のエラーになってました。

リソースグループを新しく作っても変わらなかったですが、AKS を別名にすると通った気がしました。

対応リージョンに East US / West Europe が追加

パブリックプレビューとして公開された時には West US 2 と UK West しか選べませんでしたが、最近 East US と West Europe が追加されました。

https://github.com/Azure/AKS/blob/master/preview_regions.md

Hyper-V Containers が使いたいので Nested Virtualization を有効に出来る Dv3 が使えるリージョンを選ぶ必要がありましたが、East US と West Europe は両方とも対応してるみたいです。

今新しく AKS を作ろうとすると、そもそも UK West は選べなくなってました。

f:id:shiba-yan:20171115223905p:plain

もうちょっと日本に近い場所にデプロイされると嬉しいのですが、時間はかかりそうな気がしています。East Asia か Southeast Asia なら来るかもしれません。

ルートテーブルにルートが追加されない時がある

Windows 限定っぽいですが、VM などのデプロイが完了しているにもかかわらず、ルートテーブルに新規作成した VM 向けのルートが追加されず、ノードとして認識されない現象が発生しました。

しかも、上手くいったりいかなかったりするので非常に厄介です。ほかにも Custom Script Extension の実行に失敗したり、そもそもデプロイが完了しなかったりといろいろありました。

対処方法としては上手くいくまで VM を作り直すぐらいしかないです。

Kubernetes 1.7.9 / 1.8.2 に対応

ポータルからは 1.7.7 と 1.8.1 しか選べない Kubernetes のバージョンですが、内部的には 1.7.9 と 1.8.2 に対応しているようで、ARM を使って設定値を変えるとアップデートされます。

ARM で upgradeprofile を開くと、対応しているバージョンを取得できます。

f:id:shiba-yan:20171115223145p:plain

ちゃんと Windows にも対応していることが分かります。公式発表は近いのかも。

f:id:shiba-yan:20171117230519p:plain

ARM Explorer でバージョンを書き換えたところ、ちゃんと Kubernetes 1.8.2 にアップデートされたことが確認できました。Windows と Linux の両方ともが自動でアップデートされます。

ちなみにアップデートは VM を作り直すという方法なので、多少時間はかかります。