Amazon Web Services ブログ
AWS Fault Injection Simulator による Amazon EKS でのカオスエンジニアリング実践例
この記事では、カオスエンジニアリングの実践に使用できるフルマネージドのフォールトインジェクション(障害注入)サービスである AWS Fault Injection Simulator (AWS FIS) の使用方法について説明します。AWS FIS は、Amazon Elastic Kubernetes Service(Amazon EKS)など、さまざまな AWS サービスをサポートしています。Amazon EKS は、Kubernetes の実行を容易にするマネージドサービスです。お客様は独自の Kubernetes コントロールプレーンまたはワーカーノードをインストールして操作することなく、AWS でKubernetes を実行することができます。この記事では、Amazon EKS 上のワークロードの隠れた弱点を見つけるために、制御されたフォールトインジェクションの実験を設定し実行するプロセスを、事前に構築されたテンプレートとカスタムフォールトを使用することでどれほど簡潔にすることができるかを説明したいと考えています。
この投稿は2021年7月9日に公開されたChaos engineering on Amazon EKS using AWS Fault Injection Simulator を翻訳したものです。
カオスエンジニアリングとは?
カオスエンジニアリングは、テスト環境や本番環境でサーバー停止やAPIスロットリングなどの破壊的なイベントを作成しアプリケーションにストレスをかけ、その時のシステムの応答を観察し、改善を実装していくプロセスです。カオスエンジニアリングは、分散システムで見つけにくい隠れた問題やパフォーマンスのボトルネックを明らかにするために必要な現実世界の状態を作り出すのに役立ちます。まず、定常状態の挙動の分析からはじめ、実験のための仮説を構築 (たとえば、x 個のインスタンスを停止すると再試行数が x% 増える、など)し、実験を実行する際はフォールトアクションを注入し、ロールバック条件を監視し、弱点に対処します。
AWS FIS では、カオスエンジニアリングで使用されるフォールトインジェクションの実験を簡単に実行できるため、アプリケーションのパフォーマンス、可観測性、回復力を簡単に改善できます。
ソリューションの概要
上の図は、今回のソリューションのアーキテクチャを示しています。
この投稿では、Amazon EKS クラスターを対象とした 2 つの異なる障害実験を紹介します。ここでは、Amazon EKS クラスターの作成プロセスの詳細については説明しません。この詳細については、Amazon EKS の開始方法 – eksctl と eksctl – The official CLI for Amazon EKS を参照してください。
前提条件
始める前に、次の前提条件を満たしていることを確認します。
- AWS アカウントへのアクセス
- Amazon EKS クラスターと対話するために kubectl が ローカルにインストールされていること
- Cluster Autoscaler と Container Insights を備えた実行中の Amazon EKS クラスター
- AWS FIS を利用するための AWS Identity and Access Management (IAM) のアクセス許可 (IAM ユーザーおよびロールのアクセス権限をセットアップする を参照) と AWS FIS が実験を実行するためのアクセス権限 (AWS FIS サービスの IAM ロールの設定を参照)
クラスターを作成するために、次の設定を使用しました。(訳註:このyaml はアイルランドリージョン – eu-west-1 – を利用する設定になっています。)
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: aws-fis-eks
region: eu-west-1
version: "1.19"
iam:
withOIDC: true
managedNodeGroups:
- name: nodegroup
desiredCapacity: 3
instanceType: t3.small
ssh:
enableSsm: true
tags:
Environment: Dev
クラスターは、次のように作成されています。
- 3 つの Amazon Elastic Compute Cloud (Amazon EC2) のt3.small インスタンスを 3 つの異なるアベイラビリティーゾーンに分散して配置
- OIDC プロバイダを有効化
- 各インスタンスで AWS Systems Manager Agent を有効化 (後で使用します)
- タグ付きインスタンス
3つのレプリカを持つシンプルな Nginx の deploymentを高可用性のためにそれぞれ異なるインスタンスで実行するようにデプロイしています。
この記事では、次の実験を行います。
- ノードグループインスタンスの終了 — 最初の実験では、ターゲットのノードグループで Amazon EC2 API の TerminateInstances アクションを実行する
aws:eks:terminate-nodegroup-instance
AWS FIS アクションを使用します。実験が開始されると、AWS FIS はノードを終了させていきます。私たちは設定した希望する容量に従って、クラスターが終了されたノードを新しいノードで置き換えていくことを確認できるはずです。 - アプリケーションのポッド の削除 — 2 回目の実験では、AWS FIS を使用してクラスターに対してカスタムフォールトを実行する方法を説明します。AWS FIS は将来的にサポートする Amazon EKS の障害の種類を拡大する予定ですが、この例では、カスタムフォールトインジェクションを実行し、kubectl コマンドを実行して Kubernetes deploymentのポッドをランダムに削除する方法を説明します 。Kubernetes deploymentは、アプリケーションで実行するレプリカ数の希望の状態を定義する良い方法で、ノードまたはポッドのいずれかが停止した場合に高可用性を確保できます。
実験1: ノードグループのインスタンスを終了する
まず、Amazon EKS ノードを終了する実験を作成します。
- AWS FIS コンソールで、「実験テンプレートを作成」を選択します。
- 「説明」に、説明を入力します。
- 「IAM ロール」で、前提条件で作成した AWS FIS が実験を実行するための IAM ロールを選択します。
- 「アクションを追加」を選択します。
このアクションでは、aws:eks:terminate-nodegroup-instances
を選択して、クラスター内のワーカーノードを終了するようにします。
- 「名前」 に、
TerminateWorkerNode
と入力します。 - 「説明 – オプション」に、
ワーカーノードを終了。
と入力します。 - 「アクションタイプ」で、「aws:eks:terminate-nodegroup-instances 」を選択します。
- 「ターゲット」 で、「Nodegroups-Target-1」 を選択します。
- instanceTerminationPercentage に
40
(ノードグループごとに終了するインスタンスの割合) を入力します。 - 「保存」 を選択します。
正しいアクションを追加したら、ターゲットを変更できます。この場合は Amazon EKS ノードグループインスタンスです。
- ターゲットセクションの「編集」を選択します。
- 「リソースタイプ」 に、「aws:eks:nodegroup」 を選択します。
- 「ターゲットメソッド」で、「リソース ID」 を選択します。
- 「リソース ID」 で、リソース ID を選択します。
- 「保存」を選択します。
選択モード では、Amazon EKS クラスターノードグループを選択できます。
最後に、停止条件 を追加します。これはオプションですが、適切なガードレールを使用して実験を実行することが確実になるため、強くお勧めします。停止条件は、Amazon CloudWatch アラームが定義したしきい値に達した場合に実験を停止するメカニズムです。実験中に停止条件がトリガーされると、AWS FIS は実験を停止し、実験はstopping
状態になります。
今回は、クラスターに Container Insights が設定されているため、クラスターで実行されているノードの数を監視できます。
- Container Insights を通じて、CloudWatch アラームを作成し、ノード数が 2 未満である場合に実験を停止します。
- アラームを停止条件として追加します。
- 「実験テンプレートを作成」 を選択します。
最初の実験を実行する前に、Amazon EKS クラスターノードを確認しましょう。この例では、3 つのノードが稼働しています。
- AWS FIS コンソールで、作成した実験の詳細ページに移動します。
- 「アクション」メニューの 「開始」を選択します。
実験を実行する前に、AWS FIS から実験を開始するかどうかを確認するよう求められます。これは、リソースに対して実験を実行する準備ができていることを確認するためのセーフガードの一例です。
- フィールドに
開始
と入力します。 - 「実験を開始」を選択します。
実験を開始すると、実験 ID や現在の状態を確認できます。実験で現在実行されているアクションも確認できます。
次に、クラスターワーカーノードのステータスを確認できます。クラスターに新しいノードを追加するプロセスには数分かかりますが、しばらくすると、Amazon EKS が新しいインスタンスを起動して、終了したインスタンスを置き換えることがわかります。
終了したインスタンスの数は、アクション設定の一部として提供したパーセンテージを反映する必要があります。実験が完了しているため、仮説を検証できます。クラスターは最終的に数分以内に希望の容量に等しい数のノードで定常状態に達しました。
実験 2: アプリケーションポッドの削除
それでは、Amazon EKS クラスターで実行されている特定のコンテナ化されたアプリケーション (ポッド) を対象に、カスタムフォールトインジェクションを作成しましょう。
この実験の前提条件として、Amazon EKS クラスターの configmap を更新し、ワーカーノードにアタッチされている IAM ロールを追加する必要があります。このロールを configmap に追加する理由は、実験で Kubernetes クラスターに対してコマンドを実行できる Kubernetes コマンドラインツールである kubectl を使用しているためです。手順については、クラスターのユーザーまたは IAM ロールの管理を参照してください。
- Systems Manager のコンソールで、「ドキュメント」を選択します。
- 「Create document」 ドロップダウンで、「Command or Session」 を選択します。
- 「名前」に、名前 (
Delete-Pods
など) と入力します。 - 「コンテンツ」 セクションで、次のコードを入力します。
description: |
### Document name - Delete Pod
## What does this document do?
Delete Pod in a specific namespace via kubectl
## Input Parameters
* Cluster: (Required)
* Namespace: (Required)
* InstallDependencies: If set to True, Systems Manager installs the required dependencies on the target instances. (default True)
## Output Parameters
None.
schemaVersion: '2.2'
parameters:
Cluster:
type: String
description: '(Required) Specify the cluster name'
Namespace:
type: String
description: '(Required) Specify the target Namespace'
InstallDependencies:
type: String
description: 'If set to True, Systems Manager installs the required dependencies on the target instances (default: True)'
default: 'True'
allowedValues:
- 'True'
- 'False'
mainSteps:
- action: aws:runShellScript
name: InstallDependencies
precondition:
StringEquals:
- platformType
- Linux
description: |
## Parameter: InstallDependencies
If set to True, this step installs the required dependecy via operating system's repository.
inputs:
runCommand:
- |
#!/bin/bash
if [[ "{{ InstallDependencies }}" == True ]] ; then
if [[ "$( which kubectl 2>/dev/null )" ]] ; then echo Dependency is already installed. ; exit ; fi
echo "Installing required dependencies"
sudo mkdir -p $HOME/bin && cd $HOME/bin
sudo curl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.20.4/2021-04-12/bin/linux/amd64/kubectl
sudo chmod +x ./kubectl
export PATH=$PATH:$HOME/bin
fi
- action: aws:runShellScript
name: ExecuteKubectlDeletePod
precondition:
StringEquals:
- platformType
- Linux
description: |
## Parameters: Namespace, Cluster, Namespace
This step will terminate the random first pod based on namespace provided
inputs:
maxAttempts: 1
runCommand:
- |
if [ -z "{{ Cluster }}" ] ; then echo Cluster not specified && exit; fi
if [ -z "{{ Namespace }}" ] ; then echo Namespace not specified && exit; fi
pgrep kubectl && echo Another kubectl command is already running, exiting... && exit
EC2_REGION=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document|grep region | awk -F\" '{print $4}')
aws eks --region $EC2_REGION update-kubeconfig --name {{ Cluster }} --kubeconfig /home/ssm-user/.kube/config
echo Running kubectl command...
TARGET_POD=$(kubectl --kubeconfig /home/ssm-user/.kube/config get pods -n {{ Namespace }} -o jsonpath={.items[0].metadata.name})
echo "TARGET_POD: $TARGET_POD"
kubectl --kubeconfig /home/ssm-user/.kube/config delete pod $TARGET_POD -n {{ Namespace }} --grace-period=0 --force
echo Finished kubectl delete pod command.
この投稿では、以下を実行するAWS Systems Manager ドキュメント を作成しています。
- ターゲットの Amazon EKS クラスターインスタンスに kubectl をインストールします。
- 2 つの必須パラメータを使用します。アプリケーションポッドが実行されている Amazon EKS クラスター名と名前空間です。
- kubectl delete を実行し、指定した名前空間からアプリケーションポッドの 1 つを削除します。
- 「ドキュメントの作成」 を選択します。
- AWS FIS コンソールで新しい実験テンプレートを作成します。
- 「名前」に
DeletePod
と入力します。 - 「アクションタイプ」で、
aws: ssm: send-command
を選択します。
これにより、ターゲットの EC2 インスタンスに対して、Systems Manager の SendCommand
API アクションが実行されます。
このアクションを選択したら、先ほど作成したドキュメントの ARN を指定し、クラスターと名前空間に適切な値を指定する必要があります。この例では、ドキュメントに Delete-Pods
、クラスター名は aws-fis-eks
、名前空間は nginx
という名前を付けました。
- documentArn に
arn:aws:ssm:
<region>:
<accountId>:document/Delete-Pods
と入力します。 - documentParameters に
{"Cluster":"aws-fis-eks", "Namespace":"nginx", "InstallDependencies":"True"}
と入力します。 - 右上の「保存」を選択します。
- ターゲットについては、リソース ID またはリソースタグでリソースを指定することができます。この例では、リソース ID でノードインスタンスのいずれかをターゲットにします。
- テンプレートを正常に作成したら、実験を開始します。
実験が完了したら、アプリケーションポッド を確認します。この例では、AWS FIS はポッドのレプリカの 1 つを停止し、前述したように Kubernetes のデプロイメントを使用しているため、新しいポッドのレプリカが作成されました。
クリーンアップ
今後の料金が発生しないようにするには、以下の手順に従って、この投稿の手順で作成したすべてのリソースを削除します。
- AWS FIS コンソールから、TerminateWorkerNodes & DeletePod の実験テンプレートを削除します。
- AWS EKS コンソールから、この投稿のために作成した テストクラスターの aws-fis-eks を削除します。
- AWS Identity and Access Management (IAM)コンソールから、IAM ロール AWSFISRole を削除します。
- Amazon CloudWatch コンソールから、CloudWatch アラーム CheckEKSNodes を削除します。
- AWS Systems Manager コンソールのドキュメントの「自己所有」タブから Delete-Pod ドキュメントを削除します。
まとめ
この投稿では、AWS FIS を使用して Amazon EKS で障害注入の実験を実行する 2 つの方法を示しました。まず、AWS FIS でサポートされているネイティブアクションを使用して、Amazon EKS クラスターからインスタンスを終了しました。次に、AWS FIS を拡張して、Amazon EKS で実行されているコンテナ化されたアプリケーションにカスタム障害を注入しました。
AWS FIS の詳細については、AWS re: Invent 2020 でのセッション AWS Fault Injection Simulator: Fully managed chaos engineering serviceを参照してください。カオスエンジニアリングについて詳しく知りたい場合は、AWS re: Invent セッションの Testing resiliency using chaos engineeringとThe Chaos Engineering Collection をご覧ください。最後に、次の GitHub リポジトリでその他の実験例と、AWS Cloud Development Kit (AWS CDK)を使用して AWS FIS を操作する方法を確認してください。
この記事の翻訳は、ソリューションアーキテクトの金森 政雄が担当しました。