はじめに
CloudFormationのヘルパースクリプト、とっても便利ですよね。テンプレートにスクリプトを定義しておくだけでEC2を作成するときにソフトウェアをインストールしたりサービスを開始したりできちゃいます。
今回は、そのヘルパースクリプトを使ってCloudwatch agentのインストールと設定ファイルの作成を行う機会があったので忘れないように書いていきたいと思います。
構築する環境
- Ubuntu Server 20.04 LTS (HVM), SSD Volume Type(ami-0f2dd5fc989207c82)
CFnをつくる
ヘルパースクリプトの準備
さっそく、ヘルパースクリプトを使ってcloudwatch agentをインストール!
といきたいところですが、残念ながらUbuntuにはデフォルトでインストールされていません。なので、まずはaws-cfn-bootstrapパッケージをダウンロードしていきます。EC2が起動するときに実行されるUserDateにヘルパースクリプトに下記のスクリプトを追加します。
apt-get update
apt-get install -y python-setuptools
mkdir -p /opt/aws/bin
apt-get install -y wget
wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz
python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz
CloudWatchエージェントのインストール
次に、cloudwatchエージェントをインストールします。これも同様にUserDateに追加します。
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb -O /tmp/amazon-cloudwatch-agent.deb
dpkg -i /tmp/amazon-cloudwatch-agent.deb
/opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource EC2 --region ${AWS::Region} --configsets default
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource EC2 --region ${AWS::Region}
amazon-cloudwatch-agent.jsonの作成
ヘルパースクリプトとcloudwatchエージェントのインストールまでできたので、次は設定ファイルのamazon-cloudwatch-agent.json
を作成していきましょう。設定ファイルの書き方は公式ドキュメント を参考にしました。
ヘルパースクリプトの作成
次はようやくヘルパースクリプトです。
AWS::CloudFormation::Init
タイプを使うことでcfn-init ヘルパースクリプト用のメタデータを EC2に取り込むことができます。
-
cfn-hup
リソースのメタデータの変更を検出して変更された時にユーザーが指定した操作を実行してくれるデーモンさんです。今回はトリガーとしてスタックの更新イベントを検知していて、検知するとhooks.d配下の設定ファイルにあるアクションが実行されます。 -
hooks.conf 設定ファイル
cfn-hupデーモンが定期的に呼び出すユーザーアクションが定義されてます。 -
cfn-hup.conf 設定ファイル
cfn-hupデーモンのターゲットとなるスタックの名前とAWS認証情報が格納されてます。
今回は、スタックを新規で作成するときはdefault
に、スタックの更新でメタデータを更新するときにはUpdateEnvironment
の方に行くようにしています。
EC2:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
configSets:
default:
- "01_setupCfnHup"
- "02_config_amazon-cloudwatch-agent"
- "03_restart_amazon-cloudwatch-agent"
UpdateEnvironment:
- "02_config_amazon-cloudwatch-agent"
- "03_restart_amazon-cloudwatch-agent"
01_setupCfnHup:
files:
/etc/cfn/cfn-hup.conf:
content: !Sub |
[main]
stack=${AWS::StackName}
region=${AWS::Region}
interval=1
mode: '000400'
owner: root
group: root
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
content: !Sub |
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.EC2.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource EC2 --configsets UpdateEnvironment --region ${AWS::Region}
runas=root
mode: '000400'
owner: root
group: root
/lib/systemd/system/cfn-hup.service:
content: !Sub |
[Unit]
Description=cfn-hup daemon
[Service]
Type=simple
ExecStart=/opt/aws/bin/cfn-hup
Restart=always
[Install]
WantedBy=multi-user.target
commands:
01enable_cfn_hup:
command: "systemctl enable cfn-hup.service"
02start_cfn_hup:
command: "systemctl start cfn-hup.service"
02_config_amazon-cloudwatch-agent:
files:
/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json:
content: !Sub |
{
// ここに amazon-cloudwatch-agent.json を書く//
}
mode: '000644'
owner: root
group: root
03_restart_amazon-cloudwatch-agent:
commands:
01_stop_service:
command: "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop"
02_start_service:
command: "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json"
ちょっとつまったところなのですが、「03_restart_amazon-cloudwatch-agent」のコマンド
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
ではjsonファイルをtoml形式の設定ファイルamazon-cloudwatch-agent.toml
に変換して、エージェントを開始させているようです。なのでこのCFnで作成したEC2には、amazon-cloudwatch-agent.json
というファイルは存在しません。
CloudWatchエージェントのためのロールの作成
AWS リソースにアクセスするにはアクセス権限が必要です。EC2に必要な権限を与えたIAMロールを作成していきましょう。
以下のポリシーをアタッチしたロールCloudwatchRole
を作成しました。
- AWSマネージドポリシー
- CloudWatchAgentServerPolicy
- CloudWatchAgentAdminPolicy
- AmazonSSMManagedInstanceCore
- カスタムポリシー
- 今回はS3とlogsにアクセス許可をするポリシーをつけました。状況に合わせてよきように。
CloudwatchRole:
Type: AWS::IAM::Role
Properties:
RoleName: "CloudwatchRole"
Path: /
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
Policies:
- PolicyName: CloudwatchRolePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
// 省略 //
Resource: '*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
- arn:aws:iam::aws:policy/CloudWatchAgentAdminPolicy
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
インスタンスプロファイルの作成
最後に、先ほど作成したロールをEC2に渡すためにインスタンスプロファイルを作成します。
CWAgentInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: "/"
Roles:
- !Ref CloudwatchRole
おわりに
CloudFormationを作成するのにいろいろとはまりましたが、CFnでぱぱっとできるとウィザードでポチポチ設定していくよりも簡単ですね!
まだまだ分からないことだらけのCloudFormation。奥が深い。
(他にもっといい方法があるよ、ここ間違えてるよ、というところがありましたら教えていただけると嬉しいです!)