はじめに
Terraform の local-exec を試してみるべく EC2 に CloudWatch Agent をインストールし、設定を適用 して検証しました。
CloudWatch Agent の導入方法には、以下の一般的なパターンがあります。
- Systems Manager ステートマネージャ による構成管理
- UserData による初期設定
- 管理端末から
aws ssm send-commandを実行
本記事ではlocal-execを使用して 3. を自動化して以下を確認することを目的としています。
- Terraform の apply プロセスで SSM send-command を実行した場合の挙動
- CloudWatch Agent の導入・設定を Terraform にどこまで寄せられるか
- 実際にやってみて分かった課題や、用途の整理
local-execを使って自動化するメリット・デメリット
メリット
-
local-execは手動のコマンド実行ではなく、誰がいつどの設定を適用したかが Terraform の Plan/Apply で履歴化される
デメリット
-
null_resource+local-exec自体がTerraformのベストプラクティスでないのと、プロビジョナに依存していて、純粋な宣言的 IaC からは外れてしまう - 非同期実行なのでTerraform側で完了確認はできない
この記事で作るもの
- Parameter Store に CloudWatch Agent の Config を登録
- SSM 経由で CloudWatch Agent インストール(
AWS-ConfigureAWSPackage) - エージェントのインストール完了を待つ必要があるため、 time_sleep で30秒待機している
- CloudWatch Agent に Config を適用(
AmazonCloudWatch-ManageAgent)
前提条件
- 対象の EC2 に SSM Agent がインストール & 起動済み
- サンプルコードでは、Terraform上でEC2を参照しています
- EC2 インスタンスプロファイルに下記のポリシーを付与
AmazonSSMManagedInstanceCoreCloudWatchAgentServerPolicy
- Terraform 実行環境に AWS CLI が入っていること(
local-execで呼び出しを行うため) - AWS CLI の認証設定が完了していること
Terraformコード
SSM Parameter Store へ Config を格納
resource "aws_ssm_parameter" "cloudwatch_agent_config" {
data_type = "text"
description = "Cloudwatch Agent config"
name = "Cloudwatch-Agent-config"
tier = "Standard"
type = "String"
insecure_value = file("./config/cloudwatch-agent-config.json") # CloudWatch Agent の設定ファイルのパスを指定
}
本記事で使用しているinsecure_valueはString(非暗号化パラメータ)用の引数です
暗号化が必要な機密情報を取り扱う際は、暗号化パラメータ用の引数であるvalueを使用してSecureString(暗号化パラメータ)を格納してください
また、insecure_valueに渡した値は Terraform の state ファイルにプレーンテキストで書き出されます。機密情報でなくても、state ファイルの管理状況によっては意図しない情報露出につながる可能性があるため、state ファイルの取り扱いには注意してください
CloudWatch Agent のインストール
resource "null_resource" "cloudwatch_agent_install" {
provisioner "local-exec" {
command = "aws ssm send-command --instance-ids ${aws_instance.ec2.id} --document-name AWS-ConfigureAWSPackage --parameters action=Install,name=AmazonCloudWatchAgent --region ${var.aws_region}"
}
}
待機時間
resource "time_sleep" "wait_for_install" {
depends_on = [null_resource.cloudwatch_agent_install]
create_duration = "30s"
}
local-execは非同期実行なのでTerraform側で完了確認は出来ない
エージェントのインストール完了を待つ必要があるため、 time_sleep で30秒待機している
設定している30秒の待機時間では、環境によってインストール完了しない場合があります。必要に応じて create_duration の値を調整してください
CloudWatch Agent に Config を適用
resource "null_resource" "cloudwatch_agent_configure" {
provisioner "local-exec" {
command = "aws ssm send-command --instance-ids ${aws_instance.ec2.id} --document-name AmazonCloudWatch-ManageAgent --parameters action=configure,mode=ec2,optionalConfigurationSource=ssm,optionalConfigurationLocation=${aws_ssm_parameter.cloudwatch_agent_config.name},optionalRestart=yes --region ${var.aws_region}"
}
depends_on = [time_sleep.wait_for_install]
triggers = {
instance_id = aws_instance.ec2.id
config_name = aws_ssm_parameter.cloudwatch_agent_config.name
}
}
まとめ・所感
-
local-execを使用することでaws ssm send-commandを Terraform に組み込んで自動化することが可能ということが分かった - 今回試したケースのようなものだと
local-execはあまり適さない- CloudWatch Agent を一括導入する場合 以下の方法がよく利用されるため、
local-execを使う場面はあまりないと感じた- EC2構成管理も可能な Systems Manager ステートマネージャ を使用する
- EC2の起動時の User-Data で設定する
- CloudWatch Agent を一括導入する場合 以下の方法がよく利用されるため、
-
local-exec自体はterraform applyと連動して外部コマンドやAPIを実行したいときには有効なので、方法の一つとして知っておくと良さそう