シェルスクリプトとcronでAWSCloudWatchにメモリ使用量を送信する方法

シェルスクリプトとcronでAWSCloudWatchにメモリ使用量を送信する方法

本記事はアジアクエスト Advent Calendar 2024の記事です。

目次

    はじめに

    デジタルエンジニアリング部グロースエンジニアリング課の森です。

    本記事では、シェルスクリプトとcronを使用してEC2インスタンスのメモリ使用量をCloudWatchでモニタリングする方法を記載します。

    CloudWatchエージェントで同じようなことができるのですが、この手法ならではのメリットもあるので紹介したいと思います。

    背景

    CloudWatchエージェントを使うのが一般的ですが、以下のような条件があり、CloudWatchエージェントでは実現できませんでした。

    1. モニタリング対象インスタンスのメモリ使用可能量が少ない
    2. メモリ使用率が10%を超えるプロセスのみモニタリングしたい

    そこで今回は軽量で柔軟に対応できるシェルスクリプトとcronをつかった手法を実践しました。

    前提条件

    • モニタリング対象のEC2について
      • 外部ネットワークにアクセスできる
    • モニタリングする内容
      • インスタンス全体のメモリ情報を1分ごとに収集
      • メモリ使用率が5%を超えるプロセスのメモリ使用量を1分ごとに収集

    手順

    ①IAMポリシーを作成

    1. IAMコンソールのポリシー一覧画面にて「ポリシーの作成」をクリック
      202412_shellmonitor_01

    2. 右上の「JSON」をクリック、ポリシーエディタに以下のJSONを記載し、「次へ」をクリック

      {
      "Version": "2012-10-17",
      "Statement":[
      {
      "Effect": "Allow",
      "Action": "cloudwatch:PutMetricData",
      "Resource":"*"
      }
      ]
      }
      202412_shellmonitor_02
    3. 任意のポリシー名と説明を入力し、右下の「ポリシーの作成」をクリック

    ②IAMロールを作成

    1. 左側のナビゲーションペインから「ロール」を選択し、右上の「ロールを作成」をクリック202412_shellmonitor_03

    2. 信頼されたエンティティタイプに「AWSのサービス」を、ユースケースに「EC2」を選択し「次へ」をクリック202412_shellmonitor_04

    3. ①で作成したポリシーにチェックをいれて「次へ」をクリック202412_shellmonitor_05

    4. 任意のロール名と説明を入力し、「ロールを作成」をクリック

    ③IAMロールを監視対象インスタンスにアタッチ

    1. EC2コンソールにて監視対象のインスタンスを選択202412_shellmonitor_06

    2. 右上の「アクション」をクリックし、「セキュリティ」 →「IAMロールを変更」をクリック202412_shellmonitor_07

    3. ②で作成したIAMロールを選択し「IAMロールの更新」をクリック202412_shellmonitor_08

    ④シェルスクリプトの作成・転送

    1. viコマンドやnanoコマンドで以下のシェルスクリプトを作成

      #!/bin/bash

      # しきい値(%メモリ使用率)
      threshold=10.0

      # インスタンス全体のメモリ情報を取得
      mem_info=$(free -b) # バイト単位で取得
      mem_total=$(echo "$mem_info" | awk '/Mem:/ {print $2}')
      mem_used=$(echo "$mem_info" | awk '/Mem:/ {print $3}')
      mem_free=$(echo "$mem_info" | awk '/Mem:/ {print $4}')
      mem_available=$(echo "$mem_info" | awk '/Mem:/ {print $7}')

      # CloudWatchにインスタンス全体のメモリ情報を送信(バイト単位)
      aws cloudwatch put-metric-data --metric-name MemoryTotal --namespace Custom/SystemMemory --value "$mem_total" --unit Bytes
      aws cloudwatch put-metric-data --metric-name MemoryUsed --namespace Custom/SystemMemory --value "$mem_used" --unit Bytes
      aws cloudwatch put-metric-data --metric-name MemoryFree --namespace Custom/SystemMemory --value "$mem_free" --unit Bytes
      aws cloudwatch put-metric-data --metric-name MemoryAvailable --namespace Custom/SystemMemory --value "$mem_available" --unit Bytes

      # 上位プロセスの取得(しきい値を超えるプロセスのみ)
      # $6 は RSS(KB単位)
      top_processes=$(ps aux --sort=-%mem | awk -v threshold="$threshold" '{if ($4 > threshold) print $11, $6 * 1024}')

      # 各プロセスのメトリクスをCloudWatchに送信(プロセスのRSSをバイト単位で利用)
      while read -r process_name mem_usage_bytes; do
      # メトリクス送信
      aws cloudwatch put-metric-data --metric-name ProcessMemoryUsage \
      --namespace Custom/ProcessMonitoring --value "$mem_usage_bytes" \
      --unit Bytes --dimensions ProcessName="$process_name"
      done <<< "$top_processes"
    2. zipコマンド等でシェルスクリプトをzip化

      zip <シェルスクリプトのパス>
    3. EC2にzipファイルを転送

      scp -i <pemキーのパス> <zip化したシェルスクリプトのパス> ec2-user@<インスタンスのパブリックIP>:<リモートパス>
    4. EC2のターミナルにて転送されてたzipファイルを解凍

      unzip <zip化したシェルスクリプトのパス>
    5. スクリプトファイルに実行権限を付与

      chmod +x <zip化したシェルスクリプトのパス>

    ④必要なアプリをインストール

    1. 以下コマンドでawscliをインストール

      curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
      unzip awscliv2.zip
      sudo ./aws/install
    2. 以下コマンドでcronをインストール/起動

      sudo yum install cronie -y
      sudo systemctl enable crond.service
      sudo systemctl start crond.service

    ⑤cronでスクリプトを1分ごとに定期実行

    1. 以下コマンドを実行

      crontab -e
    2. エディタが表示されるので以下を入力(* * * * *は毎分実行を意味しています。cronについての説明はこちら。)

      * * * * * <zip化したシェルスクリプトのパス>

    ⑥CloudWatchを確認

    1. CloudWatchコンソールにて左側のナビゲーションペインから「すべてのメトリクス」をクリックし、 カスタム名前空間の「Custom/SystemMemory」をクリック202412_shellmonitor_09

    2. 「ディメンションなしのメトリクス」をクリックする202412_shellmonitor_10

    3. 表示されたメトリクスにチェックボックスを入れるとグラフにインスタンス全体のメモリ情報が表示される202412_shellmonitor_11

    4. カスタム名前空間の「Custom/ProcessMonitoring」をクリックし、遷移した画面の「ProcessName」をクリックする202412_shellmonitor_12202412_shellmonitor_13

    5. 任意のプロセス名のメトリクスにチェックを入れるとそのプロセスのメモリ使用量がグラフに追加される202412_shellmonitor_14

    実施後に感じたメリット/デメリット

    今回の方法ではCloudWatchエージェントを使用する方法と同じように、インスタンス全体のメモリ使用量とプロセスごとのメモリ使用量をモニタリングできました。
    しかしパフォーマンスへの影響や手順等の細かい違いがあったのでCloudWatchエージェントと比較したメリットデメリットを紹介します。

    メリット

    • メモリ使用量が少ない
      CloudWatchエージェントでインスタンス全体メモリを送信した場合、約100MB使用するのですが、
      シェルスクリプトとcronでインスタンス全体メモリを送信した場合だと約4MBしか使用しませんでした。

    • 送信するプロセスを絞れる
      CloudWatchエージェントのprocstatを使用するとプロセスごとのメモリ情報をCloudWatchに送信できるのですが、 プロセスIDやプロセス名でしか絞れません。
      対してシェルスクリプトとcronだと「メモリ使用率が5%を超えるプロセス」のように絞り込んで送信することができます。

    デメリット

    • 操作や管理が複雑
      CloudWatchエージェントは設定ファイル1つでメモリ情報を送信できるのに対し、
      シェルスクリプト+cronはスクリプトファイルとcrontabを管理しないといけないので、操作・管理が比較的複雑です。

    まとめ

    長文にお付き合いいただきありがとうございました。
    手順が多くCloudWatchエージェントを使うより手間ですが、似たような記事がなかったので記事にしてみました。
    ただ1つ1つの手順は難しくなかったのでスムーズに実施することができました。
    メモリモニタリングの1つの手段としてご参考になれば幸いです。

    アジアクエスト株式会社では一緒に働いていただける方を募集しています。
    興味のある方は以下のURLを御覧ください。