Pairs Infra 2017

エウレカのSREチームで主にインフラを見ている坂田 (@sakajunquality )です。この記事は、eureka Engineering Advent Calendar 2017 6日目の記事です。5日目はCTO(Cat Tech Officer)の山本さんによるgRPCの実装の紹介でした。僕はPairsとParisをタイポするようなCTO(Chief Typo Officer)です。


はじめに

今年の4月に入社し、6月に入社エントリーを書かせていただきました。2017年からPairsのインフラをどのように変えてきたのかについて、サービス全体の構成要素と個々の構成要素について紹介します。


今年増えた構成要素

  • マイクロサービス
  • 韓国展開

構成の変更

  • プロビジョニングフローの変更
  • ビルド環境の変更
  • デプロイと本格的なオートスケーリングの導入


今年増えたサービスの構成要素について

マイクロサービスについて

機械学習を用いた投稿監視のマイクロサービスと、Pairsの内部で使用するユーザー系のマイクロサービスを2個立て続けにリリースしました。どちらのマイクロサービスもPairs本体からインターナルに通信しています。また現在は日本でのみ利用していますが、決済マイクロサービス同様、すべての国から利用できる用につくっています。


韓国展開について

Pairsはもともと、日本と台湾でサービスを展開していましたが、今年韓国においてもサービスの提供を開始しました。 https://pairs-korea.com/


韓国版は、iOS/Androidのネイティブアプリは同じですが、別ネットワークにインフラを構成しています。技術スタック的にはほぼ台湾に近い形で構成しています。

クライアント側でのバックエンドの切り替え処理については、そのうち@yuyakaidoさんか@muukiiさんあたりが記事にしてくれると思います。


構成変更について

サーバーのプロビジョニングについて

もともと積極的にInfrastructure as Codeは実践しており、ミドルウェアのインストールや設定変更、各種チューニングといったプロビジョニングや、実際にサーバーを起動するブートストラッピングは、比較的コード化が進んでいました。


プロビジョニングには、ansibleを利用していて、インスタンスを起動後に、ansibleのレシピを流す形を取っていました。何かを設定を変える際は、同じレシピを稼働中のサーバーに流すという形です。


ですが、2回目以降流したときの冪等性を保つのが大変だったり、変更がなかったためにレシピが長期間流されず信頼できない(実体とコードとの乖離が生まれている等)などの問題を抱えていました。



そこで、PackerとAnsibleを組み合わせて、AMI(AWSのマシンイメージ)を作成し、そのイメージからインスタンスを起動するフローに変更しました。ansibleはイメージを作る際のみ使用し、何か変更を加えるときは、AMIを新しく作り直します。そのため、ansibleレシピで同じサーバーに2回以上レシピを流したときの冪等性は考慮する必要がありません。






一見ちょっとした変更をするだけでも、AMIを作り直す必要があるので、めんどくさそうに思えますが、後述するオートスケールとの相性がよいです。後ほど理由も説明します。


ちなみに、もともとのansibleは全て捨てて、新しくPacker用にすべて書き直しました。


以前の登壇内容と重複するところもあるので、資料共有いたします。


PackerでのAMI作成について

Packer内でテンポラリーのスポットインスタンスを起動し、ansilbeで必要な設定をプロビジョニングし、ゴールデンイメージとなるAMIを作成しています。結構頻繁に利用するので、CodeBuildで Packerの動作環境を作り、Slack経由で簡単にAMIを作成できるようにもしています。この辺は別途記事を書こうと思います。

アプリケーションのビルド環境について

マイクロサービスを含め、PairsのサーバーサイドはすべてGo言語で書かれています。言語さえサーバーにインストールしてしまえば、簡単にビルドが可能です。もともと、アプリケーションのビルド/デプロイともにansibleを用いて、中央集権のビルドサーバーを経由して行っていました。いわゆるプッシュ型のディプロイの形です。しかし下記のような問題を抱えていました。

  • ビルドを並列で行うことができない
  • 単一障害点になっておりこのサーバーがないとビルドもディプロイもできない
  • ビルドサーバー自体が、古くなり再現性がない
  • パブリックIPもついておりセキュリティ的にも不安


ビルドを並列にいこなうことができないことや、単一障害点になっていることは、作り込みの問題でもあるのですが、ビルドがキューに溜まり開発者に待ちを発生させてい待っていました。ステージ環境は特に頻繁にビルド・デプロイを行いますが、ビルドのキューも可視化されておらず開発者にフラストレーションが溜まっていたと思います。


再現性については、セキュリティの観点からビルド環境を作り直したいものの、歴史的経緯によりコードがされておらず再構築のコストが高い状況でした。


そこでAWSのマネージドのビルド環境CodeBuildを利用してビルドするようにしました。マネージドサービスなので下記のような恩恵が受けられます。

  • ビルドを平行して行うことができる
  • 実行する筐体を管理する必要がない
  • 他のAWSのサービスとの連携がIAMベースで行える
  • terraformでの構築と管理が容易に行える

特に、CodeBuildは実行筐体はこちらで管理する必要がなく、時間課金で利用したいときに実行環境ができるので、運用コストが抑えられます。


ビルドサーバーを改めて構築することも選択肢としては考えられましたが、新しく作ったサーバーもいずれは陳腐化する可能性やその後の運用も考えるとマネージドのほうが良いという結論になりました。


現在ではPairsで必要なビルドにはすべてCodeBuildを利用しています。


CodeBuildの環境について

CodeBuildで、デフォルトで用意されている環境はいくつかあるのですが( http://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref.html )、バージョンが古いため、ECR(AWSのコンテナリポジトリ)にビルド用のイメージを予め用意し、アプリケーションのビルド時にdocker pullするようにしています。



余談ですが、Go 1.9がリリースされた日に、実際にCodeBuildでGo1.9を利用しました。


デプロイとオートスケーリングについて

以前にも実験的なオートスケーリングの導入は行っていましたが、スケールアウトした時の自動的なディプロイがネックとなっていました。というのもansibleを用いたプッシュ型のディプロイを行っていたので、オートスケールとの相性が悪かったためです。たとえば、スケールアウトのイベントを受けて、ロードバランサでのサービスイン前にディプロイを行いヘルスチェックを通すといったことをそのまま行おうとするとなかなか大変です。


また、デプロイ方式とオートスケールの相性が悪いだけでなく、ビルドとデプロイが同じサーバーで動いていたため、ビルドに対する問題と同じ問題をディプロも抱えていました。


そこで、AWSのマネージドサービスのCodeDeployを導入しました。CodeDeployはプル型 でAWSのオートスケーリンググループに紐付けることができ、スケールアウト時インスタンスが起動し、サービスインする前のタイミングで、自動でデプロイを実行することができます。


ビルド・デプロイ全体像


ここまでの話を図にまとめみました

  • PackerとAnsibleによるプロビジョニングでAMIを作成
  • AMIからオートスケールでサーバーを起動
  • CodeBuildでアプリケーションをビルド
  • CodeDeployでアプリケーションをディプロイ

大部分をマネージドサービスの連携で構築できているのがわかります。


実際の導入について

実際にこのビルド・デプロイ・オートスケールを全面導入するにあたっては、まず前述のマイクロサービス2つで先行して導入を行いました。新規構築だったので、少し手探りな部分はありましたが、ほぼ現在の形で構築することができました。

その後、韓国同じ要領で新規構築した後に、日本と台湾を移行し、最終的に決済マイクロサービスを移行しました。

元の構成用のansibleレシピはあったものの、新しく移行する環境が正しくプロビジョニングできているか入念にチェックするのが地味に大変でした。yamlと相当仲良く慣れたと思います。

エウレカのSREチームの方針として、技術的な挑戦をし良いものは常に取り入れる一方で、構成をシンプルにし運用負荷を下げるため、全体で技術標準化することを目指しています。

こちらも以前発表した内容とかぶるところがあるので、こちらにも共有させていただきます。



また、導入当初は、一部のアプリケーションがグレースフルにリロードできなかったり、時々ディプロイ、死活監視の設定が甘く、問題のないアラートが数多く飛んできたりしましたが、今は比較的安定して運用できています。

実際に運用に乗せてみて

ビルドは、失敗時のログの確認に最初慣れませんでしたが、それ以外には特に問題なく、並行でビルドできるようになったので、想定通りに使えています。デフォルトで20の同時ビルドという制限はありますが、今のところこの制限が問題になったことはありません(最大で17ビルドほど)。



オートスケールを全面導入することができたので、大きなメリットとしてサーバー費用を増やすことなく、トラフィック量に応じて、サーバーをスケールすることができるようになりました。

実際のオートスケーリングの台数


オートスケーリング導入の副次的なメリットとして、サーバー1台あたりのライフタイムが短くなりました。1日に何回もスケールアウトとスケールインを行っているため、経年劣化が起こりにくくなっています。インスタンスに障害が発生した場合も、自動でサービスからはずれ、新しくインスタンスが立ち上がるため、サービスに影響が出にくくなっています。



また、これらの構成はステージングやカナリー環境も含めて全て統一されています。AWSのリソースのほとんどすべてをterraformで管理しており、本番とステージングで共通部分をモジュール化していたりするので、スペックが違う全く同じ構成の環境を構築できるようにもしています。ステージング環境はトラフィックの増減が無いためワークロード確保目的のスケーリングポリシー設定は行なっていませんが、サーバのライフサイクルを短くし、常に最新のコードからビルドされたマシンイメージがサービスインしている状態を担保するために1日1回必ずサーバをローテートするようスケーリングポリシーを設定しています。これらは別途我々の考えるセキュリティ対策への技術的なアプローチだったりもするので、別の記事でご紹介したいと思います。

まだまだ改善点もある

いいことばかりではなく、まだ課題として感じている部分もあります。

ベースのAMIのプロビジョニングを自動で行いたい

オートスケールは、事前に指定したAMI(マシンイメージ)から起動します。そのマシンイメージのプロビジョニングと起動設定のを自動で変更することができていません。この部分を自動化することで、セキュリティパッチのアップデートやミドルウェアのマイナーバージョンアップを自動的に行えればサービスの運用負荷が下げられると思います。

現状は、環境変数の追加や設定変更などのタイミングで手動でAMIのプロビジョニングを行い変更していますが、何もないと変更できていないので、健全ではないと思っています。今後自動でできるように持っていきたいと思っています。


テストが不十分

もう一つは、インフラに対するテストが不十分なことです。実際にこれが間接的な起因で起きた障害もありました (haproxyでの分散先の設定が少なかったり、fluentdのプラグインのバージョン違いによるバグなど)。

インフラに対するテストは、議論の余地があると思います。Serverspecを真面目にやりすぎると、変更のコストが高くなるなど。

しかし、テストないし、設定が意図通りになっているかを用意に確認できるすべを用意することで、インフラのコストを低くできると思っています。

今後の展望

Dockerについては、機械学習のモデルのホスティングやビルドなど、本番環境での利用はエウレカ内で少しづつですが増えています。今年のre:InventでEKS(AWSマネージドk8s)が発表されるなど、環境としては整ってきているので、今後もマイクロサービスやログ基盤、機械学習において積極的にコンテナの利用を増やしていく予定です。Pairs本体は、今後サービスの展開次第な部分が大きいと思います。


ビルド・ディプロイについては、システム面だけでなく、日々のフローやチェック体制など開発のエコシステムも合わせてアップデートして行きたいと思います。

最後に

長々と書いてしまったので、そろそろまとめようと思います。

今年はビルド・デプロイ・プロビジョニングフローを中心にインフラの構成を大きく変えてきました。今回紹介はできませんでしたが、ログの基盤、バッチのワーカー化、Elasticsearchのクラスターの載せ替え、AWS新機能の追従など細かい部分も含め、多岐にわたって今年もインフラの変更を行うことができました。

ふと去年の弊社代表によるAdvent Calendarの投稿を見てみると、構成の大枠は変わっていないものの、細かいところではかなりのかわってるなぁと思いました。この記事の内容も、ほとんどは今年の下半期に行っており、新規構築するものが多かったのでやりやすい部分もありましたが、今年も去年に劣らずインフラを進化できていると思います。


来年はとりあえずMySQL on EC2をRDS Auroraに移行したいです(切実
2018年もよりよいサービスを目指して攻めのSREチームとして動いていきます!

  • このエントリーをはてなブックマークに追加

エウレカでは、一緒に働いていただける方を絶賛募集中です。募集中の職種はこちらからご確認ください!皆様のエントリーをお待ちしております!

Recommend

突撃!隣のGo言語テストコード(エウレカのGo言語におけるテストコードの工夫)

Pairs JP – iOSでプロフィール項目のViewModelをプロトコルで上手く書いている話