こんにちは、nanapiインフラチームの大西です。
最近はAWS IoTが出たのでこの波に乗るしかないと思い電子工作始めました。
Ωとかあったなーとか学生時代を思い出しながらLEDランプを何個か破壊しました。
電気は素人が扱うと危険なのでしっかり基礎をつけてから触ろうと思いました。
さて、今回はnanapiの新アプリ Amigo をリリースしましたので構成を紹介できればと思います。
言語など
自分がインフラメインなのでアプリケーション側はざっくりの説明になります。
その辺りはまた別の機会に紹介させていただければと思います。
- Androidアプリ
- サーバ側
- Ruby
- sucker punch
- Elixir
- Ruby
- データストア
- redis
- s3
今回紹介する範囲
何故HashiCorpなのか
まず一番の理由は自分が試したかったというところになります。
HashiCorpはUnix哲学の Simple, Modular, Composable
に影響を受けているため、各サービスが独立しています。
そして各ツールを集約するために Atlas
であったり最近出た Otto
などがあります。
各機能が独立しているため、自前のツールとの連携も容易にできるため非常に扱いやすいです。
そしてImmutable Infrastructureは常識となりつつある今、インフラもコード化するのは必須です。
弊社の既存のシステムでも十分にImmutable Infrastructureは達成できましたが、もっと使いやすくもっと気軽に触って欲しい思いで今回選択しました。
そういった面でHachiCorp社のツールは非常に優れていたため選択しました。
各ツールの紹介と比較
ここからは各項目の選定基準などを紹介できればと思います。
AWS
AWSの選定についてはそこまで深い意味はありませんが一応。
弊社ではAWSを中心にサービスを構築しているため今回もAWSを使用しました。
AWSは各サービスに優れているものが多く、連携が容易なこともあり弊社での初期構築ではほぼ利用しております。
PackerとItamae
今まではEC2のuserdataを使ってChefを実行し、毎回サーバを新規で構築していました。
サーバの構成を変更した時は毎回作成し直していたため、冪等性は必要なく二度目のChefが走ることはありませんでした。
方針として現在も変わっていないのですが、この機能を実装するにあたってChefはオーバースペックのためItamaeに変更しました。
ItamaeはChefのレシピをほぼ変更なしでそのまま利用できるので移行は簡単でした。
またuserdataについても今まで独自のコードで環境差分を出し分けて作成していたためPackerに移行しました。
Terraform
弊社ではCloudFormationをそのまま使わずにRubyで記述できる SparkleFormation 利用していました。
CloudFormationはJSONで全て記述するため、そのまま使うのは厳しいところがある印象です。
弊社はRubyエンジニアが多いため各自で触ってもらえるようにSparkleFormationを選択していました。
しかし今回Terraformを選んだ理由は安全という点を重視しました。
Terraformには terraform plan
というコマンドがあり、自分の書いたコードを反映するとAWS上でどんなことが起こるかを実行する前に表示できます。
インフラエンジニアとしてはもっと気軽にサーバを触ってもらいたいのですが、既存の物を壊してしまう恐れからどうしても敬遠してしまいがちです。
Terraformはそんな部分をしっかりカバーしてくれているため、非常に扱いやすいです。
$ terraform plan
Refreshing Terraform state prior to plan...
~ 略 ~
~ aws_autoscaling_group.hoge
max_size: "2" => "3"
min_size: "5" => "8"
# これはautoscaling_groupのインスタンス数を変更した場合です
ただ、Terraformは一部バグというか、対応しきれてない部分があります。
例えばLaunchConfigurationの変更した時の流れですが
既存のLaunchConfiguration削除 -> 新しいLaunchConfiguration作成という流れになるため
AutoScalingGroupで既存のLaunchConfigurationを使用しているから消せないなど順番によるトラブルがあったりします。
またSparkleFormationはRubyで記述しているため記述方法が自由です。
Terraformも一部特殊な書き方もできますがRubyと比較すると厳しいところがあります。
ConsulとStretcher
Consulに関しては現状デプロイと監視に使っています。
デプロイですがConsulのKey Valueの変更を検知してデプロイが走る仕組みになっています。
CircleCIでテストが完了したあとに圧縮してS3にアップロードしています。
S3にアップロードしたものはgitのhash値になっており、その値を指定、もしくはlatestと入力することで好きなコードを持ってこれる
ように構築しております。
この値を変更した時にConsulのイベントを使用して各サーバがStretcherを実行します。
StretcherではS3からダウンロードして各自展開して事前に必要な処理をしてサービスが稼働し、デプロイ完了報告をConsulのKey Valueに通知します。
このあたりは後ほど説明しますがCanary Deploymentsを使って稼働中のサーバの裏側で起動します。
問題点としてはCiclerCIがUbuntu12.04だったため、CircleCI上にDockerでコンテナを作成し、そこでbundle installなど構築を行っています。
ここまでするならDockerで運用すればいいかと思いますが、Dockerを使うとRegistryを検討したり、
サイズが大きくなったりと管理するものが増えるため初期の段階では使用しませんでした。
今まではCapistranoを使用していたのですが、Capistranoの場合 デプロイサーバ -> デプロイされるサーバ
の通信が切れた時デプロイできなくなります。
しかしConsulのイベントの場合、クラスタ内のどれかと通信ができればデプロイが走るためサーバがどれだけ増えても困ることがありません。
またGemのリポジトリから削除されたものがあったりした時に、bundle installできなくてスケールアウトできないと言ったトラブルもあったため、S3に全てアップしました。
Gemのリポジトリを自前で作成することも考えましたが、できるだけ管理するものは減らしたいと思い構築しておりません。
監視についてはそこまで説明することはないのですが、ConsulにはNode監視機能がついています。
現状リクエストが正常に200返っているか程度しか見ていません。
ServerSpecとか流してもいいのかなぁと思っていますが現状保留しています。
あとConsulには便利なコマンドがあり、consul exec [お好きなコマンド]
で各サーバでコマンドが走りレスポンスが返ってきます。
特にConsulを使って何かするわけでもないのですが、他サービスでこのためだけに(Serfの時もありますが)入れてるサーバがあったりします。
$ consul exec hostname
hoge-1: ip-10-10-10-01
hoge-1:
==> hoge-1: finished with exit code 0
fuga-1: ip-10-10-10-02
fuga-1:
fuga-2: ip-10-10-10-03
fuga-2:
==> fuga-1: finished with exit code 0
piyo-1: ip-10-10-10-04
piyo-1:
==> fuga-2: finished with exit code 0
==> piyo-1: finished with exit code 0
piyo-2: ip-10-10-10-05
piyo-2:
==> piyo-2: finished with exit code 0
5 / 5 node(s) completed / acknowledged
$
Vagrant
Vagrantもあまり説明する必要がない気もしますが、各自の開発環境の構築に使用しています。
こちらまだ途中で完成はしていないのですが、CoreOSとDockerでローカル環境を構築しようと思っています。
まだそれほど試すことができてないのですが、TerraformとPackerもあるのでOttoで持っていけると嬉しいです。
Atlas
こちらは今回使用していませんが、検討した結果使用しませんでした。
AtlasはHashiCorpツールを集約してくれるため非常に便利でしたが、10node以降課金のため見送りました。
確かに便利ですが、現状そこまで活用することが多くなかったため運用でカバーすることにしました。
デプロイ方法について
Canary Deploymentsはあまり名前は知られてないのですが、本番稼働しているサーバに複数本番環境を用意することで弊社解決しています。
- /var/www/unicorn_app_a -> port 8081
- /var/www/unicorn_app_b -> port 8082
上記のような設定をした上でNginxを前段に置き、80 -> 8081 or 80 -> 8082 の切り替えを行っております。
さらに事前にある程度動作確認できるように、自社専用の回線からのみ直接8081と8082を見れるような設定にすることで本番切り替え前テストをしています。
運用してみて思うこと
サービス開始してまだ数日なのであまりアプリケーションエンジニアからのフィードバックは得られていません。
とりあえず運用上一番重要なサービスダウンですが、一度も発生しておりません。
またConsul execが便利で開発段階でも何かとトラブルがあったりした時調査に役立ちました。
他にもConsulのKey Valueは curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key1
という形で変更できるため自前のツールが非常に作成しやすいです。
開発してて楽しいのですが、現状インフラを一人で担当しているため新しいツールの導入により属人化が進んでる気はしてます。
しかし、これからインフラを始める人が始めやすい環境を作っていきたいとは常に考えております。
最後に
弊社ではHashiCorpだけではなく様々な技術を使用してWebサービスを運用しています。
今回さらっと紹介しましたが最近話題のElixirなども使っていたりします。
興味のある方は是非こちらから応募を!