[アドカレ2024]Amazon CloudWatch+Zabbixダッシュボード作成してみた!(part2)

はじめに

前回の「[アドカレ2024]Amazon CloudWatch+Zabbixダッシュボード作成してみた!(part1)」に引き続き、part2を投稿します!CloudWatch RUMを構築する回になります。
以前の記事が作成済みとして進めますが、ここだけを切り取っても使える資料なので、ぜひ活用してください!
なお、細部を記載していますが、環境は既に存在していませんのでご安心ください。

前回の記事
[アドカレ2024]Amazon CloudWatch+Zabbixダッシュボード作成してみた!(part1)

※環境はこちらのとおりですので、ご一読お願いいたします!

構築!

CloudWatch RUM

Webアプリケーションのモニタリングができる Google アナリティクス みたいなもの。
どのホストがどのページにどれだけ滞在していたか、また、各ページのパフォーマンスを確認できる。

公式ドキュメント:

CloudWatch RUM公式ドキュメント

※ここでオープンテレメトリー(OpenTelemetry)について知ろう!

システムやソフトウェアの動きを遠隔地からまとめて監視するプロセス

とのこと。まとめすぎなので、細部は参考サイトへ!
参考サイト:

OpenTelemetryについてご参考

ZabbixのWEBインターフェイスにJSコードを置き、ユーザーモニタリングやパフォーマンスを確認する。
ユーザーセッションから実際のパフォーマンスデータを CloudWatch RUM が収集できるように、アプリケーションのセットアップを行います。では早速実際に構築します。

  • アプリケーションモニターを追加
  • アプリケーションモニター名:任意
  • Zabbixサーバーに割り当てているEIP(ドメイン)
  • サブドメインを含める:有効
  • RUM データ収集を設定する:デフォルト
  • Cookie を許可する:デフォルト
    (無効にすると、セッションに基づくデータが取れない。)
  • セッションサンプル:デフォルト(すべてのセッションが記録される。)
  • CloudWatch Logsにデータを保存するかを指定:任意(30日間はRUMで保持される。)
  • 承諾(cognitoの設定):既存のプロバイダーからのプライベート認証を使用します。
    (今回は一般に公開しているサイトではなく、Zabbixサーバー自身のWEBインターフェイスを監視するため。)
  • (参考)ページの指定可能。
  • (参考)アクティブトレース(X-Ray)が可能。
  • CloudWatch RUM ウェブクライアントをインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

nvm をロード

source ~/.bashrc

nvm を使用して Node.js の最新の LTS バージョンをインストール
(AmazonLinux2環境なので、少し古いバージョンのインストールになります。)

nvm install 14

Node.js が正しくインストールされ、実行されていることをテスト

node -e "console.log('Running Node.js ' + process.version)"

出力例

Running Node.js v14.21.3

npm から CloudWatch RUM ウェブクライアントパッケージをインストール(コンソールに表示されるもの。)

npm install aws-rum-web

ドメインが推奨されていますが、IPアドレスでも指定可能です。
image.png
新しいIDプールを作成することで、IDプールの作成、ポリシーの作成などを一気に済ませることができます。
image.png
サンプルコードの編集と挿入
実際にWEBサイトとして表示したいのは、Welcome to My Websiteここの部分のみなので、head内に取得したサンプルコードを挿入します。
また、RUMのコンソールからダウンロードするサンプルコードは「HTML」を選択します。
現況を確認する場合は、デベロッパーツールで確認、ネットワークとかコンソールタブ。コンソールタブでエラーが表示されない場合エラーは基本起きておりません。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Website</title>

    <!-- CloudWatch RUM script -->
    <script>
        (function(n,i,v,r,s,c,x,z){
            x = window.AwsRumClient = {q:[],n:n,i:i,v:v,r:r,c:c};
            window[n] = function(c,p){x.q.push({c:c,p:p});};
            z = document.createElement('script');
            z.async = true;
            z.src = s;
            document.head.insertBefore(z, document.head.getElementsByTagName('script')[0]);
        })(
            'cwr',
            'yyyyyyyyyy',
            '1.0.0',
            'ap-northeast-1',
            'https://client.rum.us-east-1.amazonaws.com/1.18.0/cwr.js',
            {
                sessionSampleRate: 1,
                identityPoolId: "ap-northeast-1:xxxxxxxxxxxx",
                endpoint: "https://dataplane.rum.ap-northeast-1.amazonaws.com",
                telemetries: ["performance", "errors", "http"],
                allowCookies: true,
                enableXRay: false
            }
        );
    </script>
    <!-- End CloudWatch RUM script -->

</head>
<body>
    <h1>Welcome to My Website</h1>
</body>
</html>

コンソールで取得できるサンプルコードを編集しただけでは次のエラーが発生します。
エラー(デベロッパーツール):Response was blocked by CORB (Cross-Origin Read Blocking)
Apacheの設定ファイルに次の設定を追加します。

vi /etc/httpd/conf/httpd.conf

Directoryのなかに他の設定も含みます。その中に追記します。

<Directory "/var/www/html">
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
    Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
</Directory>

後はCloudWatch ダッシュボードに表示させる。

「AWS/RUM」という項目から表示させます。
アクセス数、ペイロードなどを表示させてみました。

これまでに作成したダッシュボードを含めて役割を確認しておきます。
ディスク容量やミドルウェアも含めて確認する画面。
image.png

エラー、アクセスログを確認するための画面
異常事態発生時に見る用。設定の不足なども見られます。
image.png
I/O,ネットワークなど。
サイズの選定、ネットワークの状態、CDNなどの参考にできる画面。
image.png
すべてスクロールして見ることができます。

HTMLコード(参考)

CloudWatch RUMを試す場合は簡易的なWEBサイトを作成すると思います。
次のindex.htmlをぜひ使用してください(^^)
/var/www/html/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Website</title>

    <!-- Google Fonts for stylish typography -->
    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;700&display=swap" rel="stylesheet">

    <!-- External CSS for styling -->
    <style>
        body {
            font-family: 'Poppins', sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background: linear-gradient(135deg, #f06, #f9a);
            color: #fff;
            text-align: center;
            overflow: hidden;
        }

        h1 {
            font-size: 3rem;
            font-weight: 700;
            text-transform: uppercase;
            margin-bottom: 20px;
            animation: fadeIn 2s ease-in-out;
            color: #000;
        }

        /* Button styling */
        .cta-button {
            padding: 15px 30px;
            background-color: #ffcc00;
            border: none;
            border-radius: 25px;
            font-size: 1.2rem;
            font-weight: 500;
            color: #333;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .cta-button:hover {
            background-color: #ff9900;
            transform: scale(1.1);
        }

        /* Background animation */
        .background {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image: url('http://xxx.xxxx.xxx.xxx/images/background.jpg');
            background-size: cover;
            background-position: center;
            filter: blur(8px);
            z-index: -1;
        }

        /* Fade-in effect */
        @keyframes fadeIn {
            0% {
                opacity: 0;
            }
            100% {
                opacity: 1;
            }
        }

        /* Responsive design for mobile and tablets */
        @media (max-width: 768px) {
            h1 {
                font-size: 2rem;
            }

            .cta-button {
                padding: 10px 20px;
                font-size: 1rem;
            }
        }

        @media (max-width: 480px) {
            h1 {
                font-size: 1.5rem;
            }

            .cta-button {
                padding: 8px 16px;
                font-size: 0.9rem;
            }
        }
    </style>

    <!-- CloudWatch RUM script -->
    <script>
        (function(n,i,v,r,s,c,x,z){
            x = window.AwsRumClient = {q:[],n:n,i:i,v:v,r:r,c:c};
            window[n] = function(c,p){x.q.push({c:c,p:p});};
            z = document.createElement('script');
            z.async = true;
            z.src = s;
            document.head.insertBefore(z, document.head.getElementsByTagName('script')[0]);
        })(
            'cwr',
            'yyyyyyyyyyyyyyyy',
            '1.0.0',
            'ap-northeast-1',
            'https://client.rum.us-east-1.amazonaws.com/1.18.0/cwr.js',
            {
                sessionSampleRate: 1,
                identityPoolId: "ap-northeast-1:xxxxxxxxxxxx",
                endpoint: "https://dataplane.rum.ap-northeast-1.amazonaws.com",
                telemetries: ["performance", "errors", "http"],
                allowCookies: true,
                enableXRay: false
            }
        );
    </script>
    <!-- End CloudWatch RUM script -->

</head>
<body>
    <!-- Background container -->
    <div class="background"></div>

    <!-- Main content -->
    <h1>Welcome to My Website</h1>
    <button class="cta-button">Get Started</button>
</body>
</html>

※次の箇所は編集が必要です。
index.htmlを置いている階層に記載のとおり、imageディレクトリを作成し、中にjpgファイルを置いてあげる必要があります。xxx.xxx.xxx.xxxここはIPアドレスです。
background-image: url('http://xxx.xxx.xxx.xxx/images/background.jpg');

このイメージおすすめです。
スクショして拡張子をjpgに変えてサーバーにアップロードしちゃいましょう!
image.png

負荷試験Pythonコード(参考)

※次のコードは、あくまでささっとテスト的に作ったものなので、十分に注意し、自身の環境に合わせて実行するようにお願いいたします。
コードの内容としては、ランダムに読み書き(I/O)などの負荷をかけてくれます。今使っているインスタンスタイプがt2.microなので、他のインスタンスタイプでも問題なく高負荷にならず使えるコードだと思いますが、自己責任での実行をお願いいたします。3時間ランダムに負荷をかけるコードとなっています。
access_test.py

import time
import random
import requests
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

# アクセス先URL
url = "http://xxx.xxx.xxx.xxx(IPアドレス)"
file_path = "test_file.dat"  # テスト用ファイル

# サーバーへのリクエスト関数
def send_request(session):
    try:
        response = session.get(url)
        if response.status_code == 200:
            return f"Success: {response.status_code}"
        else:
            return f"Failed: {response.status_code}"
    except requests.exceptions.RequestException as e:
        return f"Error: {e}"

# ディスクに書き込みを行う関数
def write_to_disk(size_in_mb):
    with open(file_path, "wb") as f:
        data = os.urandom(size_in_mb * 1024 * 1024)  # 指定されたMBサイズのランダムデータを生成
        f.write(data)
        print(f"Wrote {size_in_mb} MB to disk.")

# ディスクから読み込みを行う関数
def read_from_disk():
    with open(file_path, "rb") as f:
        data = f.read()
        print(f"Read {len(data) / (1024 * 1024):.2f} MB from disk.")

# サーバー負荷テスト関数
def access_website_concurrently(total_requests, concurrent_requests):
    with ThreadPoolExecutor(max_workers=concurrent_requests) as executor:
        with requests.Session() as session:
            futures = [executor.submit(send_request, session) for _ in range(total_requests)]
            for future in as_completed(futures):
                print(future.result())

if __name__ == "__main__":
    max_duration = 9400  # ココで実行時間(秒)を調整!
    start_time = time.time()

    while time.time() - start_time < max_duration:
        # ランダムなリクエスト数と同時実行数を設定
        total_requests = random.randint(10, 50)  # 1回のラウンドで送信するリクエスト数(10~50の間でランダム)
        concurrent_requests = random.randint(1, 15)  # 同時に実行するリクエスト数(1~15の間でランダム)

        # サーバー負荷テストを開始
        print(f"Starting load test round with {total_requests} requests and {concurrent_requests} concurrent requests...")
        access_website_concurrently(total_requests, concurrent_requests)

        # ランダムなサイズのデータを書き込み・読み込み
        size_in_mb = random.randint(10, 100)  # 100MBから300MBの範囲でランダムに書き込みサイズを設定
        write_to_disk(size_in_mb)
        read_from_disk()

        # 次のラウンドまでの待機時間をランダムに設定(5~15秒の間)
        wait_time = random.uniform(5, 15)
        print(f"Waiting for {wait_time:.2f} seconds before the next round...")
        time.sleep(wait_time)

        if time.time() - start_time >= max_duration:  # 経過時間が5分を超えたら終了
            print("Reached the 5-minute limit. Ending the test.")
            break

    # テスト終了後にファイルを削除
    if os.path.exists(file_path):
        os.remove(file_path)
        print("Test file deleted.")

※次の箇所はIPアドレスを入れる必要があります。
url = "http://xxx.xxx.xxx.xxx(IPアドレス)"

Python実行コマンド

python3 /home/ec2-user/access_test.py

さいごに

以上で[アドカレ2024]Amazon CloudWatch+Zabbixダッシュボード作成してみた!は完了になります。最後まで読んでいただきありがとうございます。
感想としてはZabbixから値を取得する部分に時間を要したので、ここがなんとかならないかポイントでした。とても勉強になりました。
では!

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA