AWS CodeDeployでWindowsのCloudWatchカスタムメトリクス設定を自動化する

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

ども、大瀧です。
AWS re:Inventで発表された新サービスAWS CodeDeploy、皆さん触ってますか?シンプルな設定と柔軟なローテーション機能で、EC2のアプリケーション管理が楽になるのでは、と期待しています。今回はCodeDeployのユースケースとして、最近サポートされたEC2(Windows)でのCloudWatchカスタムメトリクス設定の自動化をご紹介します。

「CloudWatchカスタムメトリクス設定のどこかアプリケーション管理なんだ?」とツッコまれそうですが、CodeDeployはインスタンスへのファイル転送コマンド実行のオペレーションができるので、純粋なアプリケーション管理以外に今回のようなシステム/サービス構成にも応用することができます。

CloudWatchカスタムメトリクス設定とは

CloudWatchカスタムメトリクスは、ユーザーが用意した統計情報をCloudWatchに記録させる仕組みです。最近、Windows AMIにプリインストールされるEC2ConfigにCloudWatchカスタムメトリクス送信機能が追加され、Windowsのパフォーマンスモニターの任意のメトリクスを送れるようになりました。いざ設定してみようとするとJSONファイルを編集するなど設定が面倒なので、CodeDeployの活用を思いついた次第です。

設定方法は、以下の佐々木のブログエントリーが詳しいです。

Application Revisionの作成

CodeDeployは、配置するファイルと実行するべきコマンド定義をApplication Revisionとしてあらかじめ作成しておきます。といってもその造りは非常にシンプルで、任意のディレクトリ内に全体の設定となるappspec.ymlファイルと、そのファイルで参照されるファイル/スクリプトを作成するだけです。今回のApplication RevisionはGitHubにまとめてアップしておきました。

まずは、ファイル/ディレクトリ構造を示します。

$ tree aws-codedeploy-win-cloudwatch/
aws-codedeploy-win-cloudwatch/
├── Settings
│   ├── AWS.EC2.Windows.CloudWatch.json
│   └── config.xml
├── appspec.yml
├── remove_previous_configs.bat
└── restart_service.bat

1 directory, 5 files
$

appspec.ymlを見てみましょう。

version: 0.0
os: windows
files:
  - source: Settings
    destination: C:\Program Files\Amazon\Ec2ConfigService\Settings
hooks:
  BeforeInstall:
    - location: remove_previous_configs.bat
      timeout: 30
  ApplicationStart:
    - location: restart_service.bat
      timeout: 60
  • filesのリストには、配置するファイル/ディレクトリのコピー元をsource、コピー元をdestinationで指定します。今回はCloudWatchカスタムメトリクスに関する設定ファイル2つがSettingsディレクトリ以下にあるので、これらを所定のフォルダにコピーします。
  • hooksのリストには、実行するスクリプトとタイミングを指定します。タイミングは、以下の図の通りファイルコピーを行うInstallの前後で5つのイベントフック(下図の黄色の項目)から選択できます。

app_hooks

では、各ファイルを簡単に解説します。
コピーする設定ファイルのうち、Settings/config.xmlファイルは、EC2Configの設定ファイルです。デフォルトではCloudWatchプラグインが無効なので、これを有効にしています。

	  :
	<Name>AWS.EC2.Windows.CloudWatch.PlugIn</Name>
	<State>Enabled</State>
	  :

Settings/AWS.EC2.Windows.CloudWatch.jsonファイルは、CloudWatchプラグインの設定ファイルです。今回はCドライブの空き容量とメモリの利用可能サイズをカスタムメトリクスとして設定しています。

{
    "EngineConfiguration": {
        "PollInterval": "00:00:15",
        "Components": [
            {
                "Id": "PerformanceCounterFreeSpace",
                "FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "CategoryName": "LogicalDisk",
                    "CounterName": "% Free Space",
                    "InstanceName": "C:",
                    "MetricName": "DiskFree",
                    "Unit": "Percent",
                    "DimensionName": "InstanceId",
                    "DimensionValue": "{instance_id}"
                }
            },
            {
                "Id": "PerformanceCounterMemoryAvailable",
                "FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters": {
                    "CategoryName": "Memory",
                    "CounterName": "Available MBytes",
                    "InstanceName": "",
                    "MetricName": "MemoryAvailable",
                    "Unit": "Megabytes",
                    "DimensionName": "InstanceId",
                    "DimensionValue": "{instance_id}"
                }
            },
            {
                "Id": "CloudWatch",
                "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatch.CloudWatchOutputComponent,AWS.EC2.Windows.CloudWatch",
                "Parameters":
                {
                    "AccessKey": "",
                    "SecretKey": "",
                    "Region": "us-west-2",
                    "NameSpace": "Classmethod/EC2"
                }
            }
        ],
        "Flows": {
            "Flows":
            [
                "(PerformanceCounterFreeSpace,PerformanceCounterMemoryAvailable),CloudWatch"
            ]
        }
    }
}

続いて、実行するスクリプトです。Windowsの場合はスクリプトファイルの拡張子でインタプリタが決まります。今回はシンプルにバッチファイル(*.bat)にしましたが、PowerShellスクリプト(*.ps1)も利用できるようです。ただし、CodeDeployエージェントがスクリプトファイルをそのまま実行するようなので、WindowsのバージョンによってはPowerShellスクリプトの実行にはExecutionPolicyの調整が必要かもしれません。

remove_previous_configs.batファイルは、設定ファイルをコピーする前に変更前の設定ファイルを削除するオペレーションを記述しています。CodeDeployのファイルコピーは既存ファイルがある場合、エラーになるためです。

del "C:\Program Files\Amazon\Ec2ConfigService\Settings\AWS.EC2.Windows.CloudWatch.json"
del "C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml"

restart_service.batファイルは、設定ファイルを反映させるためにコピー後にサービスを再起動するオペレーションです。

net stop ec2config
net start ec2config

事前準備

続いて、AWS環境で事前に準備する項目を示します。

  1. IAMロールの設定
  2. EC2インスタンスの設定

1. IAMロールの設定

CodeDeployではIAMロールを前提とした設計になっていて、以下2つのIAMロールを準備しておく必要があります。

  1. CodeDeployサービスのロール
  2. EC2インスタンスのロール

codedeploy-cw52

CodeDeployサービスのロールは、サービス許可設定のTrust Relationshipの部分が複雑なので、インスタンスのロールとセットでCloudFormationで作成するテンプレートを用意しました。手動で作成する場合は、こちらのブログエントリーを参考にしてください。

CloudFormationスタックを作成

CloudFormationスタックの作成画面が表示されたら、ウィザードを進めていきます。オレゴンリージョン(us-west-2)が指定されますが、バージニアリージョン(us-east-1)で試したい場合は画面右上のリージョン一覧から切り替えてください。

codedeploy-cw11

[Next]を2回クリックして進め、[Capabilities]の「I acknowledge that this template might cause AWS CloudFormation to create IAM resources.」のチェックをオンにし、[Create]で作成がスタートします。

codedeploy-cw12

スタックの[Status]列が「CREATE_COMPLETE」になったら完了です。[Output]タブを確認します。

codedeploy-cw13

CodeDeployTrustARNがCodeDeployサービスのロールのARN(このあとCodeDeployの設定で必要)、InstanceProfileがインスタンスに紐付けるロールです。インスタンスのロールはS3がCodeDeployのために必要なアクションで、それ以外は任意の設定が可能です。cloudwatch:PutMetricDataは今回のカスタムメトリクス送信のために追加したものです。

{
    "Statement": [
        {
            "Action": [ 
                "s3:Get*",
                "cloudwatch:PutMetricData"
            ], 
            "Effect": "Allow", 
            "Resource": "*"
        }
    ]
}

ちなみにこのCloudFormationテンプレートもGitHubにアップしています。

2. EC2インスタンスの設定

CodeDeployおよびEC2インスタンスは、リージョンごとの設定になるので、CodeDeployと同じリージョンに配置する必要があります。現時点では、バージニアリージョン、オレゴンリージョンのみです。今回は、オレゴンリージョンに作成しました。

Windowsインスタンスでは、先ほどのロールの設定とCodeDeployエージェントのインストールを行います。ロールはインスタンスの作成時にしか指定できないので、既存インスタンスですとロールの割り当てがない場合は作り直しになります。なんらかのロールが割り当て済みの場合は、ロールの権限を調整してください。CodeDeployエージェントのインストールは、所定のコマンドを実行します。今回はユーザーデータとして以下を起動時に指定しました。

<script>
if not exist "c:\temp" mkdir c:\temp
powershell.exe -Command Read-S3Object -BucketName aws-codedeploy-us-west-2/latest -Key codedeploy-agent.msi -File c:\temp\codedeploy-agent.msi 
c:\temp\codedeploy-agent.msi /quiet /l c:\temp\host-agent-install-log.txt
powershell.exe -Command Get-Service -Name codedeployagent
</script>

AutoScalingを利用しない場合、CodeDeployからはインスタンスのタグ単位で指定することになります。今回は後の手順でNameタグを指定していますが、同じタグのインスタンスもCodeDeployの対象になってしまうため場合によってはCodeDeploy用のタグをインスタンスに追加するとよいでしょう。作成したインスタンスは以下になります。

codedeploy-cw53

CodeDeployの構成

準備ができましたので、CodeDeployの構成を進めていきます。CodeDeployの管理画面から[Get Started Now]をクリックし、ウィザードを表示します。今回は[Custom Deployment]を選択し、[Skip Walkthrough]ボタンをクリックします。

codedeploy-cw01

[Create New Application]では、[Application Name]と[Deployment Group Name]は任意の名前を指定できます。今回はどちらも「CloudWatchCustomMetrics」と入力しました。

codedeploy-cw02

[Add Amazon EC2 Instances]では、デプロイの対象インスタンスの条件となるタグを指定します。今回は、[Name]タグが「CodeDeployTest」のインスタンスとしました。

codedeploy-cw03

[Deployment Configuration]は、デプロイの同時実行数を選択します。ELBのバックに配置する場合は全台同時にサービスが停止しないよう配慮が必要ですが、今回のような1台ずつ独立した動きで一括設定を行う場合は全台一度に実行するAllAtOnceで問題ないでしょう。[Service Role]では、事前準備で作成したCodeDeployサービスロールのARNを選択し、[Create Application]でApplicationを作成します。

codedeploy-cw04-1

Applicationの画面に切り替わります。ここにApplication Revisionを追加するのですが、S3の場合Managent Consoleにはアップロード画面がなくAWS CLIで対応することになります。

codedeploy-cw05-1

Application Revisionのアップロード

続いて、Application RevisionをS3にアップロードするために、あらかじめ任意の名称でS3バケットを作成します。注意点として、CodeDeployおよびインスタンスを実行するリージョンと同一リージョンにS3バケットを用意する必要があります(CodeDeployエージェントからアクセスするS3のエンドポイントが固定?)。

codedeploy-cw51

Application Revisionのアップロードは、AWS CLIの専用のaws deploy pushコマンドで実行します。デプロイするファイルはあらかじめアーカイブする必要はありません。

オプション名
region AWSリージョン
application-name Application名
description Application Revisionの説明
s3-location 任意のアーカイブファイル名を以下の形式で指定
s3://<S3バケット名>/<任意のアーカイブファイル名>.zip
source Application Revisionを作成したローカルのディレクトリパス
$ cd aws-codedeploy-win-cloudwatch/
$ aws deploy push \
>   --region us-west-2 \
>   --application-name CloudWatchCustomMetrics \
>   --description CloudWatchCustomMetrics \
>   --ignore-hidden-files \
>   --s3-location s3://takipone-codedeploy-us-west-2/CloudWatchCustomMetrics.zip \
>   --source .
To deploy with this revision, run:
aws deploy create-deployment --application-name CloudWatchCustomMetrics --s3-location bucket=takipone-codedeploy-us-west-2,key=CloudWatchCustomMetrics.zip,bundleType=zip,eTag="d8a30556fd8399f5c947f417c4030279" --deployment-group-name <deployment-group-name> --deployment-config-name <deployment-config-name> --description <description>
$

これで準備OKです。

デプロイ実行!

CodeDeployの管理画面に戻り[Revisions]のリストを更新すると、アップロードしたApplication Revisionが確認できます。左端の三角をクリックし詳細を表示し、[Deploy This Revision]ボタンをクリックします。

codedeploy-cw06

[Deployment Group]は「CloudWatchCustomMetrics」を選択し、その他の項目はデフォルトのままでOKですが[Deployment Description]にコメントを残しておくと後で確認するのが楽なので適当に入力すると良いでしょう。「Deploy Now」ボタンをクリックし、デプロイがスタートします。

codedeploy-cw07

codedeploy-cw08

Deployments画面に切り替わり、デプロイのリストが表示されます。デプロイが成功(Succeeded)になれば完了です!

codedeploy-cw09

動作確認

CloudWatchの画面を表示すると、[Classmethod/EC2]のメトリクスが追加され、ディスクとメモリの空きが表示されました!

codedeploy-cw10

感想とまとめ

ボリューム満載な感じになってしまいましたが、一度作成してしまえばロールは他のApplicationに使い回しできますし、Application Revision/Deploymentの実行も変更したら繰り返しサクサクと実行できてストレス無く構成変更ができ、いい感じです。雰囲気としてはCapistorano as a Serviceと言うのが近い感触です。

BeanstalkやOpsWorksがインスタンス全体の構成を管理する割と大掛かりな仕組みなのに対して、Codedeployはエージェント実行さえできればちょっとしたファイル配置、コマンド実行にバージョン管理がおまけで付いてくる手軽な構成管理ツールとして活用できるのでは、と思います。