Amazon Web Services ブログ

AWS Step Functions と AWS Systems Manager を使用して、Amazon EBS ボリュームのサイズ変更を自動化する

アクティブなアプリケーションで、Amazon EC2 インスタンスの Amazon EBS ボリューム使用率がプロビジョニング済み容量に達してしまうことがあります。どのアプリケーションを使用しているかによって異なりますが、プロビジョニング済み容量が使い果たされると、アプリケーション停止のリスクが生じ、お客様に影響を与えることがあります。これに対するソリューションの 1 つに、アプリケーションへのフェールオーバーメカニズムの設計がありますが、オーケストレーションの負担になる可能性があります。より簡単なソリューションは、EBS ボリュームのサイズを自動的に変更することです。

Infor では、本番環境での数千に及ぶ EC2 インスタンス (Windows と Linux) を管理しています。当社はこうした停止を防ぐ予防的アプローチが必要であったため、特定のしきい値に達したときボリュームが自動的に増加するように、本投稿で説明するソリューションを開発しました。このアプローチには 2 つの利点があります。

  • 異常が発生し、ボリュームのスペースが非常に少なくなると、プロビジョニング済み容量が枯渇する前に自動的にボリュームを拡張します。このアクションにより、根本原因を調査し解決するまで、問題に対処できます。
  • そのため、ボリュームを過剰にプロビジョニングする必要がなくなりました。このソリューションは、より多くのスペースが必要になると、徐々に自動的にボリューム容量を増やし、EBS コストを削減します。

この投稿では、Infor で開発した自動 EBS ボリュームサイズ変更プロセスを順を追って説明します。さらに、そのアーキテクチャを確認し、ベストプラクティスをいくつか学びます。

概要

AWS は Amazon EBS Elastic Volumes を 2017 年に発表しました。この機能では、ダウンタイムなしでシンプルな API 呼び出しで、ボリュームのサイズを増やしたり、パフォーマンスを調整したり、ボリュームタイプをその場で変更したりできます。

ボリュームの変更は比較的簡単ですが、ファイルシステムを拡張して、追加のストレージを活用しようとすると一筋縄ではいきません。これは通常、OS 上で手動で行いますが、AWS Systems Manager がインスタンスを管理している場合には、AWS Lambda を使用して OS レベルのスクリプトを実行する Systems Manager コマンドを送信できます。

次のリストは、このワークフローの手順を示しています。

  1. ボリュームが 80% に達することをモニタリングし、自動化をトリガーします。
  2. 特定のシステムが除外されたため、続行する前に一連のチェックを実行します。フリートの EC2 インスタンスの一部には、手動でディスクを拡張する必要のあるカスタムビルドアプリケーションがありました。他の EC2 インスタンスは、インフラストラクチャの変更をより厳密に制御する必要がある特定のガバナンスポリシーを持つチームが管理していました。
  3. データの破損が発生する異常なイベントの安全対策として、ボリュームのスナップショットを作成します。
  4. Lambda を使用して、AWS レイヤーでボリュームを 20% 拡張します。
  5. Systems Manager ドキュメントを使用して、Amazon S3 に保存されているスクリプトをダウンロードして実行し 、OS 上のファイルシステムを拡張します。
  6. ステータスを確認し、ボリュームが正しく展開および拡張されたことを確認します。
  7. Amazon SES を使って自動化が正常に行われたことをまとめた E メール通知が送信されます。

次の図は、これらのワークフロー手順を図式的に示しています。

ストレージボリュームの変更とファイルシステムの拡張のワークフローの図

ウォークスルー

このセクションでは、ソリューションのアーキテクチャと手順を説明しています。

アーキテクチャ

このソリューションの全体的なアーキテクチャには、トリガーと実行という 2 つの主要な段階があります。

トリガー

  • Amazon CloudWatch エージェントまたは同様のサードパーティのモニタリングアプリケーションを使用して、インスタンス上のボリュームをモニタリングします。
  • 以前に定義した基準に従って、インスタンスを除外するかどうかを確認します。
  • ボリュームが特定のしきい値に達したときに Amazon API Gateway を呼び出すアラートを設定します。
  • API Gateway を、invoker Lambda 関数として機能する Lambda 関数に統合します。

実行

  • invoker Lambda 関数は AWS Step Functions ステートマシンを実行します。これは、自動化に必要なさまざまなタスクを統制する「オーケストレーター」です。
  • 特定のタスクは、Systems Manager を使用して PowerShell および bash スクリプトを S3 からダウンロードし、インスタンスで実行します。
  • SES は、自動化が成功 (または失敗) したときに通知を送信します。

次の図で、このアーキテクチャを表示しています。

このソリューションでは、トリガーフェーズと実行フェーズの 2つの主要なフェーズがあります。

トリガーの手順

ソリューションには次のトリガー手順が含まれます。

  • ボリュームが特定のしきい値に達したときにアラートを設定する。
  • アラートを受信し、呼び出し機能をトリガーするように API Gateway を設定する。
  • invoker Lambda 関数を作成する。

ボリュームが特定のしきい値に達したときにアラートを設定する

インスタンスのボリュームを積極的に拡張するには、ボリュームのモニタリングが必要であることは言うまでもありません。EBS レイヤーではファイルシステムをモニタリングできません。情報はオペレーティングシステム自体からしか取得できないためです。たとえば、この情報には Windows インスタンスの C ドライブの使用量と空き容量を含む場合があります。

標準の CloudWatch メトリクスは、OS が使用するプロビジョニング済み容量に関する情報を提供しません。しかし AWS は代わりに、カスタムメトリクスを収集できる CloudWatch エージェントを提供しています。

あるいは、サードパーティのモニタリングアプリケーションであれば、ボリュームでプロビジョニングした使用容量をモニタリングし、自動化をトリガーできる必要があります。この例では、LogicMonitor をフリートのすべてのインスタンスにデプロイしました。ボリューム使用率がプロビジョニング済み容量の 80% に達すると、LogicMonitor アラートが発行されるように設定しています。

アラートを受信し、invoker 関数をトリガーするように API Gateway を設定する

LogicMonitor で前述したアラートを設定し、Lambda 関数 (invoker 関数) に統合した API を呼び出します。invoker 関数のジョブは、要求データを受信し、ステートマシンの実行をトリガーすることです。ステートマシンの ARN は、この Lambda 関数に環境変数として渡されます。この Lambda 関数には、自動化のさまざまなタスク状態が含まれています。

API Gateway の定義

  1. Amazon API Gateway コンソールで、[Create API] を選択します。
  2. [REST] をクリックし、名前と説明のフィールドに入力します。
  3. [Resources] で新しいリソースを作成し、リソース名を指定します。
  4. 新しい API リソースをクリックし、[POST] を追加します
  5. [Integration type] では [Lambda Function] を選択し、[Use Lambda Proxy integration] の横のチェックボックスをオンにします。
  6. リージョンと Lambda 関数の名前を指定して、[Save] をクリックします。
  7. POST メソッドを追加すると、メソッド実行の概要が表示されます。
  8. デプロイします。「invoker URL」をメモします。モニタリングアプリケーションがこの URL を使用して自動化をトリガーするためです。

invoker Lambda 関数を作成する

boto3 AWS SDK for Python を使用すると、ステートマシンの実行をトリガーする短い Lambda 関数を簡単に作成できます。

import boto3 

sf = boto3.client('stepfunctions')    
  
sf.start_execution(    
    stateMachineArn='ARN_of_state_machine',   
    name='unique_execution_id',   
    input='{\"my_data\":\"As a JSON string\"}'  
)   

入力には、自動化の処理に必要なデータが含まれている必要があります。この場合、インスタンス ID、ドライブ文字 (Windows インスタンス用) またはマウントポイント (Linux インスタンス用)、リージョン、およびアカウント ID がわかっている必要がありました。ボリューム ID が必要です。ただし、ボリューム ID はモニタリングシステムからすぐに利用できない場合があるため、自動化の一部で取得する必要があります。これについては、この投稿の後半で詳しく説明します。

実行手順

ソリューションには次の実行手順が含まれます。

  1. Lambda 関数のセットアップ
  2. AWS Step Functions を使用して Lambda 関数を調整します。

Lambda 関数の作成

インスタンスのボリュームを変更するには、いくつかの手順を正しい順序で実行する必要があります。Lambda はこのような複雑な自動化を小さな部分に分割できるため、ここでは Lambda を選択するのが普通です。

以下は、自動化に含まれるタスクのリストです。

  1. インスタンスが適格かどうかを確認する。
  2. ボリュームをマッピングする。
  3. ボリューム ID を取得する。
  4. (オプション) ボリュームのスナップショットを作成する。
  5. ボリュームをデプロイします(AWS レイヤー上)。
  6. ファイルシステムのサイズを拡張する。
  7. ステータスを確認する。
  8. 確認メールを送信する。
インスタンスが適格かどうかを確認する。

インスタンスが Infor 固有の特定の条件を満たしているかどうかを確認するジョブを行うタスク。これらの条件を満たしている場合、Lambda 関数は元の入力を返し、適格性を含むキーと値のペアを追加します。たとえば、この戻り値の最後のキーと値のペアに注目してください。

{  
  "instance_id": "i-0bc3fb5a56fdc4e8e", 
  "region": "us-east-1", 
  "platform": "windows", 
  "drive_letter": "D", 
  "eligible": true
}  
ボリュームをマッピングする

モニタリングソフトウェアは、たいていのモニタリングアプリケーションと同様、インスタンスの OS レイヤーで実行するコレクタープロセスです。そのため、アラートは影響を受ける Windows (または Linux) ボリュームに関する情報を提供しますが、EBS ボリューム ID は提供しません。その結果、自動化によって EBS ボリューム ID を拡張できるように、EBS ボリューム ID を取得する方法が必要でした。

しかし、AWS Systems Manager がインスタンスを管理している場合、SSM コマンドを使って PowerShell (あるいは Linux の場合、bash) スクリプトを S3 からダウンロードし、スクリプトを実行できます。この場合、スクリプトはボリュームと対応する EBS ボリューム ID を一覧表示します。AWS はサンプルの PowerShell スクリプトも提供しています。

このタスクは、SSM ドキュメントを実行し、実行 ID を出力に返す Lambda関数 です。SSM ドキュメントは、Systems Manager boto3 クライアントを使用して Lambda から実行できます。

import boto3    
  
ssm = boto3.client('ssm')  
  
response = ssm.send_command(    
      InstanceIds=['the_id_of_the_instance'],   
      DocumentName='the_name_of_the_ssm_document',   
      Comment='Retrieve volumes mapped to this instance',    
      Parameters={    
          'driveletter': [    
              'D',   
          ]    
      },   
  )    
  
# return the command ID  
return response['Command']['CommandId']    
ボリューム ID を取得する

前の手順にある Systems Manager を使用してボリュームをマッピングし、コマンド ID を返した後、コマンド ID で SSM ドキュメント実行の出力を取得できます。次に出力を解析し、ターゲット EBS ボリューム ID を返します。

コマンド ID を使用すると、boto3 SSM クライアントと list_command_invocations() メソッドで、SSM コマンドの出力を簡単に取得できます。

(オプション) ボリュームのスナップショットを作成する

このステップはオプションですが、予防措置としてボリュームを変更する前に、常にスナップショットを作成することをお勧めします。boto3 EC2 クライアントと create_snapshot メソッドを使って、Lambda で行うこともできます。

ボリュームを展開する (AWS レイヤー上)

これはボリュームを実際に変更するための、最初のステップです。この Lambda 関数は、boto3 を使用して EBS ボリュームを 20% 拡張します (次の例は、ボリュームを 100Gib に拡張する方法を示しています)。

import boto3    
   
ec2 = boto3.client('ec2')    
    
ec2.modify_volume(    
        VolumeId='ebs_volume_id',   
        Size=100    
)  
ファイルシステムを拡張する

OS レイヤーでファイルシステムを「拡張」する機能は、この自動化の中で最も重要な (かつ、やりがいのある) 部分です。AWS レイヤーで EBS ボリュームを拡張するのは比較的簡単です。しかし、OS 上のファイルシステムを拡張して新しくプロビジョニングされたスペースを活用しない限り、この追加スペースは役に立ちません。このプロセスでは、さまざまなオペレーティングシステムやボリュームタイプなど、遭遇する可能性のあるさまざまなシナリオを十分に理解する必要があります。次に、適切なスクリプトを記述して、OS レイヤーのボリュームを拡張します。

Windows では DiskPart を使用する PowerShell スクリプトを作成し、Linux では growpart を使用する bash スクリプトを作成しました。EBS ボリュームのサイズを変更した後にファイルシステムを拡張する方法の詳細については、以下をご参照ください。

以前の手順で使用したものと同じアプローチで、スクリプトをインスタンスにデプロイしました。

  1. スクリプトを作成し、S3 に保存する。
  2. S3 からスクリプトをダウンロードして実行する SSM ドキュメントを作成する。
  3. Lambda では、SSM クライアントと send_command メソッドを使用して、インスタンスで SSM ドキュメントを実行する。
ステータスをチェックする

インスタンス上のボリュームのステータスをチェックし、ファイルシステムが正しく拡張されたことを確認する手順は重要です。これはインスタンスの OS レイヤーで行われるため、前の手順と同様に、Systems Manager を使用してスクリプトをダウンロードおよび実行できます。ファイルシステムが正しく拡張されたかどうかに応じて、「成功」または「失敗」のステータスが返されます。

確認メールを送信する

最後のタスクは、自動化を実行したことをチームに警告するメール通知の送信です (実行したアクションの概要も送信します)。

当社の場合、インフラストラクチャの規模に合わせて、複数のチームがいます。各インスタンスには「所有者」タグがあり、そのチームの配布リストのメールアドレスの値が付いています。所有者タグを抽出し、boto3 の SES クライアントを使用する Lambda 関数を作成して、自動化を実行するたびにメッセージを送信するようにします。メッセージには、影響を受けたインフラストラクチャに関する情報 (インスタンス ID、ボリューム ID、ドライブ文字、元のサイズ、最終サイズなど) を含みます。

「失敗」メールを送信する別の Lambda 関数も作成しました。時折、自動化で EBS ボリュームの変更に失敗しました。これらの障害の一部は設計によるものです (たとえば、特定のシステムが自動化から除外されたなど)。他の要因によるものもありました (たとえば、変更したドライブが 6 時間以内に再びいっぱいとなるなど)。障害が発生した場合は、システム管理者に必ず警告してください。

AWS Stepで Lambda 関数を調整する

前述のように、前にリストした手順を特定の順序で実行する必要があります。Lambda はステートレスであるため、さまざまな Lambda 関数間でステートを渡す方法が必要です。普通、AWS Step Functions がソリューションとなるでしょう。これは、いくつかの Lambda 関数を調整するステートマシンを構築するものです。このソリューションでは、invoker Lambda 関数をトリガーすると、前述の手順の実行を開始するという複雑なステートマシンを使用しました。

タスクの順序とワークフローは、特定の環境またはニーズによって大きく異なります。Step Functions では、選択状態と待機状態だけでなく、複雑な分岐やエラー処理を実装できます。次の図は、ステートマシンの正常な実行のワークフローを視覚的に示しています。

いくつかの Lambda 関数を調整するため、AWS Step Functions で構築したステートマシンの正常な実行をビジュアルで示したワークフロー。

考慮事項

前述のように、このソリューションの目標はアプリケーションの停止を回避することですが、プロビジョニング済み容量のディスク使用率が高い原因を解決するものではありません。また、ボリュームが自動的に拡張し続けるため、根本原因を無視すると追加のストレージコストが発生する可能性があることに注意してください。

この自動化を数か月実行した後、次のような重要な事項に気が付きました。

  • システム管理者が通知を正しく送受信できることを確認してください。
  • 特にプロビジョニング済み容量が極度に大量に使用される場合には、調査を行う準備をしましょう。
  • EBS ボリュームの拡張は可能ですが、EBS ボリュームのサイズを縮小するには追加の手順が必要です。ボリュームのスナップショットを取得したり、データを新しいボリュームに移行するなどの手順を追加すると、かなり複雑になります。
  • EBS ボリュームは、6 時間以内に複数回変更することはできません。その時間枠内に何かによって自動化が複数回トリガーされると、その後の試行で失敗します。

まとめ

この投稿では、EBS ボリュームを積極的に拡張する方法と、このプロセスを自動化することで得られる利点を学びました。また、既存の AWS ツールとサービスを使用した Infor のエンドツーエンドのアプローチもご紹介しました。後に料金が発生しないように、これまでに作成したサンプルリソースが不要になった場合は、忘れず削除してください。

後に料金が発生しないように、これまでに作成したサンプルリソースが不要になった場合は、忘れず削除してください。

異なる EC2 環境によっては、障害が発生する場合があります。私たちが遭遇した失敗のほとんどは、ファイルシステム拡張ステップで発生し、古いオペレーティングシステムまたは標準ではない設定のときに、スクリプトを実行できませんでした。しかし、こうした障害はほぼありませんでした。

この自動化のおかげで、Infor はストレージをより無駄なくプロビジョニングすることができました。この自動化で、過剰にプロビジョニングを行うことなく、必要に応じ EBS 容量を自動的に追加できるようになりました。

最近、レビューを実施したところ、約 15,000 の EC2 インスタンスのフリートで、1 か月間で約 450 回、自動化を正常に実行できたことがわかりました。エンジニアが追加の EBS ストレージを手動でプロビジョニングし、OS 上で拡張するには、15〜30 分はかかります。したがって、1 か月だけで、当社のスタッフは 100〜200 時間を節約し、顧客は少なくとも 5〜10 回の潜在的な停止を防いだと推定しています。

Infor でこの自動化を実装して以降、プロビジョニング済み容量の枯渇とパフォーマンスの問題は排除されました。加えて、追加の EBS ストレージのプロビジョニングにエンジニアとシステム管理者が費やす時間と労力を大幅に削減することができました。これは、法律で必要とされていいるものです。

Moneer Rifai

Moneer Rifai

Moneer Rifai 氏は Infor の開発者です。Infor のクラウドインフラストラクチャ開発チームの同僚とともに、最新のテクノロジーと DevOps プラクティスを活用して、Infor での大規模な AWS インフラストラクチャの設計と自動化に取り組んでいます。この投稿は、彼のチームマネージャーである David Benjamin 氏、および開発者の Daniel Puckett 氏、Rafael Rodrigues 氏、Mariusz Borys 氏らの協力のもとで執筆されました。