Auto Scaling環境でのBlue-Green Deploymentの切替がAWS ELBでできるようになりました。

ELB
317件のシェア(そこそこ話題の記事)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

超おはようございます。最近パンケーキを昼食にできるようになった城内です。
今回は、Auto Scalingのアップデートにより、AWSでのBlue-Green Deploymentの方式に新たな選択肢が増えたことを喜びたいと思います。

Auto Scalingのアップデート

先日のAuto Scalingのアップデートにより、Auto Scalingグループに対するELBの付け外しができるようになりました。

何が嬉しいのか?

従来、Auto Scalingに紐づくELBは変更することができず、AWS上でBlue-Green Deploymentの切替を行おうと思ったときには、DNSベース(Route53)の切替しかできませんでした。しかし、今回のAuto Scalingのアップデートにより、ELBでの切替が可能になりました。

切替方法

では、実際の切替方法ですが、いたって簡単です。今回はCLIベースでいきたいと思います。

環境構成

まず、構成は以下のような簡素な構成を前提に実施します。

bg-dev_01

CLIで確認すると、以下のような感じです。

# aws elb describe-load-balancers | jq '.LoadBalancerDescriptions[] | {LoadBalancerName, DNSName}'
{
  "LoadBalancerName": "ELB-A",
  "DNSName": "ELB-A-87373750.ap-northeast-1.elb.amazonaws.com"
}
{
  "LoadBalancerName": "ELB-B",
  "DNSName": "ELB-B-55201029.ap-northeast-1.elb.amazonaws.com"
}

# aws autoscaling describe-auto-scaling-groups | jq '.AutoScalingGroups[] | {AutoScalingGroupName, LoadBalancerNames, Instances}'
{
  "AutoScalingGroupName": "AutoScalingGroup-A",
  "LoadBalancerNames": [
    "ELB-A"
  ],
  "Instances": [
    {
      "InstanceId": "i-0d21ceff",
      "AvailabilityZone": "ap-northeast-1a",
      "HealthStatus": "Healthy",
      "LifecycleState": "InService",
      "LaunchConfigurationName": "webserver-20150618-01"
    }
  ]
}
{
  "AutoScalingGroupName": "AutoScalingGroup-B",
  "LoadBalancerNames": [
    "ELB-B"
  ],
  "Instances": [
    {
      "InstanceId": "i-8f21ce7d",
      "AvailabilityZone": "ap-northeast-1a",
      "HealthStatus": "Healthy",
      "LifecycleState": "InService",
      "LaunchConfigurationName": "webserver-20150618-01"
    }
  ]
}

Green環境の本番組み込み

上記の構成から、本番アクセスがGreen環境(AutoScalingGroup-B)へも流れるようにします。Blue環境(AutoScalingGroup-A)に紐づいているELB-AをGreen環境にも取り付けます。

# aws autoscaling attach-load-balancers --auto-scaling-group-name 'AutoScalingGroup-B' --load-balancer-names 'ELB-A'

# aws autoscaling describe-auto-scaling-groups | jq '.AutoScalingGroups[] | {AutoScalingGroupName, LoadBalancerNames, Instances}'
{
  "AutoScalingGroupName": "AutoScalingGroup-A",
  "LoadBalancerNames": [
    "ELB-A"
  ],
  "Instances": [
    {
      "InstanceId": "i-0d21ceff",
      "AvailabilityZone": "ap-northeast-1a",
      "HealthStatus": "Healthy",
      "LifecycleState": "InService",
      "LaunchConfigurationName": "webserver-20150618-01"
    }
  ]
}
{
  "AutoScalingGroupName": "AutoScalingGroup-B",
  "LoadBalancerNames": [
    "ELB-A",
    "ELB-B"
  ],
  "Instances": [
    {
      "InstanceId": "i-8f21ce7d",
      "AvailabilityZone": "ap-northeast-1a",
      "HealthStatus": "Healthy",
      "LifecycleState": "InService",
      "LaunchConfigurationName": "webserver-20150618-01"
    }
  ]
}

ここでは以下のような状態です。

bg-dev_02

Green環境への本番切替

上記では、Blue環境とGreen環境が両方本番環境として動作しています。ここから、Blue環境を切り離し、本番アクセスをGreen環境に完全に切り替えます。
オペレーションとしては、Blue環境からELB-Aを取り外し、Green環境からELB-Bを取り外します。

# aws autoscaling detach-load-balancers --auto-scaling-group-name 'AutoScalingGroup-A' --load-balancer-names 'ELB-A'

# aws autoscaling detach-load-balancers --auto-scaling-group-name 'AutoScalingGroup-B' --load-balancer-names 'ELB-B'

# aws autoscaling describe-auto-scaling-groups | jq '.AutoScalingGroups[] | {AutoScalingGroupName, LoadBalancerNames, Instances}'
{
  "AutoScalingGroupName": "AutoScalingGroup-A",
  "LoadBalancerNames": [],
  "Instances": [
    {
      "InstanceId": "i-0d21ceff",
      "AvailabilityZone": "ap-northeast-1a",
      "HealthStatus": "Healthy",
      "LifecycleState": "InService",
      "LaunchConfigurationName": "webserver-20150618-01"
    }
  ]
}
{
  "AutoScalingGroupName": "AutoScalingGroup-B",
  "LoadBalancerNames": [
    "ELB-A"
  ],
  "Instances": [
    {
      "InstanceId": "i-8f21ce7d",
      "AvailabilityZone": "ap-northeast-1a",
      "HealthStatus": "Healthy",
      "LifecycleState": "InService",
      "LaunchConfigurationName": "webserver-20150618-01"
    }
  ]
}

最終的な状態は以下の通りです。

bg-dev_03

動作確認

上記作業の動作確認は、以下のようなPHPを作って確認してみました。

<?php
require '/usr/local/aws/sdk-php/vendor/autoload.php';

$url = "http://169.254.169.254/latest/meta-data/instance-id/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$instid = curl_exec($ch);
curl_close($ch);

use Aws\AutoScaling\AutoScalingClient;

$client = AutoScalingClient::factory(array(
        'region'  => 'ap-northeast-1'
));
$result = $client->describeAutoScalingInstances(array(
        'InstanceIds' => array($instid)
));

$asg = $result['AutoScalingInstances'][0]['AutoScalingGroupName'];

if ($asg) {
        $msg = 'This instance (<strong>'.$instid.'</strong>) is attached to \'<strong>'.$asg.'</strong>\' AutoScalingGroup.';
} else {
        $msg = 'This instance is not attached to AutoScalingGroup.';
}

echo <<<EOT
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test Page</title>
</head>
<body>
<p>$msg</p>
</body>
</html>
EOT;

ブラウザでアクセスすると、どちらのAuto Scalingグループにアクセスしているのかが分かります。
切替がうまくいけば、以下のようにELB-AへのアクセスがBlue環境(AutoScalingGroup-A)からGreen環境(AutoScalingGroup-B)に切り替わります。

bg-dev_04
bg-dev_05

まとめ

うーん、いい感じに切り替えられますね!今回はあえて段階を踏んで切替を行いましたが、ほぼ一瞬で切替が可能です。DNSベースでの切替でもダウンタイムは発生しませんでしたが、DNSのキャッシュを考慮する必要がありました。今回の方法では、そんなことも気にせずにスパッと切り替えられて、とても気持ちいいですね。

参考情報