Cloud Assistant を使用すると、複数の Elastic Compute Service (ECS) インスタンスでコマンドを同時に実行できます。コマンドは、シェル、バッチ、または PowerShell コマンドです。このトピックでは、ECS SDK を使用して Cloud Assistant コマンドを実行し、コマンドの実行結果をクエリする方法について説明します。
前提条件
Cloud Assistant コマンドを実行する ECS インスタンスが 実行中 状態であり、インスタンスに クラウドアシスタントクライアント がインストールされていること。Cloud Assistant Agent のインストール方法については、「Cloud Assistant Agent をインストールする」をご参照ください。
ALIBABA_CLOUD_ACCESS_KEY_ID
およびALIBABA_CLOUD_ACCESS_KEY_SECRET
環境変数が、コードランタイム環境で設定されていること。環境変数の設定方法については、「Linux、macOS、および Windows で環境変数を設定する」をご参照ください。説明Alibaba Cloud アカウントの AccessKey ペアを保護するために、Resource Access Management (RAM) ユーザーを作成し、RAM ユーザーに ECS リソースへのアクセス権限を付与してから、RAM ユーザーの AccessKey ペアを使用して ECS SDK を呼び出すことをお勧めします。詳細については、「RAM ユーザー」をご参照ください。
RAM ユーザーに Cloud Assistant を使用する権限が付与されていること。詳細については、「RAM ユーザーに Cloud Assistant を使用する権限を付与する」をご参照ください。
実行する Cloud Assistant コマンドが準備されていること。コマンドは、シェル、バッチ、または PowerShell コマンドです。
プロジェクトに ECS SDK の依存関係がインストールされていること。詳細については、SDK センターの Elastic Compute Service ページをご覧ください。
サンプルシナリオ
最新のクラウドコンピューティング環境では、O&M 管理システムはビジネスの安定性を確保するために不可欠です。ECS インスタンスのパフォーマンスと安定性を確保するために、CPU 使用率、メモリ使用量、ディスク使用量などのリソース使用量を定期的に確認してください。たとえば、自動化された O&M 管理システムを開発するとします。Cloud Assistant のログイン不要機能に基づいて、自動化された O&M 管理システムでは、ECS インスタンスで Cloud Assistant コマンドをリモートで実行して、さまざまな O&M 要件を満たすことができます。自動化された O&M 管理システムは、さまざまなコマンドを ECS インスタンスに渡し、リソース監視、ログ収集、トラブルシューティングなどの複数の機能を実装できます。これにより、O&M 効率が大幅に向上し、効率的なビジネス運用のための信頼性の高いサポートが提供されます。
import com.aliyun.ecs20140526.Client;
import com.aliyun.ecs20140526.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.google.gson.Gson;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class CloudAssistantService {
/**
* 環境変数から AccessKey ID と AccessKey シークレットを取得します。
*/
private static final String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
private static final String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
private static volatile Client ecsClient;
private CloudAssistantService() {
}
/**
* ECS クライアントを初期化します。
*
* @param regionId リージョン ID。ECS クライアントが存在するリージョンを指定するために使用されます。
* @return 初期化された ECS クライアントを返します。
* <p>
* サンプルコードでは、二重チェックロックパターンを使用して、スレッドが安全な方法で単一の ECS クライアントを作成することを保証しています。
* ECS クライアントが既に存在するかどうかを確認します。ECS クライアントが存在しない場合は、同期ブロックでもう一度確認し、ECS クライアントを作成します。
*/
public static Client getEcsClient(String regionId) throws Exception {
if (ecsClient == null) {
synchronized (CloudAssistantService.class) {
if (ecsClient == null) {
Config config = new Config().setAccessKeyId(ACCESS_KEY_ID).setAccessKeySecret(ACCESS_KEY_SECRET).setRegionId(regionId);
ecsClient = new Client(config);
}
}
}
return ecsClient;
}
public static void main(String[] args_) {
try {
// リージョン ID。
String regionId = "cn-chengdu";
getEcsClient(regionId);
// コマンドを実行する ECS インスタンスの ID。
List<String> instanceIds = Arrays.asList("i-2vcXXXXXXXXXXXXXXXb8", "i-2vcXXXXXXXXXXXXXXXot");
// コマンドの内容。
String commandContent = "#!/bin/bash\n cat /proc/meminfo";
// コマンドの実行タイムアウト期間。
long commandTimeOut = 60;
// コマンドを実行します。
String invokeId = runCommand(commandContent, regionId, instanceIds, commandTimeOut);
// コマンドの実行結果をクエリします。
DescribeInvocationsResponse invocationResult = describeInvocations(regionId, invokeId, commandTimeOut);
System.out.println("コマンドの実行結果: " + new Gson().toJson(invocationResult));
// サンプルコードにはログ設定が含まれていません。
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
SCHEDULER.shutdown();
}
}
/**
* 指定された ECS インスタンスでコマンドを実行します。
*
* @param commandContent コマンドの内容。
* @param regionId ECS インスタンスが存在するリージョンの ID。
* @param instanceIds コマンドを実行する ECS インスタンスの ID。
* @param commandTimeOut コマンドの実行タイムアウト期間。
* @return コマンドのタスク ID を返します。
*/
public static String runCommand(String commandContent, String regionId, List<String> instanceIds, long commandTimeOut) {
try {
System.out.println("runCommand start...");
RunCommandRequest request = new RunCommandRequest();
request.setRegionId(regionId);
request.setType(Constants.COMMAND_TYPE.RUN_SHELL_SCRIPT);
request.setCommandContent(commandContent);
request.setInstanceId(instanceIds);
request.setTimeout(commandTimeOut);
RunCommandResponse runCommandResponse = ecsClient.runCommand(request);
return runCommandResponse.body.invokeId;
} catch (Exception e) {
throw new RuntimeException("runCommand failed", e);
}
}
/**
* Cloud Assistant コマンドの実行結果をクエリします。
*
* @param regionId リージョン ID。実行結果が属するリージョンを指定するために使用されます。
* @param invokeId タスク ID。タスクを一意に識別します。
* @param commandTimeOut コマンドの実行タイムアウト期間。
*/
public static DescribeInvocationsResponse describeInvocations(String regionId, String invokeId, long commandTimeOut) {
DescribeInvocationsRequest describeInvocationsRequest = new DescribeInvocationsRequest()
.setRegionId(regionId)
.setInvokeId(invokeId);
long delay = 2;
// 最大再試行回数を指定します。
int maxRetries = (int) (commandTimeOut / delay);
int retryCount = 0;
try {
while (retryCount < maxRetries) {
ScheduledFuture<DescribeInvocationsResponse> future = SCHEDULER.schedule(() ->
ecsClient.describeInvocations(describeInvocationsRequest), delay, TimeUnit.SECONDS);
DescribeInvocationsResponse results = future.get();
List<DescribeInvocationsResponseBody.DescribeInvocationsResponseBodyInvocationsInvocation> invocationList = results.body.invocations.invocation;
if (invocationList.isEmpty()) {
throw new RuntimeException("コマンドの実行結果が見つかりませんでした。");
}
DescribeInvocationsResponseBody.DescribeInvocationsResponseBodyInvocationsInvocation invocationResult = results.body.invocations.invocation.get(0);
String invocationStatus = invocationResult.invocationStatus;
switch (invocationStatus) {
case Constants.INVOCATION_STATUS.PENDING:
case Constants.INVOCATION_STATUS.RUNNING:
case Constants.INVOCATION_STATUS.STOPPING:
retryCount++;
continue;
default:
return results;
}
}
throw new RuntimeException("コマンドの実行結果の最大再試行回数を超えました。");
} catch (Exception e) {
throw new RuntimeException("describeInvocationResults failed", e);
}
}
public static class Constants {
// コマンドのタイプ。
public static final class COMMAND_TYPE {
// シェルコマンド。Windows インスタンスに適用されます。
public static final String RUN_SHELL_SCRIPT = "RunShellScript";
// バッチコマンド。Windows インスタンスに適用されます。
public static final String RUN_BAT_SCRIPT = "RunBatScript";
// PowerShell コマンド。Windows インスタンスに適用されます。
public static final String RUN_POWERSHELL_SCRIPT = "RunPowerShellScript";
}
// Cloud Assistant コマンドの実行結果。
public static final class INVOCATION_STATUS {
// システムはコマンドを確認または送信しています。
public static final String PENDING = "Pending";
// コマンドは ECS インスタンスで実行されています。
public static final String RUNNING = "Running";
// コマンドは停止されています。
public static final String STOPPING = "Stopping";
}
}
}
import os
import time
import logging
from alibabacloud_ecs20140526 import models as ecs_20140526_models
from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
from alibabacloud_tea_openapi import models as open_api_models
# ログを設定します。
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
ACCESS_KEY_ID = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
ACCESS_KEY_SECRET = os.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
if not ACCESS_KEY_ID or not ACCESS_KEY_SECRET:
raise EnvironmentError(
"必須の環境変数がありません: ALIBABA_CLOUD_ACCESS_KEY_ID と ALIBABA_CLOUD_ACCESS_KEY_SECRET")
def get_ecs_client(region_id):
config = open_api_models.Config(
access_key_id=ACCESS_KEY_ID,
access_key_secret=ACCESS_KEY_SECRET,
region_id=region_id
)
return Ecs20140526Client(config)
def execute_command(client, command_content, region_id, instance_ids, command_timeout, command_type):
if not instance_ids:
raise ValueError("インスタンス ID リストは空にできません。")
valid_command_types = ["RunShellScript", "RunBatScript", "RunPowerShellScript"]
if command_type not in valid_command_types:
raise ValueError(f"無効なコマンドタイプ: {command_type}。有効なタイプは {valid_command_types} です。")
request = ecs_20140526_models.RunCommandRequest()
request.region_id = region_id
request.type = command_type
request.command_content = command_content
request.instance_ids = instance_ids
request.timeout = command_timeout
try:
run_command_response = client.run_command(request)
return run_command_response.to_map()['body']['InvokeId']
except Exception as e:
logging.error(f"コマンドの実行に失敗しました: {e}")
raise
def query_invocations(client, region_id, invoke_id):
request = ecs_20140526_models.DescribeInvocationsRequest()
request.region_id = region_id
request.invoke_ids = [invoke_id]
try:
describe_invocations_response = client.describe_invocations(request)
return describe_invocations_response.to_map()['body']
except Exception as e:
logging.error(f"呼び出しのクエリに失敗しました: {e}")
raise
def wait_for_command_completion(client, region_id, invoke_id, max_retries, backoff_factor=2):
retry_count = 0
while retry_count < max_retries:
time.sleep(backoff_factor ** retry_count)
results = query_invocations(client, region_id, invoke_id)
invocation_list = results.get('Invocations', {}).get('Invocation', [])
if not invocation_list:
raise RuntimeError("コマンドの実行結果が見つかりませんでした。")
invocation_result = invocation_list[0]
invocation_status = invocation_result.get('InvocationStatus')
logging.info(f"現在の呼び出しステータス: {invocation_status}")
if invocation_status == "Finished":
print("query_invocations result:", results)
break
elif invocation_status in ["Failed", "Stopped"]:
raise RuntimeError(f"コマンドの実行はステータス {invocation_status} で失敗しました")
else:
retry_count += 1
else:
raise TimeoutError("コマンドの実行がタイムアウトしました。")
def main():
# リージョン ID。
region_id = "cn-chengdu"
# コマンドを実行する ECS インスタンスの ID。
instance_ids = ["i-2vcXXXXXXXXXXXXXXXb8", "i-2vcXXXXXXXXXXXXXXXot"]
# コマンドの内容。
command_content = "#!/bin/bash\n cat /proc/meminfo"
# コマンドの実行タイムアウト期間。
command_timeout = 60
# コマンドのタイプ。有効な値: RunShellScript、RunBatScript、RunPowerShellScript。
command_type = "RunShellScript"
client = get_ecs_client(region_id)
invoke_id = execute_command(client, command_content, region_id, instance_ids, command_timeout, command_type)
max_retries = max(int(command_timeout // 2), 1)
wait_for_command_completion(client, region_id, invoke_id, max_retries)
if __name__ == "__main__":
main()