Alibaba Cloud、AutoScalingを使ってブルーグリーンデプロイメントを行う


## はじめに
<a href="https://jp.aliyun.com/" target="_blank">Alibaba Cloud</a>の<a href="https://jp.aliyun.com/product/auto-scaling" target="_blank">AutoScaling</a>を利用した際のブルーグリーンデプロイメントについて書きます。
前半の話はAlibaba Cloudに関係なく、クラウド環境を利用したデプロイ方法として考え方は共通のものです。
この記事では、入門編ということでWebコンソールからの手動でのデプロイ方法を中心に書きます。
手順や考え方がわかれば当然自動化でき、クラウドでのCI/CDの実現につながります。

## クラウド上でのデプロイパターン
クラウド上でのデプロイの方法にはいくつかあると思いますが、ここでは代表的な２つをご紹介します。
オンプレのときからおなじみの既存サーバに対して変更を加えていくパターンと、クラウドの特徴をいかした新しいサーバを作ってしまおうというパターンの２つです。

### 通常デプロイパターン
従来のオンプレのときと同様に、すでに稼働しているサーバで設定の変更やアプリケーションのバージョンアップを行う方法がまずあります。
既存のサーバにバージョンアップしていくので、考え方はシンプルでわかりやす。一方で、大きな修正をした際の切り戻しが大変という面があります。

また、クラウド環境の場合はサーバ台数が増減することがあり1台ずつ行うことは必ずしも適切でありません。
そこで、クラウドサービスのAPIを活用し、デプロイするサーバのリストを取り出し、AnsibleやChefなどを用いて一括でデプロイすることはよく行います。

### イメージデプロイパターン
クラウドではサーバの作成・削除が容易にできることが特徴のひとつです。その特徴を活かしデプロイに利用します。
まず、アプリケーションのバージョンアップをする場合、新しいバージョンが動いているサーバのイメージを作成します。現在稼働しているサーバーとは別に、新しく作成したイメージでサーバーを構築します。
サーバの構築が完了したら、ロードバランサーで向き先を新しいサーバに変更しデプロイします。もしも新しいサーバーに問題があった場合は、即座に古いサーバーにロードバランサーの向き先を戻して切り戻しできます。
デプロイに成功したら、古いサーバは消してしまいます。
一般的に、このようなデプロイの方法を「ブルーグリーンデプロイメント」とよんだりします。

ブルーグリーンデプロイメント自体は、オンプレミスでも大規模な改修などでは行われることもありますが、クラウド上では気軽にできるので利用されることがおおくなってきました。

### 各デプロイパターンの概要図
![スクリーンショット 2017-05-23 14.20.08.png](https://qiita-image-store.s3.amazonaws.com/0/259/76469032-315e-4ad2-c031-b28eedb556c6.png "スクリーンショット 2017-05-23 14.20.08.png")

## AlibabaCloudでのブルーグリーンデプロイメント
一般的な話はこのくらいにして、AlibabaCloud上でAutoScalingしたブルーグリーンデプロイメントの方法について解説します。
AlibabaCloud上でのAutoScalingの設定手順から説明していきます。

### 事前準備
例えば、下の図の用にスケーリング設定をイメージ`image-version-1.0`のインスタンスで設定していたとします。

![スクリーンショット 2017-05-24 14.56.09.png](https://qiita-image-store.s3.amazonaws.com/0/259/253657f9-3ac5-a63c-08d4-e1902330a9be.png "スクリーンショット 2017-05-24 14.56.09.png")

アプリケーションあるいは、インフラのバージョンアップでイメージを`image-version-2.0`を作成しました。
どうやってデプロイしていけばいいのでしょうか。

### スケーリング設定を追加する
まずは、新しいイメージのスケーリング設定をします。
スケーリング設定とは、AutoScalingがどのイメージでどのスペックでサーバをスケールさせるか決定させる設定です。
新しくデプロイする`image-version-2.0`を指定したスケーリング設定を行います。

![スクリーンショット 2017-05-24 16.33.19.png](https://qiita-image-store.s3.amazonaws.com/0/259/b53011b3-6c54-fd1f-1ba9-f0ef83f7129d.png "スクリーンショット 2017-05-24 16.33.19.png")


### 新しインスタンスを追加する
新しいイメージのインスタンスを追加します。
追加する方法はいろいろありますが、スケーリングルールの手動実行がおすすめです。
ここでは、「ECSを2台追加する」というスケーリングルールを作成し、「実行」ボタンを押します。

![スクリーンショット 2017-05-24 19.28.02.png](https://qiita-image-store.s3.amazonaws.com/0/259/8861bc6d-617f-3483-d394-93fd8d996729.png "スクリーンショット 2017-05-24 19.28.02.png")

実際に「ECSインスタンスリスト」からインスタンスの追加がされたか確認してみます。
ECSの管理コンソールから確認しても問題ありません。
現在は新しいインスタンスと古いインスタンスが混じった状態で、ロードバランサーの重みはすべて等しい状態となっていることがわかります。

![スクリーンショット 2017-05-25 9.25.54.png](https://qiita-image-store.s3.amazonaws.com/0/259/5b59e5be-c97c-d851-c710-2b3871041336.png "スクリーンショット 2017-05-25 9.25.54.png")

### SLBの重みの変更する
この手順はオプションです。行わずに次の項目に進んでもらっても構いませんが、このオペレーションを行うことでよりデプロイ作業の成功率は高まると思います。
徐々に古いサーバの重みを減らしていくと、大きな影響がなく切り替えができます。

![スクリーンショット 2017-05-24 16.08.44.png](https://qiita-image-store.s3.amazonaws.com/0/259/51ae6de4-7dbe-f0ec-ca3c-7225771718b4.png "スクリーンショット 2017-05-24 16.08.44.png")

SLBの重み（分散比率）はSLBコンソールから変更することが可能です。
必要に応じて変更してください。

![スクリーンショット 2017-05-25 9.30.16.png](https://qiita-image-store.s3.amazonaws.com/0/259/9499f948-99ce-47ef-8f5e-ae776eeb21c5.png "スクリーンショット 2017-05-25 9.30.16.png")


### 古いインスタンスの削除する
新しく追加したインスタンスでの動作が確認できたら、古いインスタンスを削除します。
AutoScalingのコンソール画面から「スケーリンググループからの削除とリリース」を選択し、対象のインスタンスを削除します。
削除する対象を間違えないように必ずスケーリンググループ名などは確認するといいです。
![スクリーンショット 2017-05-25 9.33.12.png](https://qiita-image-store.s3.amazonaws.com/0/259/116b93f7-0547-e811-9664-db5e7260a416.png "スクリーンショット 2017-05-25 9.33.12.png")


### おまけ
通常型のデプロイで、クラウド上のサーバに一括でデプロイしたいことがあります。AutoScalingを利用しているとサーバの台数は日々増減しますので、APIを利用してインスタンリストを管理するといいです。

参考例ではあるが、PHPのAlibaba Cloud SDKを使って、Ansibleのinventryリストを生成するなどして活用した経験があります。
以下はサンプルで、`staging-server`という名前のつくECSインスタンスの一覧を取り出し、そのIPアドレスを配列に入れるところまでのコードです。

```php
include_once './lib/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Config.php';
use Ecs\Request\V20140526 as Ecs;
$iClientProfile = DefaultProfile::getProfile(
  "ap-southeast-1",
  $_SERVER['ALIYUN_KEY'],
  $_SERVER['ALIYUN_SECRET']
);
$client = new DefaultAcsClient($iClientProfile);
$target_ipaddress = array();

// Check if staging server exists
$request = new Ecs\DescribeInstancesRequest();
$request->setMethod("GET");
$response = $client->getAcsResponse($request);
$instances = $response->Instances->Instance;
foreach($instances as $instance) {
    $pattern = '/staging-server/';
    if(preg_match($pattern, $instance->InstanceName)){
        array_push($target_ipaddress, $instance->InnerIpAddress->IpAddress[0]);
    }
}
```