tech.guitarrapc.cóm

Technical updates

AWS Windows 自動化ラウンドテーブルのセッション資料公開

2016/5/13に、アマゾン ウェブ サービス(AWS) 様主催で、AWSでWindowsを扱っている方を集めてのクローズドなラウンドテーブルの第1回が開催されました。

私も、AWS Solution Architectの@keisuke69さんにお誘いいただき登壇させていただきました。今回の資料を作るきっかけを与えていただき、本当にありがとうございます。当日参加して下さった方もありがとうございます。

今回は、ラウンドテーブルで用いた資料と、グラニのインフラの基本的な考え方を紹介します。

Simple Windows Architecture on AWS

グラニは3年以上に渡りAWSでインフラ環境を構築しています。

神獄のヴァルハラゲートのリリース当初はPHPだったためAmazon Linuxでしたが、2013年7月のある晩にサービス運営中のコードベースをC# にリプレースし、以降はWindows Serverを中心としています。

当時と現在では、大きくインフラ構成が異なります。最も大きな変更が、インフラコンポーネントをDisposable *1 にしたことであり、よりシンプルにすることの追求です。

なぜ構成を公開するのか

今回の構成は、かなり踏み込んだ部分まで公開しています。グラニのインフラ構成を公開したのは、自分達の現状の整理と戒めを強く意識しています。

過去もそうですが、現在のインフラ構成にも多くの不満があり直したいことが山積みです。しかし直すにあたっても、そもそも私の考えが間違っていることが非常に多い自覚があります。

資料の補足と現状の理解を確認することを兼ねて少し現在の考えを書きますが、この資料や記事を読んでいただいた素敵な皆様がおかしいと感じられたことをご指導いただけると本当に嬉しいです。

Cloud Design Pattern

Cloud Design Patternというと、AWS Cloud Design Patternsをぱっと思い浮かべることが多いと思います。しかし同時にAzure Design Patternも浮かべる方も多いのではないでしょうか? 私は、それぞれのデザインパターンを次のように大雑把に捉えています。

Cloud Design Pattern 大雑把な解釈
https://aws.clouddesignpattern.org/index.php/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8 インフラコンポーネント構成に関するデザインパターン
アンチパターンでないパターン集
https://msdn.microsoft.com/ja-jp/library/dn568099.aspx サービス設計に関するデザインパターン
ベスト プラクティスパターン集

インフラ環境をDisposable(いつでも捨てられるよう)にする。これを実現するためにAWS上の構成変更を躊躇わず、マネージドサービスを積極的に利用し、インフラ全員がコードを書いています。しかし巷に溢れる優れたサービスを無差別に採用はできません、自分達にあったサービスを選択するための原則がないとすぐにカオスな状況に陥ります。

コード設計、サービス取捨選択の原則としている考え方がAzureのCloud Design Patternにある、Retry PatternExternal configuration store Patternです。

Retry Pattern

AWSにかぎらず、パブリッククラウドにおける大原則であることが多いように思います。

そのための手法も多く公開されています。

https://docs.aws.amazon.com/ja_jp/general/latest/gr/api-retries.html

https://azure.microsoft.com/ja-jp/documentation/articles/best-practices-retry-service-specific/

グラニも同様に失敗しても再施行によって成功する構成を目指しています。*2

失敗時の処理方法を共有するのではなく、もう一回やればいい。

このシンプルさは失敗に対する心理的障壁を下げるだけでなく、チームに対しても単純で伝えやすいです。

External configuration store Pattern

グラニのインフラは、インスタンスを1台たてるのも100台立てるのも構成方法と処理時間に大きな違いがないようにしています。この担保をしている重要な要素がExternal configuration Patternであり、スケーラビルティに大きく寄与すると思っています。

インフラは多くのミドルウェアが動きます。*3自分たちのコードもその1つです。そんな時に利用するのがExternal configuration store Patternです。

ミドルウェアをインスタンスに配置するにあたり、構成ファイルをデプロイ自体に含めるのではなく、S3 や Blob、場合によっては GitHub など外部に寄せるようにする。

もちろん自動デプロイ/再デプロイが高速、容易な場合はその限りではありません。またコードを書くにしても、AWS LambdaAzure FunctionsといったServerlessを利用できないかまず検討しています。*4

GitHubにpushすれば、全サーバーの構成が速やかに自動的に変わるというのは楽なものです。

Stamp Pattern

さて、インフラ視点のクラウドデザインパターンとして採用しているのがStamp Patternです。*5

ウェブサーバーに限らず、事前構成に時間が掛かる役割のEC2はStampパターンを用いてることで、全て同一構成に揃うようにしています。

https://aws.clouddesignpattern.org/index.php/CDP:Stamp%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3

この辺は過去にも記事で書いたことがあります。

https://gihyo.jp/admin/serial/01/grani/0003

個人的には柔軟性、展開速度、シンプルさの観点からStamp Patternはかなり嫌いです。*6Amazon AMIにConfiguration Managementを適用するだけで済む場合は、Stamp Patternを利用せずCMを適用するだけで構成しています。

このあたりはWindows版DockerがWindows Server 2016で出るのを心から待っています。リリースされたらすぐに乗り換えて、全サーバーコンポーネントを一新します。

他の基本としている要素

Design Patternとは少し違いますが、基本としている要素があります。

速度

先日のセッションと公開した資料の中で、「何度も、素早く繰り返すこと」(高速なイテレーション)を重視していることを述べました。

リトライするにしても、1回の処理に30minもかかっていては繰り返し自体が困難です。なるべく1回の施行は高速に、そして短いスパンで繰り返せることを目指しています。

もちろん何でも速さが正義ではありません。頻度との兼ね合いで、一日1回しか実行しないなら数分、数秒に大きなこだわりを出しても仕方ないと思っています。

副作用を伴う改善は極力選択しない

「課題A」を改善するために、「回避不可能な別の課題B」を生じる。

そんな改善は選択しないように気をつけています。*7

もちろん程度問題なので、課題Bが限定的だったり無視できるようなデメリットなら採用することが多いです。また、短期的にデメリットがあっても、すぐに改善するとわかっているなら課題の大きさによっては待たずに即採用もあります。*8

大事にしているのは、「根本の問題がなんなのか、原因を分析」することです。その場ですぐに解決できなくても後日ヒントや解決策に気づけるように意識づけています。

コスト意識

AWS EC2なら、LambdaやS3など「実行時課金」のServerlessへ変更できないかいつも考えています。

もしEC2でやるしかなくても、Spot Instanceを積極的に採用しています。EC2オンデマンドだったり、他のリソースならReserved Instanceを検討します。

グラニのインフラにおいて、AWS利用コストは当初と比較して劇的に改善しました。今も、不定期に構成を見なおして改善できないか検討しています。

自動化を常に考慮する

マネージドサービスを導入する際は、自動化できることを強く評価しています。Webhook、APIを含めて、サービス間連携できることが自動化手段を提供しているかどうかは重要です。

逆に、.NET SDKがなくともAPIが公開されていれば問題とすることがあまりありません。*9

そういえばAWSでウェブコンソールを使って最後にEC2を立てたのは3年前です。ずっとSDK経由で作成しかしていません。

デプロイ戦略

今回構成したインフラ構成において、アプリはC#6.0、ASP.NET MVC 5.3.2です。

そのため、2013年当時はMSDeployを用いていましたが、内製ツールのRapidHouseへと一年以上前に切り替えました。

残念ながらRapidHouseの公開は今のところ予定にないのですが、当初の構想通りデプロイが1秒で終わるようにできたのは体感できるインパクトが大きくよかったと思っています。

ずっと言っているのですが、Windowsにおけるシンボリックリンクの重要性は極めて高く、インフラ構成を「柔軟、簡素」にできる可能性が高いのでぜひ検討してください。

mamiyaの発表を見た時に、ほとんど同じ発想だったのでどこの環境でも同じことを考えるのだなぁと思い、ブラッシュアップのため参考にさせていただきました。

https://github.com/sorah/mamiya

資料も非常に分かりやすかったので、セッション資料でも参考にしています。

https://speakerdeck.com/sorah/scalable-deployments-how-we-deploy-rails-app-to-150-plus-hosts-in-a-minute

インフラ基盤を C#へ

RapidHouseによって各Windowsサーバーの操作がAPI公開されているので、サーバーの管理はPowerShell RemotingからHTTP(S)経由に完全移行し、C# がフル活用できるようになっています。

察しの良い方は気づかれた通り、昔のグラニはPowerShellをインフラの中心としていましたが、現在はC# が中心になっています。

もちろんPowerShellも利用しますが、ただのツールです。PowerShell DSCのConfigurationやワンライナー、補助スクリプトがメインで長大なコードは次々とC#にリプレースされています。

構成図の見直し

今回は、ヴァルハラゲートの構成図でしたが、最初期からみてどんどん変わっていっています。

変化は大事だと思っています。停滞はサービスの死に直結します。

そして変化の記録と公開も同様に大事にしています。弊社のサービス構成図は、CTOのスライドでも度々引用されています。

少し時系列で並べて見ます。構成図にない変化がかなりあるのですが、ここでは触れません。

時期 構成図
2013年3月
2013年9月
2014年1月
2015年12月
2016年5月

構成図自体も変化しています。従来は構成図をVisioで書いていましたが、現在はCloudCraftに移行しています。Visio、昔から使っていますが、ついにトドメを刺せました。

だれでも直感的に使えて再利用も共有も可能。しかも、コンポーネントの違いも3Dで表現しやすい構成図。CloudCraftはそんなサービスだと思います。

https://cloudcraft.co/

まとめ

どうでしょうか? 目新しいことがない、ふつーの構成ではありませんか? WindowsをAWSで使うのがツラい、Linuxにしたいという声をよく聞きますが、私達はUNIX/LinuxでのふつーをWindowsでも十分に構築できると考え実践する努力をしています。インフラの多くのコンポーネントは、実はServerlessだったりもします。

AWSにロックイン、ということもよく耳にしますが一切そんなことはありません。AWSじゃなくても、いつでもAzureやGoogle Cloud Platformに移行できる体制でもあります。それでもAWSを使うのは全てのバランスとAuroraなどの各リソースの強力、安定さからです。

グラニのインフラが目指しているのは、Windowsでうんぬんより、ユーザーにサービスをよりよく楽しんでもらえることです。そのためにできることをチーム全員が積極的に挑戦しています。Linuxには、共有するという文化から始まり、多くの面でインフラのトレンドを突き進んでいます。新しい考え方、手法にはサービスがより良くなることが多く秘められています。それがWindowsでできないということは誰も言っていません、だから採用する努力をしています。

あ、あと、グラニのこんなインフラを変えたい、もっと良くしたいとお考えの方をインフラ一同心からお待ちしています。

*1:Immutable InfrastructureというよりDisposable Infrastructureという方がグラニには適しています

*2:失敗したらリトライ可能な状態にロールバックする、冪等性を担保するなど、多くのやり方があるでしょう

*3:なるべく動かしたくないですし、減らすことを常に図っていますが!

*4:AWS LambdaがC# に対応してくれれば、Azure Functionsにある不満がAPI Gateway/Lambdaで強く改善できるので変更するのですが...

*5:いわゆるゴールデンイメージですね

*6:正確にはEC2が嫌いです

*7:それでも失敗します……

*8:なるべく待ちますが

*9:特にSwaggerに対応していると嬉しいです