LoginSignup
1
2

More than 1 year has passed since last update.

統合 CloudWatch Agent のカスタムメトリクスとログ監視の設定を Ansible と CloudFormation で構成する

Last updated at Posted at 2021-04-10

概要

やりたいこと

  1. EC2 のメモリ使用率・ディスク使用率などを CloudWatch で監視したい
  2. 各種サービスやアプリケーションが出力するログも CloudWatch に送信したい
  3. ただし管理コンソールや AWS Systems Manager を使わないで、Ansible と CloudFormation だけで構成・更新したい

上記 3. で試行錯誤したので、備忘録を記事にしました。

環境

  • Ansible 2.9 と 2.10 で動作しました。3.x は未使用です
  • Amazon Linux 2 を使用します

予備知識

まず CloudWatch の全体像について、以下の動画で勉強させていただきました。

CloudFormation で EC2 に IAM Role をアタッチする

監視対象の EC2 インスタンスが CloudWatch にメトリクスやログを送信するためには、適切な IAM ロールが必要です。

ec2-iam-role-stack.cfn.yaml
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  MyEc2KeyName:
    Type: "AWS::EC2::KeyPair::KeyName"

Resources:
  # CloudWatchに送信するためのIAMロール定義
  MyIamRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      Path: "/"
      # EC2に適用したい管理ポリシーのARNをここに列挙する
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy

  # 上で定義したIAMロールをEC2インスタンスに適用するために
  # IAMインスタンスプロファイルを定義する
  MyInstanceProfile:
    Type: "AWS::IAM::InstanceProfile"
    Properties:
      Path: "/"
      # 上で定義したIAMロールを関連付ける
      # 注意: 1つのEC2インスタンスに関連付けられるIAMロールは1つだけ
      Roles:
        - !Ref MyIamRole

  # 監視対象のEC2インスタンス
  MyEc2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: ami-00d101850e971728d
      InstanceType: t2.micro
      KeyName: !Ref MyEc2KeyName
      # 上で定義したIAMインスタンスプロファイルをアタッチする
      IamInstanceProfile: !Ref MyInstanceProfile

EC2 インスタンス、IAM インスタンスプロファイル、IAM ロール、管理ポリシーという 4 種類のリソースの関係が分かりにくいのでクラス図を作ってみたら、下図のようになりました。

InstanceProfile の Roles プロパティはリスト型なので、複数の IAM ロールを指定できるように見えますが、「EC2 インスタンスに同時に関連付けられるロールは 1 つだけ」という成約があるため、結果的に関連付けられる IAM ロールは 1 つだけになります。 → 参考: AWS::IAM::InstanceProfile - AWS CloudFormation

IAM ロールと管理ポリシー

適用したい管理ポリシーの ARN を、AWS::IAM::RoleManagedPolicyArns プロパティに列挙します。

上記の arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy は、メトリクスやログを CloudWatch に送信するために必要な管理ポリシーです。

これ以外にもアタッチしたい管理ポリシーがあれば、ここに並べて指定します。
例えば S3 へのアクセスが必要なら arn:aws:iam::aws:policy/AmazonS3FullAccess などを追加します。

参考: 管理ポリシーとインラインポリシー|AWS ユーザーガイド

管理ポリシーの ARN が分からない場合は、AWS 管理コンソールの「サービス」→ 「IAM」→「ポリシー」に名前の一部を入力すれば簡単に見つけることができます。

下図は「s3」でポリシーを絞り込んで「AmazonS3FullAccess」を選択し、表示された ARN をクリップボードにコピーする例です。

search-policy.png

view-policy-arn.png

IAM インスタンスプロファイル

IAM ロールを直接 EC2 インスタンスにアタッチすることができないので、IAM ロールを関連付けた IAM インスタンスプロファイルをアタッチすることで、間接的に IAM ロールを EC2 インスタンスに関連付けます。
ただし関連付けられる IAM ロールは 1 つだけです。

EC2 インスタンス

上で定義した IAM インスタンスプロファイルを、監視対象の AWS::EC2::InstanceIamInstanceProfile プロパティにアタッチします。

Ansible で統合 CloudWatch Agent を構成する

CloudWatch Agent 用の Ansible ロールを作成します。

roles/
├── cloudwatch_agent/
│   ├── handlers/
│   │   └── main.yml
│   ├── tasks/
│   │   └── main.yml
│   └── templates/
│       └── config.json.j2

テンプレート(設定ファイル)

Gunicorn と Nginx のログ、およびディスクとメモリの使用率を収集して CloudWatch に送信するための定義の例です。

templates/config.json.j2
{
  "agent": {
    "metrics_collection_interval": 60
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/gunicorn/access.log*",
            "log_group_name": "gunicorn.access",
            "log_stream_name": "{local_hostname}"
          },
          {
            "file_path": "/var/log/gunicorn/error.log*",
            "log_group_name": "gunicorn.error",
            "log_stream_name": "{local_hostname}"
          },
          {
            "file_path": "/var/log/nginx/access.log*",
            "log_group_name": "nginx.access",
            "log_stream_name": "{local_hostname}"
          },
          {
            "file_path": "/var/log/nginx/error.log*",
            "log_group_name": "nginx.error",
            "log_stream_name": "{local_hostname}"
          }
        ]
      }
    }
  },
  "metrics": {
    "append_dimensions": {
      "AutoScalingGroupName": "${aws:AutoScalingGroupName}",
      "ImageId": "${aws:ImageId}",
      "InstanceId": "${aws:InstanceId}",
      "InstanceType": "${aws:InstanceType}"
    },
    "metrics_collected": {
      "collectd": {
        "metrics_aggregation_interval": 60
      },
      "disk": {
        "measurement": [
          "used_percent"
        ],
        "metrics_collection_interval": {{ cw_interval_default }},
        "resources": [
          "*"
        ]
      },
      "mem": {
        "measurement": [
          "mem_used_percent"
        ],
        "metrics_collection_interval": {{ cw_interval_default }}
      },
      "statsd": {
        "metrics_aggregation_interval": 60,
        "metrics_collection_interval": 10,
        "service_address": ":8125"
      }
    }
  }
}

紛らわしいですが、Ansible (Jinja2) のプレースホルダーは {{ cw_interval_default }} だけで、{local_hostname}${aws: … } は CloudWatch Agent が使用するプレースホルダーと変数です。

agent セクション

CloudWatch Agent の全体的な設定です。
"run_as_user": オプションを追加して実行ユーザーを指定することができます。省略すると root で実行されます。

logs セクション

収集するログファイルの設定です。
"file_path": オプションでログファイルのパスを指定します。*(アスタリスク)と **(スーパーアスタリスク)を使用することができます。

agent セクションで root 以外の実行ユーザーを指定した場合は、読み取り権限のないログファイルを収集することができなくなります。

metrics セクション

カスタムメトリクスの定義と収集の設定です。
内部で使用する collectd と StatsD という 2 つのサービスの設定を含みます。
"namespace": オプションでメトリクスの名前空間名を指定することができます。省略すると CWAgent になります。

設定ファイルを編集するための詳細情報は、以下のページを参照にさせていただきました。

ウィザードを使用すれば、質問に答えるだけの対話方式で設定ファイルを作成することができます。以下を参考にさせていただきました。

タスク

Amazon Linux 2 に CloudWatch Agent をインストールして、上記テンプレートの設定ファイルを配置する例です。

tasks/main.yml
- name: Install or update Amazon packages
  yum:
    name:
      - amazon-cloudwatch-agent
      - amazon-linux-extras
      - amazon-linux-extras-yum-plugin
    state: latest

- name: Install collectd from Amazon Extras Library
  shell: amazon-linux-extras install collectd
  changed_when: false

- name: Enable and start collectd service
  service:
    name: collectd
    enabled: yes
    state: started

- name: Enable and start amazon-cloudwatch-agent service
  service:
    name: amazon-cloudwatch-agent
    enabled: yes
    state: started

- name: Deploy CloudWatch Agent configuration file from templates
  template:
    dest: "/opt/aws/amazon-cloudwatch-agent/bin/config.json"
    src:  "{{ role_path }}/templates/config.json.j2"
  notify:
    - "cloudwatch agent config changed"

2 番めの shell モジュールを使った collectd のインストールは、AWS 公式ドキュメントに合わせて amazon-linux-extras コマンドを使用していますが、yum でインストールしても問題ないと思います。

3 番目と 4 番目の service モジュールで各サービスを起動して自動起動に設定します。

最後に template モジュールで設定ファイルを /opt/aws/amazon-cloudwatch-agent/bin/ に配置し、ファイルに変更があればハンドラを実行します。

設定ファイルを /opt/aws/amazon-cloudwatch-agent/etc/ に配置して Playbook を実行するとファイルが削除されてしまうため、設定ファイルに変更がなくても changed になってハンドラが実行されてしまいました。
これを避けるために、ウィザードの出力先と同じ bin/ に設定ファイルを配置するようにしました。

ハンドラ

設定ファイルをの変更をトリガーとして実行されます。

handlers/main.yml
- name: Fetch configuraton file and restart CloudWatch Agent
  shell: ./amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:config.json -s
  args:
    chdir: "/opt/aws/amazon-cloudwatch-agent/bin/"
  listen: "cloudwatch agent config changed"

amazon-cloudwatch-agent-ctl コマンドを実行して、設定ファイルの定義を CloudWatch Agent に反映します。

  • -a オプションで実行するアクション(fetch-config)を指定
  • -c オプションで設定ファイルのパスを指定
  • -s オプションでサービスを再起動して、設定ファイルの内容を反映します

amazon-cloudwatch-agent-ctl コマンドについては以下を参照してください。

Playbook

以上のロールを既存の Playbook に追記するか、以下のように Playbook を作成して ansible-playbook コマンドで実行します。

my_playbook.yml
- hosts: all
  become: yes
  roles:
    - role: cloudwatch_agent

テンプレートで使用する変数は、どこかで cw_interval_default = 60 のように定義されているものとします。

確認

Playbook が完走すると、EC2 インスタンスがメトリクスとログを CloudWatch に送信し始めるので、AWS 管理コンソールにログインして確認することができます。

カスタムメトリクス

送信されたカスタムメトリクス名が CloudWatch → メトリクス → エクスプローラー → メトリクス に表示され、選択することができます。

custom-metrics.png

ログ

送信されたロググループ名が CloudWatch → ログ → ロググループ に表示され、選択すると各 EC2 インスタンスの一覧が表示され、さらにインスタンスを選択するとログの内容が表示されます。

loggroup.png

トラブルシューティング

意図したとおりに動作しない場合は、SSH でインスタンスにログインして、以下を確認してみてください。

  • まず /opt/aws/amazon-cloudwatch-agent/ に移動する
  • Ansible で配置した bin/config.json が存在するか、内容が意図したとおりかを確認する
  • etc/amazon-cloudwatch-agent.toml(実行時に生成される)の内容が config.json の内容と一致するを確認する
  • logs/ 内のログを読む
  • SSH 端末から手動で bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:bin/config.json -s を実行して、出力されるメッセージを読む
  • bin/amazon-cloudwatch-agent-ctl -a status を実行して、CloudWatch Agent のサービスの動作状態を確認する
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2