JTP Technology Port

    技術や情報、そして人々が集まる"港"

Chaos Kitty(ミニ!)を 作って、カオスエンジニアリングを体験してみた

「ボタンを押すと、クラウドに“あえて障害”が起きる」——そんなカオスエンジニアリングを体験できる Chaos Kitty を、Raspberry Pi と AWS でミニ版として作ってみました。カオスエンジニアリングは気になるものの、実際に触る機会は少ないものです。そこで今回は、障害の発生から検知、復旧までを手を動かしながら体験できる構成と、その作成手順を詳しくご紹介します。

 

はじめに

皆さんは「Chaos Kitty」をご存知でしょうか?Chaos Kittyは、ボタンひとつでクラウド環境に“あえて障害”を発生させることができる、カオスエンジニアリングを体験するためのユニークな仕組みです。

今回のブログでは、そんなChaos Kittyを実際に作ってみました。とはいえ本格的な構成ではなく、誰でも再現しやすい「ミニ版」として構築しています。

本記事では、次の内容を、実体験ベースで分かりやすく紹介していきます。

  • Chaos Kittyとは何か
  • どのような構成で動いているのか
  • 実際の作成手順
  • 動かしてみた結果と学び

この記事を読み終わる頃には、「自分でも作ってみたい!」「カオスエンジニアリングを触って体験してみたい!」と思っていただけたら嬉しいです。

それでは、実際にChaos Kittyの世界に入っていきましょう。

 

Chaos Kittyとは?

まず「Chaos Kitty」とは何か? から説明していきます。

Chaos Kitty は 3 つの機能に分かれた体験型 AWS ソリューションで、AWSが提唱しているカオスエンジニアリングの考え方を、誰でも手軽に体験できるようにしたデモツールとなっています。

  • AWS と連動した IoT 電球がセキュリティの状態を反映する機能
  • AWSに対して障害を挿入する機能
  • 発生した障害を自動的に修復する機能

もともとカオスエンジニアリングとは、システムにあえて障害を発生させることで、耐障害性や設計の問題点を明らかにする手法です。代表的なものとしては、Netflixの「Chaos Monkey」が有名ですね。

ただ、実際にこれを試してみようとすると、どうしてもハードルが高く感じてしまいます。そこで登場するのが「Chaos Kitty」です。物理ボタン(たとえばRaspberry Piに接続したボタン)をポチッと押すだけで、AWS上のリソースに対して意図的に障害を発生させることができます。

たとえば以下のような操作が可能です。

  • EC2インスタンスの停止
  • セキュリティグループの変更
  • S3の設定変更 などなど

つまり、「手元のボタンひとつでクラウドにカオスを起こす」ことができる仕組みを持っています。視覚的にも、LEDの点灯などで状態を確認できるため、デモや学習用途として非常に分かりやすいのも特徴です。カオスエンジニアリングを「難しいもの」から「触って理解できるもの」にしてくれる、それがChaos Kittyです。

  

今回作る構成

Raspberry Pi + AWS の全体像

今回作成する「Chaos Kitty」の全体構成を紹介します。

今回は「誰でも再現できること」を重視し、本格的なカオスエンジニアリング環境ではなく、シンプルで分かりやすいミニ構成にしています。最小限の構成ながらも、「障害を発生させる → 影響を確認する → 復旧する」という一連の流れを体験できるように設計しています。

今回の構成で使用する主なリソースは以下の通りです。

  • Raspberry Pi 4 (ボタンやランプでAWSの状況を視覚的に表現)
  • AWS Lambda (pythonでAWSへの障害挿入を実装)
  • AWS Security Hub(AWSに発生した障害を検知)

以下のコンポーネントは障害を受ける側なので、自由に構成してみてください!

  • Amazon S3
  • AWS CloudTrail
  • Amazon EC2
  • Security Group

Raspberry Piをトリガーとして、Lambdaを経由し、AWSリソースに対して操作を行う構成になっています。また、Security Hubを組み合わせることで、「変更がどのように検知されるのか」も確認できるようにしています。

実現したい動作

今回のゴールはとてもシンプルです。

ボタンを押す → 意図的に障害を発生 → 状態を確認 → 復旧する

さらに、Raspberry Piに接続したLEDを使って、

  • 正常状態(緑)
  • 障害発生中(赤)

のように、状態を視覚的に分かるようにすることもポイントです。これにより、Chaos Kittyを体験する際にAWSの環境状態を直感的に理解できるようになります。

今回の発生させる障害

構成図に記載した番号ごとに、以下のような操作を実行します。

①S3のパブリックアクセスをオン
 S3バケットのパブリックアクセス制御を変更し、意図的にセキュリティリスクのある状態を作ります。

②CloudTrailの証跡を無効化
 CloudTrailの証跡ログの記録を停止します。

③Security Groupの開放
 Security Groupのルールを変更し、外部からアクセスされる危険がある状態を作ります。

④EC2の停止

 EC2インスタンスを停止します。

 

用意したもの

今回の「Chaos Kitty」を作成するにあたって用意したものを紹介します。基本的には手に入りやすいものだけで構成しているため、初めての方でも比較的簡単に再現できる内容になっています。

AWSアカウント

本構成では、LambdaやEC2、S3など複数のAWSサービスを利用します。そのため、事前にAWSアカウントを用意しておく必要があります。

Raspberry Pi Imager

Raspberry PiにOSを書き込むための公式ツールです。microSDカードへ簡単にOSイメージを書き込むことができ、初期セットアップをスムーズに進めることができます。

Raspberry pi 4 Model B

今回のトリガーとなるデバイスです。ボタン操作を検知し、AWSへリクエストを送信します。

micro SDXCカード

Raspberry PiのOS(Raspberry Pi OS)をインストールするために使用します。PC側にmicro SDカードスロットが無い場合など、必要に応じてUSB変換アダプタを利用してください。

ブレッドボード

はんだ付けなしで回路を組めるため、初心者でも扱いやすいです。

5mm LED(赤・緑)

状態表示用として使用します。 緑:正常状態赤:障害発生中

抵抗器(220Ω〜330Ω程度)

LEDの電流制御のために必須です。これがないとLEDが壊れる可能性があります。

ジャンパー線

各パーツを接続するために使用します。今回はF-Mを使用。

タクトスイッチ(ボタン)

カオスを発生させるためのトリガーとして使用します。「ポチッと押すだけで障害が起きる」という、Chaos Kittyの象徴的なパーツです。

実際に作ってみよう!

それでは実際に作ってみましょう。まずはRaspberry pi 側の実装について説明します。

 

Raspberry Pi側のセットアップ

Chaos KittyのトリガーとなるRaspberry Pi側の実装について解説します。

大きな流れとしては、以下の3ステップで進めていきます。

  1. Raspberry Pi OSのセットアップ
  2. Raspberry Piの配線
  3. 実際に環境へ接続(SSH)

初めて触る方でも進められるように、順を追って説明していきます。

 

(1) Raspberry Pi OSのセットアップ

まずは、Raspberry Piを使える状態にするために、OSをmicroSDカードへ書き込みます。

基本的な手順は以下の通りです。

① Raspberry Pi Imagerを起動
② OS(Raspberry Pi OS)を選択
③ 書き込み先のSDカードを選択
④ 書き込みを実行

特別な設定は不要ですが、今回はSSHで接続するため、設定からSSHを有効化しておきます。

(2) Raspberry Pi の配線

次に、LEDやボタンを使った回路を組んでいきます。配線のポイントは以下です。

  • LEDには必ず抵抗を入れる
  • GPIOピンの番号を間違えない

実際に組んでみるとシンプルな回路ですが、配線ミスがあると動かないため、配線毎に、ランプが点灯するか や ボタンが動作するか、といったように1つずつ確認しながら進めるのがおすすめです。

実物はこのような形になります。

(3) 実際に環境に入ってみる

セットアップと配線が完了したら、実際にRaspberry Piへ接続してみます。
今回はSSHを利用して、PCからリモート接続します。

ターミナル(WindowsならPowerShellなど)で以下のコマンドを実行します。
ssh ユーザ名@ホスト名.local
例:ssh pi@chaos-kitty.local

初回接続時は確認メッセージが表示されるため、「yes」と入力してください。
パスワードを入力すればログイン完了です。

ログイン出来ましたらAWS CLI、pythonが利用できるようにインストールしましょう!

AWS側の構築

Raspberry Pi側の準備ができたら、次はAWS側のリソースを構築していきます。今回の構成では、Raspberry Piからの操作をトリガーにして、AWSリソースへカオス(障害)を発生させる仕組みを作っていきます。

注意事項(重要)

本記事で紹介する「Chaos Kitty」では、意図的に障害やセキュリティリスクのある状態を作り出します。

そのため、以下の環境では 絶対に実施しないでください。検証は必ず、専用のAWSアカウントや検証用環境で行うことを強くおすすめします。

  • 本番環境
  • 業務で利用している環境
  • 他システムへ影響が出る可能性のある環境

AWS側の構築は、大きく以下のステップで進めていきます。

① 障害対象のリソース準備
② IAMポリシー / ロールの作成
③ Lambdaの作成(障害挿入 と 障害復旧の2つ)
④ Security Hubの有効化

 

①障害対象のリソース準備

まずは、障害を発生させる対象となるAWSリソースを準備していきます。今回の構成では、これらのリソースに対して意図的に設定変更や停止などの操作を行います。

今回用意する主なリソースは以下の通りです。

  • Amazon EC2
  • Amazon S3
  • AWS CloudTrail(証跡の作成)
  • Security Group

これらはすべて、後ほどLambdaから操作される「ターゲット」となるリソースです。

②IAMポリシー/ロールの作成

次に、Lambdaから各AWSリソースを操作するためのIAMポリシーとロールを作成します。Lambdaで利用するロールには以下のような権限(ポリシー)が必要になるので、以下の権限が含まれるようにポリシーの作成を行います。

  • EC2の操作(インスタンスの停止)
  • Security Groupの変更(ルールの追加 / 削除)
  • S3の設定変更(パブリックアクセス制御)
  • CloudTrailの操作(ログの開始 / 停止)

IAMポリシー

以下が今回使用するIAMポリシーの例です。そのままJSONで作成することができます。

IAMポリシー (クリックでコードを表示)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "EC2AndSGControl",
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:DescribeSecurityGroups",
                "ec2:StopInstances",
                "ec2:StartInstances",
                "ec2:DescribeInstances"
            ],
            "Resource": "*"
        },
        {
            "Sid": "S3PublicAccessControl",
            "Effect": "Allow",
            "Action": [
                "s3:PutBucketPublicAccessBlock",
                "s3:GetBucketPublicAccessBlock"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Sid": "CloudTrailControl",
            "Effect": "Allow",
            "Action": [
                "cloudtrail:StopLogging",
                "cloudtrail:StartLogging",
                "cloudtrail:GetTrailStatus"
            ],
            "Resource": "*"
        }
    ]
}

IAMロール
IAMポリシーを作成したら、IAMロールの作成を行います。

  1. IAMコンソールでロールを作成
  2. 信頼されたエンティティに「Lambda」を選択
  3. 先ほど作成したポリシーをアタッチ
  4. 任意のロール名を設定(例:chaos-kitty-lambda-role)

このロールを、後ほど作成するLambda関数に割り当てます。

今回のポリシーはシンプルさを重視して「Resource: *」としていますが、Chaos Kittyの性質上、やや強めの権限が必要になるためChaos Kitty用に限定したロールとして作成することが重要になります。

③Lambdaの作成

次に、Raspberry Piから呼び出されるLambda関数を作成します。今回の構成では、以下の2つのLambda関数を用意します。

① 障害を発生させる関数(Action)
② 障害を復旧させる関数(Recover)

それぞれ役割が分かれているため、1つずつ作成していきます。

1つ目:障害を発生させるLambda関数

今回、この関数では以下のような処理を実装します。

  • S3のパブリックアクセス化
  • CloudTrailのログ停止
  • Security Groupの開放
  • EC2の停止

基本設定

  • 関数名:chaos-kitty-action-lambda※分かりやすい関数名でOK
  • ランタイム:Python3.x ※今回はPythonで動かすのでPythonを選択
  • 実行ロール: ②IAMポリシー/ロールの作成 で作成したIAMロールを選択

Lambda関数を作成したらコードと環境変数を設定しましょう。

環境変数

Lambdaの「設定」→「環境変数」から以下を設定します。

これで、障害を発生させるLambda関数は完成です。

BUCKET_NAME:作成したS3バケット名

INSTANCE_ID:作成したEC2のインスタンスID

SG_ID:作成したSecurityGroupのID

TRAIL_NAME:CloudTrailで作成した証跡名

障害を発生させるLambda関数 Lambdaコード (クリックでコードを表示)

import boto3
import random
import os

ec2 = boto3.client('ec2')
s3 = boto3.client('s3')
cloudtrail = boto3.client('cloudtrail')

def open_sg():
    sg_id = os.environ['SG_ID']

    ec2.authorize_security_group_ingress(
        GroupId=sg_id,
        IpPermissions=[{
            'IpProtocol': 'tcp',
            'FromPort': 22,
            'ToPort': 22,
            'IpRanges': [{'CidrIp': '0.0.0.0/0'}]
        }]
    )
    return "SG opened"

def make_s3_public():
    bucket = os.environ['BUCKET_NAME']

    s3.put_public_access_block(
        Bucket=bucket,
        PublicAccessBlockConfiguration={
            'BlockPublicAcls': False,
            'IgnorePublicAcls': False,
            'BlockPublicPolicy': False,
            'RestrictPublicBuckets': False
        }
    )
    return "S3 public"

def stop_ec2():
    instance_id = os.environ['INSTANCE_ID']

    ec2.stop_instances(InstanceIds=[instance_id])
    return "EC2 stopped"

def stop_cloudtrail():
    trail = os.environ['TRAIL_NAME']

    cloudtrail.stop_logging(Name=trail)
    return "CloudTrail stopped"

def lambda_handler(event, context):
    action = random.choice(["sg", "s3", "ec2", "ct"])

    if action == "sg":
        result = open_sg()
    elif action == "s3":
        result = make_s3_public()
    elif action == "ec2":
        result = stop_ec2()
    else:
        result = stop_cloudtrail()

    return {
        "action": action,
        "result": result
    }

2つ目:障害を復旧させるLambda関数

次に、発生させた障害を元に戻す「復旧用Lambda」を作成します。

基本設定

  • 関数名:chaos-kitty-recover※分かりやすい関数名でOK
  • ランタイム:Python3.x ※今回はPythonで動かすのでPythonを選択
  • 実行ロール: 1つ目のLambda関数と同様

基本的な設定は1つ目のものと同じになります。関数名はリージョン内で一意である必要があるので、違う名前を付けましょう。作成したら、1つ目と同じようにコードと環境変数の設定をしていきます。

環境変数

BUCKET_NAME:作成したS3バケット名

INSTANCE_ID:作成したEC2のインスタンスID

SG_ID:作成したSecurityGroupのID

TRAIL_NAME:CloudTrailで作成した証跡名

障害を復旧させるLambda関数 Lambdaコード (クリックでコードを表示)

import boto3
import os
from botocore.exceptions import ClientError

ec2 = boto3.client('ec2')
s3 = boto3.client('s3')
cloudtrail = boto3.client('cloudtrail')

def close_sg():
    try:
        ec2.revoke_security_group_ingress(
            GroupId=os.environ['SG_ID'],
            IpPermissions=[{
                'IpProtocol': 'tcp',
                'FromPort': 22,
                'ToPort': 22,
                'IpRanges': [{'CidrIp': '0.0.0.0/0'}]
            }]
        )
    except ClientError:
        pass

def make_s3_private():
    s3.put_public_access_block(
        Bucket=os.environ['BUCKET_NAME'],
        PublicAccessBlockConfiguration={
            'BlockPublicAcls': True,
            'IgnorePublicAcls': True,
            'BlockPublicPolicy': True,
            'RestrictPublicBuckets': True
        }
    )

def start_ec2():
    ec2.start_instances(InstanceIds=[os.environ['INSTANCE_ID']])

def start_cloudtrail():
    cloudtrail.start_logging(Name=os.environ['TRAIL_NAME'])

def lambda_handler(event, context):
    close_sg()
    make_s3_private()
    start_ec2()
    start_cloudtrail()

    return {"status": "recovered"}

これらの設定が終わったらLambdaは完成です!この2つをRaspberry Piから呼び出すことで、ボタン押下 → 障害発生 → 復旧 という一連のカオスエンジニアリングの流れを体験できるようになります。

 

④Security Hubの有効化

最後に、今回発生させた障害やセキュリティリスクを検知できるように、AWS Security Hubを有効化します。
Chaos Kittyでは、あえてセキュリティ的に問題のある状態を作り出しますが、それがどのように検知されるのかを確認することも重要なポイントです。

有効化手順
Security Hubの有効化は非常にシンプルで、基本的にはこれだけで利用可能です。

  1. AWSコンソールで「Security Hub」を開く
  2. 「Security Hubを有効化」をクリック
  3. デフォルト設定のまま有効化

Security Hubを有効化すると、以下のような変更が自動的に検知されます。

  • S3バケットがパブリックになっている
  • Security Groupが過剰に開放されている
  • その他のセキュリティベストプラクティス違反

これにより、「どの操作がどのようなリスクとして認識されるのか」を可視化することができます。

 

Raspberry Piのコード実装

Raspberry PiのセットアップとAWS側の準備が完了したら、いよいよ本体のロジックを実装していきます。このコードは、ボタン操作をトリガーにAWSのLambdaを呼び出し、障害を発生・復旧する制御プログラムになっています。実際のコードは以下になります。SSHでRaspberry Piに入り、nano コマンド等でpythonファイルを作成してコードを追加してみましょう。

Raspberry Piのコード (クリックでコードを表示)

import RPi.GPIO as GPIO
import time
import subprocess
import json

# ===== 設定 =====
GREEN_LED = 27
RED_LED = 17
BUTTON = 18

CHAOS_LAMBDA = "作成した障害挿入用のLambda関数名"
RECOVER_LAMBDA = "作成した復旧用のLambda関数名"

BUCKET_NAME = "作成したS3バケット名"
SG_ID = "作成したSecurityGroupのID"
INSTANCE_ID = "作成したEC2のインスタンスID"
TRAIL_NAME = "作成したCloudTrailの証跡名"

LONG_PRESS_SEC = 2

GPIO.setmode(GPIO.BCM)
GPIO.setup(GREEN_LED, GPIO.OUT)
GPIO.setup(RED_LED, GPIO.OUT)
GPIO.setup(BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)

state = "normal"

# ===== LED制御 =====
def set_normal():
    GPIO.output(GREEN_LED, GPIO.HIGH)
    GPIO.output(RED_LED, GPIO.LOW)

def set_error():
    GPIO.output(GREEN_LED, GPIO.LOW)
    GPIO.output(RED_LED, GPIO.HIGH)

# ===== Lambda実行 =====
def invoke_lambda(name):
    try:
        print(f"{name} 実行")
        subprocess.run([
            "aws", "lambda", "invoke",
            "--function-name", name,
            "out.json"
        ], timeout=5)
    except subprocess.TimeoutExpired:
        print("エラー:Lambda実行タイムアウト")

# ===== AWS共通 =====
def run_aws_command(cmd):
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)

        if result.returncode != 0:
            print("AWSエラー:", result.stderr)
            return None

        if result.stdout.strip() == "":
            return None

        return json.loads(result.stdout)

    except:
        return None

# ===== 各状態チェック =====
def is_s3_private():
    data = run_aws_command([
        "aws", "s3api", "get-public-access-block",
        "--bucket", BUCKET_NAME
    ])
    if not data:
        return False
    c = data["PublicAccessBlockConfiguration"]
    return c["BlockPublicAcls"] and c["IgnorePublicAcls"] and c["BlockPublicPolicy"] and c["RestrictPublicBuckets"]

def is_sg_closed():
    data = run_aws_command([
        "aws", "ec2", "describe-security-groups",
        "--group-ids", SG_ID
    ])
    if not data:
        return False

    for perm in data["SecurityGroups"][0]["IpPermissions"]:
        for ip in perm.get("IpRanges", []):
            if ip.get("CidrIp") == "0.0.0.0/0":
                return False
    return True

def is_ec2_running():
    data = run_aws_command([
        "aws", "ec2", "describe-instances",
        "--instance-ids", INSTANCE_ID
    ])
    if not data:
        return False

    state = data["Reservations"][0]["Instances"][0]["State"]["Name"]
    return state == "running"

def is_cloudtrail_enabled():
    data = run_aws_command([
        "aws", "cloudtrail", "get-trail-status",
        "--name", TRAIL_NAME
    ])
    if not data:
        return False
    return data["IsLogging"]

# ===== メイン =====
try:
    print("Chaos Kitty起動")
    set_normal()

    last_state = GPIO.input(BUTTON)
    press_start = None

    while True:
        current_state = GPIO.input(BUTTON)

        # 押した瞬間
        if last_state == GPIO.HIGH and current_state == GPIO.LOW:
            press_start = time.time()

        # 離した瞬間
        if last_state == GPIO.LOW and current_state == GPIO.HIGH and press_start:
            duration = time.time() - press_start
            print(f"押下時間: {duration:.2f}秒")

            # ===== 長押し(Recover)=====
            if duration >= LONG_PRESS_SEC:
                print("Recover実行")
                invoke_lambda(RECOVER_LAMBDA)
                state = "error"

            # ===== 短押し(Chaos)=====
            else:
                if state == "normal":
                    print("ChaosKittyスタート!🐱")
                    set_error()
                    invoke_lambda(CHAOS_LAMBDA)
                    state = "error"

            press_start = None

        last_state = current_state

        # ===== 復旧検知 =====
        if state == "error":
            set_error()

            s3_ok = is_s3_private()
            sg_ok = is_sg_closed()
            ec2_ok = is_ec2_running()
            ct_ok = is_cloudtrail_enabled()

            if not s3_ok:
                print("S3 NG")
            if not sg_ok:
                print("SG NG")
            if not ec2_ok:
                print("EC2 NG")
            if not ct_ok:
                print("CloudTrail NG")

            print(f"[状態] S3={s3_ok} SG={sg_ok} EC2={ec2_ok} CT={ct_ok}")

            if s3_ok and sg_ok and ec2_ok and ct_ok:
                print("復旧完了!🐱")
                set_normal()
                state = "normal"

        time.sleep(0.1)

except KeyboardInterrupt:
    GPIO.cleanup()

Raspberry Piコードの解説

このコードでは、実際何をしているかをポイントに絞って解説します。

①LEDの状態切り替え処理

ここでは、LEDの点灯状態を制御しています。

  • set_normal():緑LED点灯(正常状態)
  • set_error():赤LED点灯(障害状態)

def set_normal():

GPIO.output(GREEN_LED, GPIO.HIGH)

GPIO.output(RED_LED, GPIO.LOW)

def set_error():

GPIO.output(GREEN_LED, GPIO.LOW)

GPIO.output(RED_LED, GPIO.HIGH)

②ボタン押下時間の判定

ボタンを押していた時間を計測し、

  • 短押し → 障害発生
  • 長押し → 復旧処理

というように処理を分岐しています。

if duration >= LONG_PRESS_SEC:

~~~

else:

~~~

③障害挿入処理

この箇所は、障害挿入処理となっており主に以下のことを行っています。

  • set_error()
    → 赤LEDを点灯(障害状態を表示)
  • invoke_lambda(CHAOS_LAMBDA)
    → 障害発生用Lambdaを実行(EC2停止/SG開放/S3公開/CloudTrail停止)
  • state = "error"
    → 内部状態を「障害中」に変更

if state == "normal":

print("ChaosKittyスタート!🐱")

set_error()

invoke_lambda(CHAOS_LAMBDA)

state = "error"

④障害復旧処理

  • invoke_lambda(RECOVER_LAMBDA)
    → 復旧用Lambdaを実行(SG閉じる/S3非公開/EC2起動/CloudTrail有効化)
  • state = "error"
    → 復旧中も「障害状態」として扱いますが、復旧が完了すると⑤の処理で復旧が完了したステータスになります。

if duration >= LONG_PRESS_SEC:

print("Recover実行")

invoke_lambda(RECOVER_LAMBDA)

state = "error"

⑤自動復旧判定

ここでは、以下の処理を行っています。

  • 各リソースの状態をチェックして、すべてOKなら
    → 緑LEDに戻す(正常状態)
    → stateをnormalに戻す

復旧コマンドの実行以外にも、障害が発生したリソースの設定を手動で復旧した際にも緑ランプが点灯するようになっています。

if s3_ok and sg_ok and ec2_ok and ct_ok:

print("復旧完了!🐱")

set_normal()

state = "normal"

実際に動かしてみよう!

ここまで準備してきた内容を、いよいよ実際に動かしてみます。「作る」だけでなく、「動かして体験する」のがChaos Kittyの一番面白いポイントです。

今回の動作は、シンプルに以下の流れで進みます。

  1. Raspberry PiのPythonコードを実行(緑ランプ点灯)
  2. ボタンを押す
  3. 障害が発生(赤ランプ点灯)
  4. 復旧(手動 or ボタン長押し)

それでは、Raspberry Pi上でコードを実行してみましょう。
    python3 pythonファイル名
    例:python3 chaos_kitty.py

コードを実行するとこのようにターミナル上に表示されます。

Raspberry Pi 側では緑ランプが点灯してます!

それでは、いよいよボタンを押してみます。ポチ。

コンソール画面では...

ChaosKittyがスタートしてますね!

一方、Raspberry Piはというと...

赤ランプ光ってます!これは何か起こってそうです。

実際にAWSコンソールから確認してみましょう。

S3側でパブリックアクセスのブロック設定がオフになってますね!問題なく動いているようです。今回はコンソールにどのリソースに障害が発生したかを出しているので分かりやすいですが、実際にどの設定が変わったかを発見するのが醍醐味なので、実際に設定を見て特定してみてください!

その特定作業ですが...途中で有効化したSecurity Hubを確認してみましょう。

何やら検知されてますね。

検知内容を確認すると、「chaoskitty-lambda-role calling PutBucketPublicAccessBlock」と出ており、Lambda用のIAMロールによってS3のパブリックアクセスブロック設定が変更されたことが分かります。

今回はミニ版なので、AWSコンソールからリソースの設定を確認してみてもいいですが、対象リソースが多くなると特定するのが大変になるので、Security Hubのログを確認したり、CloudTrailのログを確認すると特定まで繋がりますね!

最後に、忘れずに障害の復旧を実行しましょう。AWSコンソールから実際に設定を戻すことでも復旧できますが、折角なのでRaspberry Piのボタンを長押ししてみて復旧してみましょう。

長押しすると...

復旧完了の文字が出てますね!

Raspberry Piはというと...

緑ランプが点灯してますね!AWSコンソール上でも設定が戻っているようです。

実際にChaos Kitty (ミニ版)を作成/動作させてみましたが、いかがでしたでしょうか。ボタン1つでリソースが変更されてLEDランプでAWS環境の状態が一目で分かるというのはなかなか面白いですよね!

改善したいポイント

今回のChaos Kitty(ミニ版)はシンプルな構成にしましたが、作成を通して改善したい内容も出てきました。次に作成する際は以下の内容も追加したいと思いました。

  • Amazon Alexaによる自動修復
    実際のChaos Kitty ではAmazon Alexaに喋りかけることで自動修復ができるとのことです。今回では実装していない部分になるので、是非機能として取り入れたいと思ってます。
     
  • 多様なAWSサービスを利用
    Amazon Alexaの件と同じ様な内容にはなりますが、今回の構成では関連するコンポーネントが少ないので、追加で「自動修復」、「可視化」、「セキュリティ」をより楽しみ学べるような構成にしたいと思いました。
     
  • おしゃれなボタンやLEDといった装飾部分
    最後に装飾部分ですね。Raspberry Pi含めかなりコンパクトに仕上がったので、次に作成する際は、大きなLED、ボタン、レゴなどの装飾をあしらったChaos Kitty完全版を作りたいと思います。

 

おわりに

作ってみての感想

配線などの電子工作の経験があまりなかったため、Raspberry Piの実装には少し苦労しました。特にGPIOの扱いや配線ミスで動かないこともあり、トライ&エラーの連続でした...

ただ、実際に完成して動かしてみると、LEDで視覚的に分かるという事もあり、達成感がかなり大きかったです!

最後に

ここまでお読みいただきありがとうございました。この記事を通して、Chaos Kittyの仕組みや楽しさを少しでも体験していただけたでしょうか?

実際に手を動かしてみると、次のような点を、よりリアルに理解できたのではないかと思います。

  • クラウドの設定変更がどのように影響するのか
  • 障害がどのように検知されるのか
  • 復旧の流れがどうなっているのか

カオスエンジニアリングというと難しそうなイメージがありますが、今回のようにシンプルな構成でも、その考え方や面白さをしっかり体験することができます。

もしこれから作ってみようという方がいれば、ぜひ気軽にチャレンジしてみてください!小さな構成からでも十分に学びがあり、そこからどんどん自分なりに拡張していく楽しさも味わえるはずです!「触って学べるカオスエンジニアリング」かなりおすすめです 🐱

本記事の内容は、公開時点での内容のものです。
実際に導入を検討する際は、各製品・サービスの情報は、公式サイトのドキュメント等をご参照ください。

JTP Technology Port 新着記事