結論
import { custom_resources as cr } from 'aws-cdk-lib';
const installCWAgent = new cr.AwsCustomResource(this, 'InstallCWAgent', {
onUpdate: {
service: 'SSM',
action: 'sendCommand',
parameters: {
DocumentName: 'AWS-ConfigureAWSPackage',
Targets: [
{
Key: 'InstanceIds',
Values: [instance.instanceId],
},
],
Parameters: {
action: ['Install'],
name: ['AmazonCloudWatchAgent'],
installationType: ['Uninstall and reinstall'],
version: ['latest'],
additionalArguments: ['{}'],
},
},
physicalResourceId: cr.PhysicalResourceId.of(`InstallCWAgent-${instance.instanceId}`),
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
CLI
これは、EC2 に CloudWatch Agent をインストールするための SSM ドキュメント(AWS-ConfigureAWSPackage)を利用した Run Command の例です。
CLIに直すと以下のようになります。
aws ssm send-command \
--document-name "AWS-ConfigureAWSPackage" \
--instance-ids "instance-IDs" \
--parameters '{"action":["Install"],"name":["AmazonCloudWatchAgent"], "version":["latest"],"installationType":["Uninstall and reinstall"]}'
解説
onUpdate: {
上記のように記載することで、作成時および更新時にこのドキュメントを実行することを表しています。
onCreate を指定しても動作しますが、CloudFormation の仕様上「差分がない場合は再実行されない」ため、「デプロイのたびに確実に実行したい」ケースでは onUpdate を使うのが実用的かと思います。
service: 'SSM',
action: 'sendCommand',
サービスとアクションを指定します。これはCLIの通りです。
parameters: {
DocumentName: 'AWS-ConfigureAWSPackage',
Targets: [
{
Key: 'InstanceIds',
Values: [instance.instanceId],
},
],
Parameters: {
action: ['Install'],
name: ['AmazonCloudWatchAgent'],
installationType: ['Uninstall and reinstall'],
version: ['latest'],
additionalArguments: ['{}'],
},
},
ここも、CLIを参考に記載していきます。
parameterに関してはマネジメントコンソールからでも参照できます。
physicalResourceId: cr.PhysicalResourceId.of(`InstallCWAgent-${instance.instanceId}`),
CloudFormation がリソースを追跡できるように、physicalResourceId は一意を指定する必要があります。
ここではインスタンス ID を含めてユニークさを担保するようにしています。
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
CustomResourceで作成するLambdaに付与する権限を指定します。
ANY_RESOURCE はデモ用途では問題ないですが、本番環境では対象のリソースARNを絞り込むのが望ましいと思います。適宜調整してください。
おわりに
本来はCDK内で、CustomResourceを用いてRunCommandを実行し、EC2のセットアップをすべてCDKで完結させようと思っていました、、、
しかしながらRunCommandを実行するタイミングでEC2の起動が完了しておらず実行うまく動作しませんでした。
とはいえ、せっかく実装したので、供養のためにとっておきます。
実運用では、SSM Association を用いる方が自然かつ確実にエージェントをインストールできます。
もし「EC2 起動後に自動で処理を適用したい」という要件があれば、Association の利用を検討するのが良いと思います。
これはまた別途記事にしたいと思います。
それでは、内容がご参考になれば幸いです。
