エンジニアの五十嵐 (@gantawitter) です。
今回はクラウドソーシングのクラウドワークスのサービスの土台となるインフラについて紹介させていただきます。
クラウドワークスはAmazon Web Services上に構築されています。 サービス本体はRailsを利用して実装されたモノリシックなアプリケーションです。 BlueGreenDeploymentを行えるようになっており、1日に5回程度のペースでアプリケーションをデプロイしています。
利用している主なサービスは次の図のとおりです。(一部省略しています)
課題
インフラのコード化が一般的になってきた昨今ですが、サービスの機能開発を優先して成長させてきたため、昨年までインフラ構成に次のような課題がありました。
- サーバーが温かみのある手作業で構築されていたため、複数台あるサーバーへの設定変更も手作業で行っていた。
- インフラに対する設定変更がレビューしづらく、当然テストも存在しなかった。
解決方法
そこで、クラウドワークスのサービスを支えるインフラを継続的に改善できるようにするため、インフラ構築の自動化を行いました。 これにより、アプリケーションサーバーの設定変更がPull Requestベースで行えるようになり、サーバーへの設定変更は自動的に反映されるようになりました。 また、Serverspecによるテストも追加され、サーバーを新しく自動で作成できるようになりました。
設定のコード化
Chef
まず、既存のアプリケーションサーバーと同一になるChefレシピの作成を行いました。 レシピの適用はChef Manageを利用したChef Server/Client構成で行っています。
既存のサーバーと設定を極力合わせることで問題を防ぐという方針を取りました。 その際に、弊社@minamijoyoが開発したAjimiが活躍しました。
苦労した点としては、Amazon Linuxを利用しているため、手元でレシピを書いているときもtest-kitchenからEC2を使わなければならず、EC2の起動時間とネットワークレイテンシの面で時間が取られたことです。 現在は一度レシピを作り切っているので、将来的にはUbuntuなどに移行してDockerで高速にテストを実行できるようしたいです。
Terraform
AWSのリソースの構築はTerraformを利用しました。 Terraformは構築したリソースの状態を保存しておく必要がありますが、それにはAtlasを用いてチームで共有できるようにしました。 今回はまっさらな状態からリソースを構築したわけではなく、既存のELBやSecurity Groupなどを参照する形で構築しました。
Terraformを使っていて感じたのは、これをどこまでやってよいのか、ということでした。 すべてをTerraform化するにはまだ安定している感じではなく、割とクセがあるのでAWSを触る全エンジニアに修得を求めるのはコストが高いと思いました。
インフラ構築の自動実行
Wercker
インフラ構築のCIはWerckerを利用しています。
(エンジニア) Pull Requestの作成
↓
(CI環境) テスト
↓
(エンジニア) マージ
↓
(CI環境) テスト&CookbookバージョンアップのPull Requestの作成
↓
(エンジニア) マージ
↓
(CI環境) production環境へのインフラデプロイ
という流れで運用しており、このフローをWercker上で実行するためのスクリプトを自前で実装しています。
AWS CodeDeploy
インフラデプロイ実行時に現在デプロイされているバージョンのアプリケーションもデプロイする必要があります。 アプリケーションのデプロイにはAWS CodeDeployを利用しています。
CodeDeployはデプロイ対象をAuto Scaling Groupまたは特定のタグで指定します。 将来的にAuto Scalingを使うことを検討しており、何らかの形でグルーピングした方が綺麗に管理できるためAuto Scaling Groupで指定することを選択しました。
ただ、CodeDeployは差分ではなく指定コミットのコードを全取得するため、リポジトリが巨大になってしまっているとデータ転送時間が掛かります。
加えて現状のアプリケーションは初回のbundle install
とassets:precompile
にも時間が掛かっており、結果としてEC2の生成に時間が掛かってしまうため、実はまだAuto ScalingはさせておらずEC2インスタンスは固定となっています。
注意点として、Auto Scaling Group上のEC2インスタンスはStopさせるとTerminateされる仕様となっています。
そのため、BlueGreenDeploymentで待機系となるEC2インスタンスたちは一旦Auto Scaling GroupからデタッチしてからStopさせる必要があります。
デタッチしてしまうと元々どこにアタッチしていたかわからなくなるため、アタッチしていたAuto Scaling Group名をセットしたattached_asg
タグを付与することで識別しています。
staging環境の構築
自動化の過程でこれまで存在しなかったstaging環境を容易に作れるようになりました。 これまで机上確認しかできていなかった部分がテストできるようになり、安心してリリースが行えます。
ここでTerraformの話に戻りますが、staging環境を作るにあたり、Terraformのテンプレートは当初productionとstagingでそれぞれ書く方針にしていました。 しかし、テンプレート自体の検証はどうするのか?ということから同一のテンプレートを利用することにしました。
Terraform自体にはEnvironmentを切り替える機能は持っていないため、自前で切り替えられるように工夫しました。 詳細はこちらの記事をご覧ください。 qiita.com
また、依存するサービスについては費用を抑えるため、MySQLとElasticsearch、Memcached、Fluentdを1つのECS (Amazon EC2 Container Service)上で動作させています。 ECSの構築もTerraformででき、コンテナの設定値を容易にコードで管理できるので便利です。
We're hiring!
「個人の与信インフラ」を目指すクラウドワークスの「インフラ」を支えてくださるエンジニアを募集しています。 www.wantedly.com