tjinjin's blog

インフラ要素多めの個人メモ

pull型デプロイとAutoScallingの相性が結構よかった話

About

私が担当しているインフラ環境で先日インスタンス障害がありましたが、pull型デプロイにしていたからか自動でインスタンスが復旧できたので嬉しさのあまり記事にしてみます。

技術スタック

  • consul + stretcher
  • Autoscaling

AutoScalingにした際のゴールデンイメージ問題

AutoScallingをさせるにはアプリが全部入りのAMIが必要です(AMIを起動させた時点でサービスインできる状態)。ただ、更新が多いアプリだと更新の度にAMIを作るの時間かかりますよね…。1日10回デプロイするなんてことになったら、CIでやるにしろそれなりの時間がかかるのでかなり面倒くさいです…。CI環境が潤沢でないと専有して大変なことに…。

そこをpull型デプロイで解決します。インスタンス起動時に最新のアプリケーションを取得・デプロイするようにします。

pull型デプロイについて

いろいろな記事ありますが、今回のケースだとS3上に最新のアプリがあり、各インスタンスがそれをpullして自分自身にデプロイするような形です。こちらの資料を読むとよりわかりやすいと思います。

tech.feedforce.jp

ざっくりとしたイメージは下記のようになります。

f:id:cross_black777:20160716001543p:plain

web/batchサーバがいてconsul clusterを形成しています。consul eventが発火されるとeventに基いてS3上にあるmanifestファイルと呼ばれるファイルを取得し、そのファイルをparseし、その設定にもとづきアプリのデプロイをします。manifestはデプロイするファイルとどういう手順を踏むかが書いてあると思えばよいです。

この仕組みを応用し、インスタンス起動時に最新の状態を目指します。

インスタンス起動の流れ

インスタンス起動時に最新のミドルウェア・アプリケーションを導入したいため、launch_configurationの設定にあるuser_dataを使って初回のプロビジョニング・デプロイをしています。(Terraformで定義しています)

resource "aws_launch_configuration" "prod_api_blue" {
    name_prefix = "${var.stage}-blue-api-"
    image_id = "${var.blue_ami}"
    instance_type = "${var.api_blue_instance_type}"
    iam_instance_profile = "${var.project_name}-${var.stage}-instance"
    key_name = "${var.key_name}"
    security_groups = ["${aws_security_group.private_instances.id}"]
    user_data = "${file("./user_data/boot-blue.sh")}"

    root_block_device {
        delete_on_termination = true
    }

    lifecycle {
        create_before_destroy = true
    }
}
# provisioning
echo "s3://<hogehoge>/manifests/manifest_${role}_${stage}.yml" | stretcher

# deploy
echo "s3://<hogehoge>/manifests/manifest_${role}_${stage}.yml" | stretcher

通常のプロビジョニング・デプロイはconsul event経由で行ってますが、consul event経由だと他のnodeにイベントが伝播してしまい、例えば複数台インスタンスを起動した際にイベントが重複してしまうので、直接stretcherを実行しています。今の所問題は出ていないです。

GitHub - fujiwara/stretcher: Deployment tool with consul/serf event notification.

この前起きた障害時の流れ

  1. インスタンスが突然死亡
  2. AutoScallingの機能で新しいインスタンスが勝手に起動する
  3. インスタンスが起動する際にcloud-initが実行されその中でuser_dataが実行される
  4. stretcherが実行されプロビジョニング・デプロイされる
  5. ELBのヘルスチェックが通ったタイミングでサービスインし、元の状態に戻る

インスタンスが死亡しても一次対応しなくていいってステキですね!!!インスタンスガチャ怖くない!

この構成のデメリット

インスタンス起動時にプロビジョニング・デプロイが走るので、サービスインまでに多少時間がかかります。サービスのアクセス急増などによりスケールアウトするというケースだと遅すぎるかもしれません。現在のサービスの特性として、急激なアクセス増などはないので、障害の一次対応をインフラエンジニアが対応しなくていいという点では大きなメリットがあると思います。

まとめ

pull型デプロイにはその他にもメリットがありますが、今回実際に障害に直面してほんとこの構成にしてよかったと思いました!今後、サービスをコンテナ化していくにしろ、安心して眠れるインフラ環境を目指していきたいと思います!

参考

社内でpull型デプロイの話をした際のスライドとか

社内勉強会でデプロイ周りの話をしました - tjinjin's blog