AmazonCloudWatch-ManageAgentドキュメントでCloudWatchエージェントを設定する際の挙動を確認した

2021.09.22

いわさです。

CloudWatchエージェントを設定して追加のメトリクスを収集したり、ログの転送を行うことが出来ますが、どのように設定を行っていますか。

私は以下の記事のようにSSM(Systems Manager)を使ってログインせずに一括で反映するのが気に入っています。
複数台同時に設定出来ますし、自動化も出来ますし、ログインしなくても済みますし、早いですし、前提となるSSMエージェントが最初から入っているAMIも多いですし。

こちらのやり方ですが、SSMのRun CommandにてAmazonCloudWatch-ManageAgentを使ってCloudWatchエージェントへ設定します。
設定の際のActionにconfigureを設定します。
しかし、このActionにはconfigure(append)configure(remove)もあります。
どのように使い分ければ良いでしょうか。

実は、挙動を把握せずに使うと、意図せず設定が上書きされたり上書きしたかったのに出来なかったりしてしまう場合があります。
本日は実際にこちらを動かしながら、どういう時にどのように設定が反映されるのかを確認してみました。

CloudWatchエージェントをインストール

まずは、CloudWatchエージェントをインストールします。
こちらが無いと何も始まりません。
もちろんRun Commandでインストールですよ。

次のパラメータでAWS-ConfigureAWSPackageドキュメントを実行します。

パラメータ
Action Install
Installation Type Uninstall and reinstall
Name AmazonCloudWatchAgent
Version latest
Additional Arguments {} ※デフォルト

これにて、CloudWatchエージェントのインストールは完了です。

CloudWatchエージェントの設定を行う

SSMパラメータストアへ設定情報を登録します。

パラメータの名称はAmazonCloudWatch-で開始させます。
AWSマネージドポリシーのCloudWatchAgentServerPolicyをインスタンスプロファイルにアタッチさせるのが楽だからです。
この管理ポリシーは以下のようにリソースを制限しているため、この命名規則に従っておくと楽です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricData",
                "ec2:DescribeVolumes",
                "ec2:DescribeTags",
                "logs:PutLogEvents",
                "logs:DescribeLogStreams",
                "logs:DescribeLogGroups",
                "logs:CreateLogStream",
                "logs:CreateLogGroup"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter"
            ],
            "Resource": "arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*"
        }
    ]
}

さて、ではRun Commandを実行しましょう。
AmazonCloudWatch-ManageAgentを以下のパラメータで実行します。

パラメータ
Action configure
Mode ec2
Optional Configuration Source ssm
Optional Configuration Location AmazonCloudWatch-Param1

SSMセッションマネージャーでEC2へ接続し設定状況を確認しましょう。
設定ファイルは取り込まれた後に変換されて、Amazon Linux2の場合だと以下へ格納されます。

/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml

sh-4.2$ cd /opt/aws/amazon-cloudwatch-agent/etc/
sh-4.2$ ls
amazon-cloudwatch-agent.d  amazon-cloudwatch-agent.toml  common-config.toml  env-config.json  log-config.json
sh-4.2$ cat amazon-cloudwatch-agent.toml
[agent]
  collection_jitter = "0s"
  debug = false
  flush_interval = "1s"
  flush_jitter = "0s"
  hostname = ""
  interval = "60s"
  logfile = "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log"
  logtarget = "lumberjack"
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  omit_hostname = false
  precision = ""
  quiet = false
  round_interval = false

[inputs]

  [[inputs.logfile]]
    destination = "cloudwatchlogs"
    file_state_folder = "/opt/aws/amazon-cloudwatch-agent/logs/state"

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/messages"
      from_beginning = true
      log_group_name = "/var/log/messages"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false
    [inputs.logfile.tags]
      metricPath = "logs"

[outputs]

  [[outputs.cloudwatchlogs]]
    force_flush_interval = "5s"
    log_stream_name = "i-0ac0bba12493dc764"
    region = "ap-northeast-1"
    tagexclude = ["metricPath"]
    [outputs.cloudwatchlogs.tagpass]
      metricPath = ["logs"]

反映されていますね。

CloudWatchエージェントの設定を「上書き」する

先程はログの設定を行いました。
ここにメトリクスの設定を追加してみたいと思います。

シンプルにこんな感じで。

{
    "metrics": {
        "metrics_collected": {
            "processes": {
                "measurement": [
                    "running",
                    "sleeping",
                    "dead"
                ]
            }
        }
    }
}

先程と同様にパラメータストアに登録し、Run Commandで実行です。
Actionはconfigureです。

セッションマネージャーからまた確認してみましょう。

sh-4.2$ cat amazon-cloudwatch-agent.toml
[agent]
  collection_jitter = "0s"
  debug = false
  flush_interval = "1s"
  flush_jitter = "0s"
  hostname = ""
  interval = "60s"
  logfile = "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log"
  logtarget = "lumberjack"
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  omit_hostname = false
  precision = ""
  quiet = false
  round_interval = false

[inputs]

  [[inputs.processes]]
    fieldpass = ["running", "sleeping", "dead"]
    [inputs.processes.tags]
      metricPath = "metrics"

[outputs]

  [[outputs.cloudwatch]]
    force_flush_interval = "60s"
    namespace = "CWAgent"
    region = "ap-northeast-1"
    tagexclude = ["metricPath"]
    [outputs.cloudwatch.tagpass]
      metricPath = ["metrics"]

先程追加したログの設定が消えましたね。
そう、configureは上書きされてしまいます。

CloudWatchエージェントの設定を「追加」する

追加したいときには、configure(append)を使う必要があります。

複数の設定ファイルを使用するように CloudWatch エージェントを設定できます。たとえば、一連のメトリクスとログを収集する、共通の設定ファイルを使用して、常にインフラストラクチャ内のすべてのサーバーから収集することができます。その後、追加の設定ファイルを使用して、特定のアプリケーションから、または特定の状況でメトリクスを収集することができます。

これを設定するには、まず使用する設定ファイルを作成します。同じサーバー上で一緒に使用される設定ファイルは、異なるファイル名を持つ必要があります。設定ファイルは、サーバー上または Parameter Store に保存できます。

fetch-config オプションを使って CloudWatch エージェントを開始し、1 つ目の設定ファイルを指定します。エージェントの実行の 2 つ目の設定ファイルを追加するには、同じコマンドを使用しますが、append-config オプションを使います。

このように複数の設定ファイルに分割することが可能です。
こうすることでSSMパラメータストア上も、たとえば以下のように分割し、組合わて使うことが可能です。

  • ログ用パラメータ(共通)
  • ログ用パラメータA
  • ログ用パラメータB
  • メトリクス用パラメータ

組み合わせ毎にマージした設定ファイルをパラメータストアに用意する必要はない、という点を覚えておきましょう。

追加してみる

ではParam1を設定した後にParam2をconfigure(append)で追加してみます。

AmazonCloudWatch-Param1

{
    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/secure",
                        "log_group_name": "/var/log/secure",
                        "log_stream_name": "{instance_id}"
                    },
                    {
                        "file_path": "/var/log/messages",
                        "log_group_name": "/var/log/messages",
                        "log_stream_name": "{instance_id}"
                    }
                ]
            }
        }
    }
}

AmazonCloudWatch-Param2

{
    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/hoge",
                        "log_group_name": "/var/log/hoge",
                        "log_stream_name": "{instance_id}"
                    }
                ]
            }
        }
    }
}

セッションマネージャーで確認した結果がこちらになります。(以降、inputsのみ抜粋)

[inputs]

  [[inputs.logfile]]
    destination = "cloudwatchlogs"
    file_state_folder = "/opt/aws/amazon-cloudwatch-agent/logs/state"

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/messages"
      from_beginning = true
      log_group_name = "/var/log/messages"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/hoge"
      from_beginning = true
      log_group_name = "/var/log/hoge"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false
    [inputs.logfile.tags]
      metricPath = "logs"

期待どおり追加されましたね。
このように、configure(append)を使うと複数の設定ファイルをマージすることが出来ます。

もうひとつ追加してみましょう。
file_pathに同じものを指定してみました。

AmazonCloudWatch-Param3

{
    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/secure",
                        "log_group_name": "/var/log/secure2",
                        "log_stream_name": "{instance_id}"
                    }
                ]
            }
        }
    }
}

どのように追加されると思いますか。
ひょっとして3つ目はエラーになるか、マージされて追加ではなく更新として扱われたりするでしょうか。 バッティングしてそうだけど、どうかな。
やってみましょう。

[inputs]

  [[inputs.logfile]]
    destination = "cloudwatchlogs"
    file_state_folder = "/opt/aws/amazon-cloudwatch-agent/logs/state"

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/messages"
      from_beginning = true
      log_group_name = "/var/log/messages"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/hoge"
      from_beginning = true
      log_group_name = "/var/log/hoge"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure2"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false
    [inputs.logfile.tags]
      metricPath = "logs"

シンプルに追加されました。
configure(append)はシンプルに追加です。
重複を確認してマージなどは行ってくれません。

CloudWatchエージェントの設定を「部分更新」する

シンプルに追加、と言いましたが、部分的に更新させる方法もあります。
例えばParam1の内容を以下のように修正してみます。

{
    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/secure",
                        "log_group_name": "/var/log/secure3",
                        "log_stream_name": "{instance_id}"
                    },
                    {
                        "file_path": "/var/log/messages",
                        "log_group_name": "/var/log/messages3",
                        "log_stream_name": "{instance_id}"
                    }
                ]
            }
        }
    }
}

これをconfigure(append)すると、新たに2つ追加はされません。
取り込み時の設定ファイル名を見て、追加ではなく上書きの操作を行います。

今は、Param1(旧) + Param2 + Param3 がマージされた状態の設定になっていますが、appendすると Param1(新) + Param2 + Param3 となります。

[inputs]
  [[inputs.logfile]]
    destination = "cloudwatchlogs"
    file_state_folder = "/opt/aws/amazon-cloudwatch-agent/logs/state"

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure3"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/messages"
      from_beginning = true
      log_group_name = "/var/log/messages3"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/hoge"
      from_beginning = true
      log_group_name = "/var/log/hoge"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure2"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false
    [inputs.logfile.tags]
      metricPath = "logs"

更新の際は、反映済みのパラメータを更新してappendする形が良いですね。
なお、反映済みのパラメータがパラメータストアからのみ削除されている場合は、同名のパラメータを作成することで上書き処理を行うことが出来ます。単純に名称だけを見ています。

注意点

同じファイル名だとしても configure≠appendを選択してしまうと上書きされてしまいます。
ためしにParam1を更新してconfigureしたところ、以下の結果となりました。

[inputs]

  [[inputs.logfile]]
    destination = "cloudwatchlogs"
    file_state_folder = "/opt/aws/amazon-cloudwatch-agent/logs/state"

    [[inputs.logfile.file_config]]
      file_path = "/var/log/secure"
      from_beginning = true
      log_group_name = "/var/log/secure4"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false

    [[inputs.logfile.file_config]]
      file_path = "/var/log/messages"
      from_beginning = true
      log_group_name = "/var/log/messages4"
      log_stream_name = "i-0ac0bba12493dc764"
      pipe = false
    [inputs.logfile.tags]
      metricPath = "logs"

Param2とParam3の設定値が削除されましたね。
複数の設定ファイルを使っている場合は基本的にconfigure(append)を使いましょう。

まとめ

まとめです。

  • 設定値は共通部分を切り出して複数ファイルを組み合わせて環境毎の設定を組み立てることが出来ます。
  • 複数の設定ファイルを使う場合はすでに取り込み済みのパラメータなのかを意識しましょう。
  • Actionはconfigure(append)を使って上書きされないように注意しましょう。
  • 更新が必要な場合は反映済みのパラメータと同名のパラメータを作る(or更新する)ことで差分更新を行いましょう。

地味ですけど、CloudWatchエージェントの設定を変更したい、部分的に追加や削除をしたい、といった場合に差分だけのファイルを追加すれば良いのか、全て上書きすれば良いのか。分割する場合はどのように分割するのが良いのか。
今回の検証結果から判断できそうです。