職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

CloudWatch Agent が起動しないトラブルの対応メモ

先日、お仕事で久しぶりに、AWSのEC2に CloudWatch Agent を入れる作業をしていたところ、ちょっとハマったポイントがあったのでここにメモしておきます。

目指す状態

  • CloudWatch Agent が起動して、メトリクスを CloudWatch に送信している状態
  • CloudWatch Agent が起動して、Webアプリケーションのログを CloudWatch Logs に送信している状態
    • 本当はNginxとかOSの一部機能のログとかも送るけど、本メモの主題とは離れてるので、この観点での情報は割愛

IAM Role の設定

対象の EC2 Instance に設定する IAM Role には、以下の2つの AWS managed policy を付与しました。

  • AmazonSSMManagedEC2InstanceDefaultPolicy : Session Manager で接続するために必要です。 AmazonSSMManagedInstanceCoreでも良いと思います。これら2つの違いは SSM のパラメータストアを使うかどうかです。AmazonSSMManagedInstanceCoreだと ssm:GetParameter権限も付いてます。
  • CloudWatchAgentServerPolicy : CloudWatch にメトリクスを送ったり、CloudWatch Logs にログを送ったりする権限です。

CloudWatch Agent のインストール

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-EC2-Instance.html
インストール手順の、公式のマニュアルは↑の通りです。command line から入れるか、Systems Manager から入れるか、CloudFormation でゴニョゴニョするか、の3択ですが、本メモではcommand line から実施しました。つまり、マニュアルとしては https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/installing-cloudwatch-agent-commandline.html を参照したということになります。

なお、このマニュアルには、1つだけ、とても不親切な点があります。それは、インストール手順の最後にAgentを起動する際、設定ファイルのファイルパスの入力を求めているのですが、マニュアルをそこまで *順番通りに* 読んでいると、設定ファイルを書く工程に到達しないという点です(または私が見落としたか)。
設定ファイルの書き方やデフォルトのファイルパスは https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/create-cloudwatch-agent-configuration-file.html にあります。

設定ファイルの作成

前述のマニュアルにある通り、設定ファイルはデフォルトではJSON形式です。おそらく他のフォーマットも読んでくれるのでしょうけども、設定ファイルを作ってくれるwizardさんがJSONを吐くので、JSONを使うのが一般的なのだろうと思います。私もJSON派です。

wizardさんは、マニュアルにある通り sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard で起動します。ここで多くの質問に答えると、設定ファイルができあがります。
なお、質問事項には StatsDCollectD を使うかどうかの質問がありますが、使う回答をするとインストールとかがちょっと面倒なので、ここでは使いません😅

Do you want to turn on StatsD daemon?
1. yes
2. no
default choice: [1]:
2
Do you want to monitor metrics from CollectD? WARNING: CollectD must be installed or the Agent will fail to start
1. yes
2. no
default choice: [1]:
2

全部の質問に答えると The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json. みたいなメッセージが出力されるので、ここで設定ファイルのファイルパスを知ることになります。

CloudWatch Agent のコマンドいろいろ

EC2上で動くUbuntuの場合、です。オンプレやWindowsなど、環境が変われば当然にコマンドは変わります。
なお、本来は sudo で作業するべきだろうとは思いますが、ここでは雑にroot権限で作業する前提になっています😇

  • 設定ファイルを食わせて起動 : /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
  • プロセスの状況を確認 : /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status

トラブルの内容

設定ファイルを食わせて起動しようとしたところ、Agentさんが上手く起動してくれませんでした。時系列で話を書いても読みにくくて仕方ないので、「こういう間違いをしたら、こういうエラーになった」という情報をいくつか列挙するという書き方でトラブルを紹介したいと思います。

トラブル1:設定ファイルがJSONとして正しくないとき

設定ファイルを食わせて起動しようとすると、コマンドは正常っぽく終了しますし、「Configuration validation succeeded」って言ってますし、終了ステータスは 0 です。よく見ると「unable to parse json」と言われていますが、これは容易に見落とします。
その後に稼働状況を見ても status: stopped のままです。

root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
****** processing amazon-cloudwatch-agent ******
I! Trying to detect region from ec2 D! [EC2] Found active network interface I! imds retry client will retry 1 timesSuccessfully fetched the config and saved in /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp
Start configuration validation...
2023/11/23 11:18:27 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp ...
2023/11/23 11:18:27 unable to scan config dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d with error: unable to parse json, error: invalid character 'a' looking for beginning of value
2023/11/23 11:18:27 No json config files found, use the default one
2023/11/23 11:18:27 I! Valid Json input schema.
2023/11/23 11:18:27 D! ec2tagger processor required because append_dimensions is set
2023/11/23 11:18:27 D! pipeline hostDeltaMetrics has no receivers
2023/11/23 11:18:27 Configuration validation first phase succeeded
I! Detecting run_as_user...
I! Trying to detect region from ec2
D! [EC2] Found active network interface
I! imds retry client will retry 1 times
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
Configuration validation second phase succeeded
Configuration validation succeeded
amazon-cloudwatch-agent has already been stopped


root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# echo $?
0


root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
  "status": "stopped",
  "starttime": "",
  "configstatus": "configured",
  "version": "1.300031.0b313"
}

※見やすさのために、コマンド間に空行を入れています。

なお、ログが /opt/aws/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log に吐かれますが、その内容は以下のようなものでした。

2023/11/23 11:18:28 I! Return exit error: exit code=99
2023/11/23 11:18:28 I! No json config files found, please provide config, exit now

config file が無いみたいなことを言っていることから、私は誤った調査を進めてしまい、時間を浪費しました。

トラブル2:multi_line_start_pattern に与える正規表現が、正規表現として正しくないとき

CloudWatch Logs にログを送信する際、デフォルトでは、テキストファイルとしての1行(つまり改行文字ごとに1行)として処理されます。多くの場合はこれで良いのですが、アプリケーションのログが1つのエントリの途中で改行文字を出すことがある場合(例:スタックトレース)、CloudWatch Logs でログを参照する際の見易さが最悪の状態になります。filterが上手く機能しなくなるのです。なので、そのようなログを処理する際は multi_line_start_pattern の設定が重要です。

アプリケーションのログが、論理的な1行(1つのエントリ)の最初に必ずタイムスタンプを吐くようであれば "multi_line_start_pattern": "{datetime_format}", と書くことができ(別途 datetime_format の設定が必要)、便利です。そうではない場合は正規表現を書くことになりますが、この書き方を間違えると、トラブルになります。

  • エスケープシーケンス \ の使い方を誤った場合
    • 例えば "multi_line_start_pattern": "^\[" と書くと、起動時のメッセージには unable to parse json, error: invalid character '[' in string escape code と出ます。起動はしません。
    • こう書きたい場合は、正しくは "multi_line_start_pattern": "^\\[" のように、エスケープシーケンスを2つ重ねることになります。JSON Parse の段階でescapeとして処理されてしまうから、ですね。
    • この誤りは、前述の「JSONとして正しくないとき」と、本質的には同じということになります。
  • JSON parseは成功するけれども、正規表現として正しくない文字列を入れた場合
    • 例えば "multi_line_start_pattern": "*" と書くと、起動には成功しますが、ログは CloudWatch Logs には送信されません。Agentのログ /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log には 2023-11-23T11:39:36Z W! [inputs.logfile] not started with file state folder %s/opt/aws/amazon-cloudwatch-agent/logs/state といったログが1秒に1行、出力されます。このエラーメッセージから、原因が正規表現の誤りであることに気付くのは、なかなか難しいと思います。
  • 空文字列を与えた場合
    • "multi_line_start_pattern": "" とすると、以下のようなメッセージが出て、そもそもAgentの起動にも明示的に失敗します。ここだけとても親切ですw
root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
****** processing amazon-cloudwatch-agent ******
I! Trying to detect region from ec2 D! [EC2] Found active network interface I! imds retry client will retry 1 timesSuccessfully fetched the config and saved in /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp
Start configuration validation...
2023/11/23 11:47:30 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp ...
2023/11/23 11:47:30 E! Invalid Json input schema.
2023/11/23 11:47:30 E! Invalid Json input schema.
2023/11/23 11:47:30 Under path : /logs/logs_collected/files/collect_list/0/multi_line_start_pattern | Error : String length must be greater than or equal to 1
2023/11/23 11:47:30 Configuration validation first phase failed. Agent version: 1.0. Verify the JSON input is only using features supported by this version.


root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# echo $?
1

さいごに

日本語でこんなことを喋っていても世界は救えないので、issueをreportしました。

github.com
github.com

このメモで言及した内容は、バグ管理という意味では2つに分けるのが妥当だと思ったので、分けて報告しました。

環境情報

  • Ubuntu 22.04 の公式のAMIから起こした EC2 instance
  • t4g.nano
  • CloudWatch Agent version 1.300031.0b313
    • バージョン番号は /opt/aws/amazon-cloudwatch-agent/bin/CWAGENT_VERSION ファイルに書いてあります。
  • 作業は Session Manager の接続で実施