本日も乙

ただの自己満足な備忘録。

Vuls運用のためのBlue-Green Deploymentパターン

本記事はVuls Advent Calendar 2017 12日目の記事です。

qiita.com

本当はサーバレスVulsの話でも書こうと思ったのですが、いい加減引っ張り過ぎ感があったので今回は別の話にしたいと思います(でも18日の記事はサーバレスVulsについて書くかもしれません)。

テーマは「Blue-Green Deployment」です。
Vulsと直接関係が薄いテーマかもしれませんが、ヒントはSoftware Design 2017年10月号にありました(皆さんすでに買われてますよね!?)。

「バッチを適用しやすい仕組み」節で、Blue-Green Deploymentによってパッケージのアップデートをしやすい構成にしていく必要性を挙げられていました。「Blue-Green Deploymentの特徴やメリットは分かったけど、実際にどうやって実現すればいいのだろう」と思う方も少なくないと思います。

私は業務でAWSを使っており、AWSにおけるBlue-Green Deploymentについて色々調べてみると、AWSが出しているブログ記事とホワイトペーパーに行き着くことになります。

この2つを読んでおしまい!とこれで終わっては寂しいので、本記事ではこれらをベースにBlue-Green Deploymentの構成をいくつか紹介していきます。

目次

そもそも Blue-Green Deploymentってなに?

簡単に言えば、現行システムである、Blueと全く同じ構成のGreenを構築し、BlueからGreenに切替えるデプロイ方法です。Blueには何もしないでGreenの方にデプロイしておき、スイッチするだけでGreenに切り替わることでデプロイからリリースにかかる時間の短縮ができます。また、万が一問題が生じた場合は即座にBlueに戻すことで容易にロールバックすることができます。

AWSなどのIaaSを活用することで、Greenシステムの構築に時間をかけずに短時間でデプロイができるようになってきました。

なぜ Blue-Green Deploymentなのか

デプロイと聞くとソフトウェアに関するイメージが強いですが、私はインフラ系こそBlue-Green Deploymentを活用すべきだと考えています。

一般的なデプロイ(In-Place:置き換え)で、パッケージアップデートを行おうとするのは極めて危険です。なぜなら、アップデート後に何かしらの不具合が出る可能性があるからです。また、一旦アップデートした後に元に戻すのはかなり大変ですし、そもそもカーネルをアップデートしたらOSの再起動が必要になるので、サービスを止めなければならなくなります。

一方で、Blue-Green Deploymentであれば、Greenシステムにパッケージをアップデート、再起動をしておき、事前に問題が無いかを検証しておくことで、安全に運用することができます。

構成パターン

では、次から実際にAWSにおいてどのように実現していけばいいのかを見ていきます。

Classic DNS Cutover、Route53 Weighed DNS Switching

Blue/GreenそれぞれにELB+EC2+Auto Scaling Group(ASG)の組み合わせのシステムを構築しておきます。事前にBlueのELBにRoute53でDNSレコードを登録しておき、切替時にGreenのELBのDNSレコードを登録することで向き先を変えます。

https://contents.blog.jicoman.info/2017/12/blue-green-deployment-1.png ※ 図はホワイトペーパーから借りています。

また、Weighted Round Robin(WRR)を利用することで、徐々にリクエストをGreenに流していくこともできるのでより安全に切替えることが可能です。

https://contents.blog.jicoman.info/2017/12/blue-green-deployment-2.png ※ 図はホワイトペーパーから借りています。

この方法のメリットは、Auto Scalingに対応していなくても実現可能である点です。 後に紹介するパターンはAuto Scalingやコンテナに対応する必要がありますが、この手法はELBとEC2の構成さえ整えれば切り替えができます。 また、手順があまり複雑でないため、ツールを自作しなくても手動での切り替えが比較的容易です(ただし作業ミスには注意)。

デメリットは、DNSのTTLに注意しなければならず切り替え後もクライアント側でDNSキャッシュが残っている可能性があるため、完全に切替えるまでに時間がかかることです。
そういった意味では、少々使い勝手が悪い手法といえるでしょう。

Swap Auto Scaling Group

ELBに対して複数のASGをアタッチできる仕組みを利用します。 BlueのASGがELBにアタッチされている状態で、GreenのASGを作成し、インスタンスを起動・デプロイしておきます。Green ASGの準備が整ったらELBにアタッチします。この時点でBlue/Green 両方のインスタンスが混在している状態になります。

https://contents.blog.jicoman.info/2017/12/blue-green-deployment-3.png ※ 図はホワイトペーパーから借りています。

Green ASGで問題がなければ、Blue ASGのインスタンスを減らしていき、Blue ASGをELBからデタッチすれば切り替え完了です。

https://contents.blog.jicoman.info/2017/12/blue-green-deployment-4.png ※ 図はホワイトペーパーから借りています。

この方法のメリットは、DNSを使わないため、切り替えにかかる時間が短く済むこと、ELBが一つで済むことです。

私が担当しているシステムでAuto Scalingを導入しているサービスはこの方式でBlue-Green Deploymentを実現しています。

Terraformと自作ツールで実現する

この方式のデメリットは、手順が多いため、手動だとミスが起きやすいことです。そのため、私の場合、ツールを自作して切り替えを行っています。

まず、BlueとGreenのASGをTerraformで構築します。ASGの台数やLaunch Configurationは常に変わっていくため、構築後はignore_changesに入れてしまいます。 また、Stateタグというのを付けることでどちらが主システムかを判定できるようにしています。

resource "aws_autoscaling_group" "blue" {
  lifecycle {
    create_before_destroy = true
    ignore_changes        = ["launch_configuration", "max_size", "min_size", "desired_capacity", "tag"]
  }
  tag {
    key                 = "State"
    value               = "active"
    propagate_at_launch = false
  }
}

resource "aws_autoscaling_group" "green" {
  lifecycle {
    create_before_destroy = true
    ignore_changes        = ["launch_configuration", "max_size", "min_size", "desired_capacity"]
  }
}

切り替えの処理は自作ツールで行います。Golangで実装しています。
流れを簡単に書くと、以下のようになります。簡略のため、徐々にインスタンスを切替えるのではなく、ASG丸ごと切替えるようにしています。

  1. パッケージアップデート済みのAMIを作成し、Launch Configurationを作成しておく
  2. Stateタグが付いているASGをBlue(現行)、付いていないASGをGreen(置き換え)とする
  3. Green ASGのLaunch Configurationを0で作成したものに指定する
  4. Min_size、Max_size、Desired_capacityをBlueに揃える
  5. Green ASGのインスタンスが起動したらELBにアタッチし、InServiceになるまで待つ(この時点でBlueとGreenの両方が混在している)
  6. Blue ASGをELBからデタッチし、完全にデタッチするまで待つ
  7. Green ASGで問題がなければ、Blue ASGのインスタンスを削除(Min_size、Max_size、Desired_capacityを0にする)
  8. Green ASGで問題が生じた場合は、Blue ASGをELBにアタッチし、Green ASGをELBからデタッチすることで元に戻す

Swap Launch Configuration

Swap Auto Scaling Groupパターンに近いですが、Auto Scalingの起動設定(Launch Configuration)をアップデートし、古いLaunch Configurationで起動しているインスタンスを徐々に減らすことで切り替えていくパターンです。

パッケージアップデート済のAMI IDを指定したGreen Launch Configurationを作成し、ASGの設定を変更します。設定変更後は、Blue Launch Configuration で起動したインスタンスとGreen Launch Configuration で起動したインスタンスが混在しています。

https://contents.blog.jicoman.info/2017/12/blue-green-deployment-5.png ※ 図はホワイトペーパーから借りています。

Blue Launch Configuration で起動したインスタンスを徐々に減らしていくことで、Green のインスタンスのみが残るようになる仕組みです。

https://contents.blog.jicoman.info/2017/12/blue-green-deployment-6.png ※ 図はホワイトペーパーから借りています。

この方法のメリットはDNSを使わなくても済むこと、Swap Auto Scaling Groupより若干ですが、手順が少なく済むことです。 デメリットは、Swap Auto Scaling Groupと比較して、古い(Blue)のインスタンス削除が少々面倒なことです。

ECSを使ったパターン

時間切れなので、後で更新します :bow:

最後に

Vulsで検知した脆弱性のあるパッケージをアップデートするための仕組みとしてBlue-Green Deploymentの優位性と実現に向けていくつかのパターンを紹介しました。また、私が実際に取り込んでいる方法についても紹介しました。

書いてみて、やはりVulsとの関連性は低いなぁと思いましたが気にしないでおきましょう。 ではまた。

参考