はじめに

従来 cron ジョブと自作スクリプトでログのローテーションや転送を行うことは一般的でした。しかし、このアプローチには設定管理の煩雑さやエラー発生時の追跡の難しさなど、見過ごせない課題が潜んでいます。

この記事では、AWS Systems Manager Run Command を活用して、これらの課題を解決し、より柔軟で効率的な EC2 ログ管理を実現する方法を紹介します!

従来のログ管理 (cron) の課題

cron を用いた従来のログ管理には、以下のような共通の課題がありました。これらは特にサーバー台数の増加やシステムの複雑化に伴い、顕著になります。

課題項目 具体的な内容
設定管理の複雑化 各サーバーへの cron 設定やスクリプトの配布・更新作業が煩雑。設定漏れやバージョン不整合のリスクがある。
エラーハンドリング スクリプト実行失敗時の検知や原因特定が困難。エラー通知の仕組みも自前で構築する必要がある。
スケーラビリティ ログ量の急増やサーバー構成変更への追従が難しい。スクリプトや設定の見直しが頻繁に発生。
属人化リスク スクリプトや設定の詳細が特定の担当者に依存しがち。担当者不在時の対応が困難になる。
リアルタイム性の欠如 バッチ処理のため、ログ発生から収集・転送までにタイムラグが発生する。
一元管理の難しさ ログが各サーバーに分散し、横断的な検索や分析が困難。

これらの課題は、運用負荷の増大や障害対応の遅れに直結します。

EC2 ログ管理の選択肢と比較

AWS 環境における EC2 のログ管理には、いくつかの主要な選択肢があります。ここでは代表的な二つのアプローチを比較します。

  1. CloudWatch Agent + Amazon Data Firehose + Amazon S3 (リアルタイム指向)
    • CloudWatch Agent が EC2 インスタンスからリアルタイムに近い形でログを CloudWatch Logs へ収集します。
    • CloudWatch Logs から Amazon Data Firehose を経由して、Amazon S3 へストリーミング転送します。
    • 途中でデータの変換や圧縮も可能です。
    • メリット: リアルタイム性、高度な監視・分析連携、マネージドサービスによる運用負荷軽減。
    • デメリット: コストが比較的高くなる可能性、構成要素がやや多い。
  2. AWS Systems Manager Run Command + Amazon S3 (バッチ処理指向・本記事のテーマ)
    • EC2 インスタンス上で実行するスクリプト (ログのローテーション、圧縮、S3 転送) を Run Command で定期実行します。
    • Systems Manager State Manager や Amazon EventBridge でスケジュール管理します。
    • メリット: 構成が比較的シンプル、既存のスクリプト資産を活かせる可能性、コストを抑えやすい!
    • デメリット: リアルタイム性は低い、スクリプトの管理やエラーハンドリングの作り込みが必要。

それぞれの特徴をまとめた比較表は以下の通りです。

比較ポイント CloudWatch Agent + Firehose Run Command + S3 (今回のアプローチ)
ログ収集のリアルタイム性 高い (ほぼリアルタイム) 低い (バッチ処理、スケジュール依存)
構成の複雑さ やや複雑 (複数のマネージドサービス連携) シンプル
主なコスト要素 CloudWatch Logs (取り込み/保存)、Firehose (処理)、データ転送 Run Command (無料枠超過時)、S3 (保存/リクエスト)、EC2 (処理リソース)
エラーハンドリング マネージドサービスによる堅牢なリトライと通知 スクリプト内での自前実装と Run Command の結果確認
スクリプト管理 CloudWatch Agent 設定ファイル Run Command 内のスクリプト (SSM ドキュメントで管理可能)
スケーラビリティ 高い (マネージドサービスが自動スケール) インスタンス数やログ量に応じてスクリプトや実行間隔の調整が必要
向いているケース リアルタイム監視・分析、運用負荷軽減を最優先 コスト抑制、既存スクリプト活用、シンプルなバッチ処理で十分な場合

Run Command によるログ管理を選定するポイント

Run Command を使ったログ管理が適しているのは、以下のようなケースです。

  • リアルタイム性が必須ではない: ログは日次や数時間ごとのバッチ処理でS3にアーカイブできれば十分。
  • 既存のスクリプト資産を活かしたい: 既に cron で運用しているログ処理スクリプトがあり、それを AWS 環境でも継続利用したい。
  • 構成をシンプルに保ちたい: CloudWatch Agent や Firehose といった追加のコンポーネントを導入せず、既存の Systems Manager の枠組みで完結させたい。
  • コストをできる限り抑えたい!: 特にログの取り込み量が多い場合、CloudWatch Logs や Firehose のコストが課題になる場合に検討価値があります。
  • 特定の処理を柔軟に行いたい: ログファイルに対して、圧縮前に特定のフィルタリング処理を行ったり、特殊な形式でリネームしたりするなど、既存のスクリプトでなければ難しい処理がある。

これらのポイントに合致する場合、Run Command は非常に有効な選択肢となります。ログ管理の新たな選択肢です!

検証手順: Run Command で Apache ログを S3 へ転送

ここでは、EC2 上の Apache アクセスログを、AWS Systems Manager Run Command を使用して定期的に圧縮し、Amazon S3 バケットへ転送する手順を解説します。

検証の前提:

  • 検証対象 EC2 インスタンスを作成していること
  • EC2 にAmazonSSMManagedInstanceCoreの IAM ポリシーがアタッチされていること
  • EC2 にログ転送先 S3 バケットへのs3:PutObjectの IAM ポリシーがアタッチされていること
  • EC2 で apache のログ出力設定がされていること
  • ログ転送先 S3 バケットを作成していること

1: Run Command スクリプトの作成とテスト (手動実行)

次に、ログを処理して S3 へ転送するスクリプトを作成し、Run Command で手動テストします。

1-1. ログ処理スクリプトの準備

EC2 インスタンス上で実行するシェルスクリプトです。このスクリプトは、Apache のアクセスログを日付スタンプ付きでコピー・圧縮し、S3 へアップロード後、元のログファイルを空にします。

“ はご自身のバケット名に置き換えてください。

#!/bin/bash

LOG_FILE_PATH="/var/log/httpd/access_log"
ARCHIVE_DIR="/tmp/apache_log_archives" # 一時作業ディレクトリ
DATE_SUFFIX=$(date +%Y-%m-%d_%H-%M-%S)
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) # インスタンスIDを取得
TARGET_S3_PATH="s3://<YOUR-S3-BUCKET-NAME>/apache-access-logs/${INSTANCE_ID}/" # S3の保存先パス

# エラー発生時に処理を中断
set -e

echo "Log processing started for ${LOG_FILE_PATH}"

# アーカイブディレクトリ作成 (存在しない場合)
mkdir -p ${ARCHIVE_DIR}

# ログファイルが存在し、かつ空でないか確認
if [ ! -s "${LOG_FILE_PATH}" ]; then
    echo "Log file ${LOG_FILE_PATH} not found or is empty. Exiting."
    exit 0 # ログがなければ正常終了とする
fi

COPIED_LOG_FILE="${ARCHIVE_DIR}/access_log-${DATE_SUFFIX}"
COMPRESSED_LOG_FILE="${COPIED_LOG_FILE}.gz"

# ログファイルを一時ディレクトリにコピー
cp ${LOG_FILE_PATH} ${COPIED_LOG_FILE}
echo "Log file copied to ${COPIED_LOG_FILE}"

# コピーしたログファイルを圧縮
gzip ${COPIED_LOG_FILE}
echo "Log file compressed to ${COMPRESSED_LOG_FILE}"

# 圧縮ファイルをS3にアップロード
echo "Uploading ${COMPRESSED_LOG_FILE} to ${TARGET_S3_PATH} ..."
aws s3 cp ${COMPRESSED_LOG_FILE} ${TARGET_S3_PATH}

echo "Upload successful to ${TARGET_S3_PATH}"

# アップロード成功後、ローカルの元ログファイルをクリア
# 注意: この処理はログロストのリスクを伴うため、実際の運用では慎重に検討してください。
sudo truncate -s 0 ${LOG_FILE_PATH}
echo "Original log file ${LOG_FILE_PATH} truncated."

# 一時ディレクトリ内の圧縮ファイルを削除
rm ${COMPRESSED_LOG_FILE}
echo "Cleaned up ${COMPRESSED_LOG_FILE}"

echo "Log processing finished successfully."
exit 0

スクリプトのポイント:

  • set -e: スクリプト内でコマンドがエラーになった場合、即座にスクリプトを終了させます。
  • INSTANCE_ID: ログの保存先 S3 パスにインスタンス ID を含めることで、複数インスタンスからのログを区別しやすくします。
  • truncate -s 0: 元のログファイルを空にします。

1-2. Run Command による手動実行テスト

作成したスクリプトを Systems Manager Run Command を使用して実行してみます。

  • AWS マネジメントコンソールで Systems Manager を開きます。
  • ナビゲーションペインから「Run Command」を選択し、「Run command」ボタンをクリックします。
  • コマンドドキュメント: 検索バーで AWS-RunShellScript を検索し、選択します。
  • コマンドのパラメータ:
    • Commands テキストエリアに、上記で準備したシェルスクリプトの内容全体を貼り付けます。
  • ターゲット:
    • 「インスタンスを手動で選択する」を選択し、準備した EC2 インスタンスにチェックを入れます。
  • 出力オプション (推奨):
    • 「S3 バケットへの書き込み」を有効にし、コマンドの実行結果を保存する S3 バケットとオプションのプレフィックスを指定します。これにより、実行ログを後から確認できます。
  • 「実行」をクリックします。

    コマンドの実行が開始され、しばらくするとステータスが表示されます。

    Run Command が正常に実行されることが確認できました。

次に、S3 バケットを確認します。

ログファイルが S3 へ正しく転送されたことが確認できました!

最後に、EC2 インスタンスに SSH で接続し、元の Apache アクセスログファイルが処理されたか (このスクリプト例では空になっているか) を確認します。

sudo ls -lh /var/log/httpd/access_log

確認結果↓

[root@ip-10-0-1-83 httpd]# sudo ls -lh /var/log/httpd/access_log
-rw-r--r--. 1 root root 0 May 11 03:04 /var/log/httpd/access_log
[root@ip-10-0-1-83 httpd]# cat /var/log/httpd/access_log
[root@ip-10-0-1-83 httpd]# 

EC2 インスタンス上のログファイルが適切に処理されたことが確認できました。

2: State Manager Association を用いた定期実行の設定

手動での実行が成功したので、次はこの処理を Systems Manager State Manager を使用して定期的に実行するように設定します。

  • Systems Manager のナビゲーションペインで「State Manager」を選択します。
  • 「関連付けの作成」をクリックします。
  • 名前: 任意の名前を入力します (例: ApacheLogToS3Archive)
  • ドキュメント: AWS-RunShellScript を選択します。
  • パラメータ:
    • Commands テキストエリアに、先程のシェルスクリプトの内容全体を再度貼り付けます。
  • ターゲット:
    • 「インスタンスを手動で選択する」を選択し、対象の EC2 インスタンスにチェックを入れます。
  • スケジュールの指定:
    • 「CRON スケジュールビルダー」、「Rate スケジュールビルダー」で実行間隔を指定。もしくは、「CRON/Rate 式」で cron 式を記述して指定することもできます。
  • レート制御 (オプション): 多数のインスタンスを対象とする場合に、同時実行数やエラー発生時の閾値を設定できます。
  • 出力オプション (推奨): Run Command 手動実行時と同様に、S3 への実行ログ出力を設定します。
  • 「関連付けを作成」をクリックします。

    関連付けが作成され、最初のスケジュール時刻になると自動的にコマンドが実行されます。

    State Manager Association がスケジュール通りに実行されることが確認できました!

指定したスケジュール間隔で S3 バケットを確認し、新しいログファイルが定期的にアップロードされていることを確認します。

ログがスケジュール通り S3 へ転送され続けることが確認できました!

この構成のメリットと考慮事項

Run Command を活用したこのログ管理方法には、以下のメリットと考慮事項があります。

メリット:

  • 構成のシンプルさ: CloudWatch Agent や Firehose と比較して、導入・管理するコンポーネントが少ないです。
  • コスト効率: 特にログ流量が多い場合、CloudWatch Logs や Firehose のコストを削減できる可能性があります。Run Command の実行自体は無料枠も大きいです。
  • 柔軟性: 実行するスクリプトを自由にカスタマイズできるため、独自のログ処理ロジックを組み込みやすいです。
  • 既存資産の活用: 既に cron で運用しているシェルスクリプトがあれば、それをベースに移行しやすいです。
  • SSM による一元管理: スクリプトの配布や実行管理、実行結果の確認を Systems Manager で一元的に行えます。
  • SSM Automation: SSM Automation と統合し、コマンド実行結果を評価、リトライロジックを作成することが可能です。

考慮事項:

  • リアルタイム性の欠如: あくまでバッチ処理のため、ログ発生から S3 へ転送されるまでにタイムラグが生じます。リアルタイムなログ分析や監視には不向きです。
  • スクリプトの管理と堅牢性: 実行するスクリプトの品質、エラーハンドリング、冪等性などは自前で確保する必要があります。スクリプトの不備はログロストに繋がる可能性があります!
  • インスタンスへの負荷: ログの圧縮や転送処理は、EC2 インスタンスのリソース (CPU、メモリ、ネットワーク) を消費します。実行タイミングや処理内容によっては、アプリケーションのパフォーマンスに影響を与える可能性を考慮する必要があります。
  • エラー発生時の通知: Run Command の実行失敗は Systems Manager で確認できますが、スクリプト内部の詳細なエラーや、それに応じた通知の仕組みは別途検討が必要です (例: スクリプト内から SNS トピックへ通知)。
  • CloudWatch Logs の機能: CloudWatch Logs Insights のようなリアルタイムログ分析機能や、メトリクスフィルター、サブスクリプションフィルターといった便利な機能は直接利用できません。S3 に保存したログは Athena などで分析することになります。

この構成は万能ではありません!システムの要件や制約を十分に考慮して、最適なログ管理方法を選択することが重要です。

まとめ

AWS Systems Manager Run Command と State Manager を活用することで、cron 運用が抱えていた多くの課題を解決し、EC2 インスタンスのログを効率的に S3 へ自動転送する仕組みを構築できます。

今回紹介した方法は、特にリアルタイム性を厳しく求めない環境や、既存のスクリプト資産を活かしたい場合、そしてコストを抑えたい場合に有効な選択肢となります。

ご自身の環境や要件に合わせて、CloudWatch Agent を利用する構成と比較検討し、より良いログ管理体制の構築を目指してください。ぜひ試してみてください!

参考ドキュメント

AWS Systems Manager Run Command
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/run-command.html

AWS Systems Manager State Manager
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-state.html

AWS-RunShellScript ドキュメント
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/documents-command-ssm-plugin-reference.html#aws-runshellscript