Webサーバーのリプレイス

外山英幸氏:これで認証と認可がリプレイスされたので、続いて、Webサーバのリプレイスについてお話ししたいと思います。

Webサーバは古いアーキテクチャだったので、キャリトレはいまだにスティッキーセッションを使っておりました。

あとは、設定がステートを含んだところで、Ansibleの中に環境依存の設定を多数持っていますので、サーバを増やしたいと思ったときにも簡単に増やせず、Ansibleの設定をいじる必要がありますし、それをリリースする作業を挟む必要があるので、スケールしづらいWebサーバとなっていました。

ここを一気に変えて、RESTful API化と合わせてオートスケール可能な構成にしました。

今回クライアントはSPAになっていますので、表にあるのは基本的にAPI Gatewayです。API Gatewayの裏はECS・Fargateを組みまして、FargateのコンテナにJavaのAPIをデプロイするので、Web APIを構築しています。API GatewayのAuthorizerは、先ほどもありましたように、CognitoとLambdaを利用しています。

これはそれほど癖のある構成ではなく、同じようにAPIをサーバレスではなくJavaのAPIにしたいような場合ですと、ほぼこのパターンになるのではないかという構成です。

ビルド・デプロイのマネージド化

これで、認証、認可、それを返すAPIができたのですが、そこに対してソースコードをビルド・デプロイしていく必要があります。ここに関してもマネージド化を図っております。

過去のビルドです。これもよくあるパターンだと思います。GitHubからソースコードを持ってきて、Jenkinsでビルドをして、デプロイをする、といったことをやっていました。

問題点としては、ビルドが毎年高負荷化しているので、けっこうなスペックになってしまっている状態です。基本的にスケールアップで対応しています。

デプロイも直列でしかできない状態ですので、1台5分で終わったとしても、例えば6台Webサーバがあったら、デプロイに30分かかってしまいます。

そのため一連の流れで1時間ぐらいかかってしまう現状ですので、リリースしたあとに緊急リリースが必要な事態が発生したときに、そのインターバルがどうしても長くなってしまう状態でした。これは年々長くなっていますので、今後もさらに遅くなってしまうことが予見されている状態でした。

ここに関してもビルド・デプロイのマネージド化というところで、こちらは開発環境の例です。GitHubにPushされた場合、それをwebhookで検知して、Jenkinsが自動でCodeBuildを実行しています。

フェーズとしては3つです。まずBuild Phase。CodeBuildでJavaのソースをビルドして、それをDockerイメージ化して、ECRに登録しています。Deploy Phaseでは、ECRに登録されたDockerイメージを基にコンテナをアップデートしまして、ECSが最新化されます。そのあと、今回はAPI Gatewayを使っていますので、API Gatewayに最新のTerraformを適用するというところで、API Gatewayも最新化される。これが開発環境ではwebhookを起点にずっと回っている状態になっています。

これをパッと見たときに「JenkinsじゃなくてPipelineを使えばいいんじゃないか」と思うかもしれませんが、開発環境はいろいろなケースがありまます。デプロイだけ再度実行したいなど、いろいろな要望に応えられるようにJenkinsで実行しています。

これも本番環境ではCodePipelineを使っています。本番ではwebhookのタイミングでリリースされてしまったら困りますよね。あくまでデベロッパーがリリースをするというアクションをとると、CodePipelineが先ほどと同じようなフローを回すようになっています。

ただ、開発環境と1点違うのが、この認証フェーズを分けている点です。監査の対応も含めまして、誰かがリリースしたいと思ったときにすぐリリースされる状況では困ります。

ですので、リリースボタン自体は誰が押してもいいのですが、その後ちゃんと承認をするフェーズをPipelineで定義していまして、リリースボタンが押されると、自分のところに「リリースを承認してください」というメールが飛んできます。そのメールを見て、コンソールにログインして承認を押すと、Pipelineのコードが走り出して、リリースが行われるという流れです。

なので、監査にも対応していますし各種ログも自動で残りますので、監査内容も含めて簡素化されました。

DBのAurora化、SolrのElasticSearch化

認証、認可、APIができて、そこに対してのデプロイもできました。ここはさらっとなのですが、データのリソースも刷新しています。

まずはデータベースです。

今まではRDSのMySQLを使っていたのですが、Auroraの導入実績も世の中に広まってきていましたので、Auroraを選択するリスクはなかろうということ、今回はAuroraを採用しています。MySQLのAuroraです。

Auroraはいろいろなメリットがありまして、一番大きいのは今までRDSの時にマスター・スレーブ構成をとっているときに、どうしても更新が多いとレプリ遅延が発生すると思います。そこの遅延リスクが大幅に下がるところや、IOPSの考慮が減る点でした。

RDSでパッチアップデートがあります。パッチアップデートの際に、弊社も夜中に放置する戦略を取り入れるのですがなにが起きるかわからないので、やはりショートメンテをして、その間にパッチアップデートを行っています。

ですが、Auroraはゼロダウンタイムパッチというものがありまして、基本的にショートメンテを入れなくてもアップデートができるものがあったので、ここに期待していました。ですがこれに関してはまだうまくいっておらず、Javaのコネクションプールと相性が悪い部分がありリリースまでに解決できる目処が立っていないので、Auroraを導入したとしてもショートメンテは入れる予定です。

これも細かいところなのですが、Solrを使われている会社も多いと思っています。弊社もSolrを使っていたのですが、Solrのアプリケーションとしての機能はわりと使いやすいのですが、サーバの保守においては大変なことが多く、マスターがメモリ不足になったりいろんなことがあるため、今回はAmazon Elasticsearch Serviceの導入を決めています。

Batchのマネージド化

続いて、Batchのマネージド化です。

Batchのマネージド化ということで、バッチも今までは自作のWebスケジューラーを作っていたり、バッチサーバ自体も普通にEC2上で動かしていたので、同じEC2で動いているバッチがリソースをとってしまうと、ほかのバッチも全て死んでしまう状況でした。それを防ぐためには、やはりバッチサーバのスケールアップをしてしまうんです。そうすると工数的にもかさむので、ここもシンプルな構成にしています。

まず、スケジューラーはCloudWatch Events+StepFunctionによる実行管理を行っています。ですので、バッチのフロー管理が単純化されていますし、実行状況のモニタリングも容易になっています。さらにスケジューラー自体の保守から解放されていますので、ここも楽になった部分です。

起動時間を含むすべての設定をTerraformで管理していますので、「誰が変えたのか」「いつ変わったのか」といった情報もすべてGitHubで見ることができます。

もう1つ、バッチの実行環境自体がスケーラブルになっているのは非常に大きいです。基本的にバッチはすべてECSのrun-taskで実行しています。起動するときだけタスクが立ち上がるようになっています。

これはコストメリットも大きいですし、あとはtask definition、タスクの定義を、例えばレコメンドみたいにスペックが必要なものは別の定義にしておくことで、ECSのスペック自体も変えることができるので、ここもコストの最適化・パフォーマンスの最適化が図れる構成です。

運用方法のリプレイス

続いて運用方法のリプレイスです。

運用方法は、「特権管理」という言葉が通じるかわからないのですが、要は「休日に家にいるときにインフラの障害が発生したときはどうするのか?」といったところで、今までそういったケースでは、VPNを使って本番環境にログインして対応していました。

ただ、VPNは証明書の管理がけっこう大変なんですよ。証明書が漏れるのは最大のリスクですので、払い出すための申請や棚卸など、そういった管理が面倒ですし監査の対応でもつっこまれるところです。ここを解消するために、リプレイス後はSTS+SSMを利用した時限付きの特権権限を導入することで改善を図っています。

フローのイメージです。まず、なにか調査したいことが発生したとします。そうするとSlackのHubotで「本番調査したいので、今から10分間ログインさせてください」と申請をすると、自分のところにメールが届きます。そのメールのURLを基にコンソールにログインして、問題がなければ承認する。その申請者はその10分間、実際は1時間ぐらいはSSMを利用して本番で作業できる、という構成になっています。

メールをよりよいフローにしたいと思っているのですが、今はいったんこれで十分だということで、このような運用部分の改善を行っています。脱VPNです。

ログ周りも一気に変えまして、今までKibanaを使ってログ収集していたのですが、今回はAWSと非常に親和性の高いDataDogを全面導入し、WebのログはすべてDataDog Logsで見られるようにしました。APMも、各種メトリクスを全部定義してDataDogに送ることで、DataDogですべて数値化されている状態になっています。クリティカルなものに関してはメンション付きでSlackで通知をする、というフローです。

Infrastructure as Code

最後に「Infrastructure as Code」についてです。今回これが一番がんばったところじゃないかと思います。今述べたすべてをほぼ100パーセントTerraformでコード管理しております。Infra as Codeはよく言われる話でして、まぁ「コードで書けばいいじゃん」と思うかもしれませんが、AWSをTerraformで全部書こうとすると、いろんなはまりポイントがあります。実際に苦労したのは、自分というより担当してくれた現場のメンバーたちです。

Terraformで管理しきった結果どうなったかといいますと、Terraformのファイル数が現在1,200を超えています。このたくさんあるファイルを管理しやすいディレクトリ構造にしたい。そのため運用をがんばってしているところです。

これはなにがうれしいかといいますと、Terraform化されるとオペレーションの部分がある程度エンジニアサイドでできるようになります。

例えば、バケットを1つ増やしたいと思ったときも、今まではインフラチームに申請を上げていました。ですが今のフローでは、エンジニアがTerraformの設定を増やして、そのプルリクエストをインフラチームに投げて承認されれば、もうそれでバケットが増えます。

Terraform上は環境依存を完全に排除していますので、検証環境のデプロイも本番環境のデプロイも同じものです。なので、「検証にS3追加したんだけど、本番リリースしたときに本番のS3バケットを追加するのを忘れていた」みたいなことは絶対に起こらない構成です。

Terraform周りは本当に奥が深くていろいろはまりポイントがあるのですが、AWSに関係あるのかといわれるとあまり関係ないかもしれませんし、これだけで1セッションになりうる内容ですので、割愛させていただきます。

グロースしていくためのスタートにすぎない

最後に、今回、本当にインフラ面もいろいろ変えました。重視したのは、今まで手動運用していたものを自動化、楽をするという部分や、属人化していた部分をコード化・可視化することによって標準化する、といったことを徹底的に行おうとしたプロジェクトです。

先ほどから「今やっています」とお話をしてきましたが、現在はシナリオ試験のフェーズでして、リリースは8月以降を予定しています。

1年がかりの大規模プロジェクトなのですが、今回のリリースはゴールではありません。これからグロースしていくためのスタートにすぎないと思っておりますので、今後どんどんシステムを大きくしていく上で、サービス拡大を一緒にやっていただける仲間はいつでも募集しております。

ぜひこのサービスに興味がありましたら、会社のホームページからご応募していただいたり、このあとお話しできる機会があると思いますので、そこで質問していただいたり、接点を持っていただければと思っています。よろしくお願いいたします。

これにて発表を終わらせていただきます。ご清聴ありがとうございました。

(会場拍手)