All Products
Search
Document Center

Elastic Compute Service:Jalankan perintah dengan SDK

Last Updated:Apr 28, 2026

Gunakan ECS SDK untuk menjalankan perintah Cloud Assistant pada beberapa instance ECS dan mengambil hasil eksekusinya tanpa perlu login.

Skenario contoh

Sistem O&M sangat penting untuk stabilitas bisnis. Untuk menjaga kesehatan instance ECS, lakukan pemeriksaan berkala terhadap penggunaan sumber daya seperti utilisasi CPU, konsumsi memori, dan penggunaan disk.

Cloud Assistant menjalankan perintah pada instance ECS tanpa login, sehingga memungkinkan otomatisasi tugas O&M seperti pemantauan sumber daya, pengumpulan log, dan troubleshooting.

Prasyarat

Pastikan persyaratan berikut terpenuhi:

Operasi API yang digunakan

Operasi API ECS berikut digunakan:

Operasi

Deskripsi

RunCommand

Menjalankan perintah pada satu atau beberapa instance ECS dan mengembalikan InvokeId untuk tugas perintah tersebut.

DescribeInvocations

Menanyakan hasil eksekusi perintah berdasarkan InvokeId.

Jenis perintah

Cloud Assistant mendukung tiga jenis perintah, yang ditentukan oleh parameter Type dalam RunCommand:

Type value

Deskripsi

RunShellScript

Perintah shell untuk instance Linux

RunBatScript

Perintah batch untuk instance Windows

RunPowerShellScript

Perintah PowerShell untuk instance Windows

Nilai status invokasi

Saat melakukan polling hasil, bidang InvocationStatus menunjukkan status perintah:

Status

Deskripsi

Pending

Perintah sedang diverifikasi atau dikirim.

Running

Perintah sedang berjalan.

Stopping

Perintah sedang dihentikan.

Finished

Perintah selesai.

Failed

Perintah gagal.

Stopped

Perintah dihentikan.

Kode contoh

Contoh Java dan Python berikut menunjukkan cara menjalankan perintah pada instance ECS dan melakukan polling terhadap hasil eksekusi menggunakan ECS SDK.

Java

Contoh ini membuat kelas CloudAssistantService yang menginisialisasi klien ECS, menjalankan perintah, dan melakukan polling terhadap hasil hingga perintah selesai atau timeout.

Perilaku utama:

  • Membuat klien ECS singleton yang aman untuk thread dengan double-checked locking.

  • Menjalankan cat /proc/meminfo pada instance yang ditentukan.

  • Melakukan polling setiap 2 detik, hingga maksimal commandTimeOut / delay kali percobaan.

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 {

    /**
     * Baca ID AccessKey dan rahasia AccessKey dari variabel lingkungan.
     */
    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() {
    }

    /**
     * Inisialisasi klien ECS.
     *
     * @param regionId ID wilayah tempat klien ECS terhubung.
     * @return Klien ECS yang telah diinisialisasi.
     * <p>
     * Metode ini menggunakan pola double-checked locking untuk memastikan pembuatan
     * singleton klien ECS yang aman untuk thread. Pertama-tama metode ini memeriksa apakah
     * klien sudah ada, lalu memeriksa kembali di dalam blok synchronized sebelum membuatnya.
     */
    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 wilayah.
            String regionId = "cn-chengdu";
            getEcsClient(regionId);
            // ID instance ECS tempat perintah akan dijalankan.
            List<String> instanceIds = Arrays.asList("i-2vcXXXXXXXXXXXXXXXb8", "i-2vcXXXXXXXXXXXXXXXot");
            // Perintah yang akan dijalankan.
            String commandContent = "#!/bin/bash\n cat /proc/meminfo";
            // Timeout eksekusi perintah, dalam detik.
            long commandTimeOut = 60;


            // Jalankan perintah.
            String invokeId = runCommand(commandContent, regionId, instanceIds, commandTimeOut);
            // Tanyakan hasil eksekusi perintah.
            DescribeInvocationsResponse invocationResult = describeInvocations(regionId, invokeId, commandTimeOut);
            System.out.println("Hasil eksekusi perintah:" + new Gson().toJson(invocationResult));
            // Catatan: Contoh ini tidak menyertakan konfigurasi logging.

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            SCHEDULER.shutdown();
        }
    }

    /**
     * Jalankan perintah pada instance ECS yang ditentukan.
     *
     * @param commandContent Perintah yang akan dijalankan.
     * @param regionId       ID wilayah instance ECS target.
     * @param instanceIds    ID instance ECS target.
     * @param commandTimeOut Timeout eksekusi perintah, dalam detik.
     * @return ID invokasi (InvokeId) dari tugas perintah.
     */
    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);
        }
    }

    /**
     * Tanyakan hasil eksekusi perintah Cloud Assistant.
     *
     * @param regionId       ID wilayah instance target.
     * @param invokeId       ID invokasi yang secara unik mengidentifikasi tugas perintah.
     * @param commandTimeOut Timeout eksekusi perintah, dalam detik.
     */
    public static DescribeInvocationsResponse describeInvocations(String regionId, String invokeId, long commandTimeOut) {
        DescribeInvocationsRequest describeInvocationsRequest = new DescribeInvocationsRequest()
                .setRegionId(regionId)
                .setInvokeId(invokeId);

        long delay = 2;
        // Jumlah maksimum percobaan polling.
        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("Hasil eksekusi perintah tidak ditemukan.");
                }
                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("Jumlah maksimum percobaan untuk hasil eksekusi perintah telah terlampaui.");
        } catch (Exception e) {
            throw new RuntimeException("describeInvocationResults failed", e);
        }
    }


    public static class Constants {
        // Jenis perintah.
        public static final class COMMAND_TYPE {
            // Perintah shell, berlaku untuk instance Linux.
            public static final String RUN_SHELL_SCRIPT = "RunShellScript";
            // Perintah batch, berlaku untuk instance Windows.
            public static final String RUN_BAT_SCRIPT = "RunBatScript";
            // Perintah PowerShell, berlaku untuk instance Windows.
            public static final String RUN_POWERSHELL_SCRIPT = "RunPowerShellScript";
        }

        // Nilai status invokasi untuk perintah Cloud Assistant.
        public static final class INVOCATION_STATUS {
            // Sistem sedang memverifikasi atau mengirim perintah.
            public static final String PENDING = "Pending";
            // Perintah sedang dijalankan pada instance ECS.
            public static final String RUNNING = "Running";
            // Perintah sedang dihentikan.
            public static final String STOPPING = "Stopping";
        }
    }
}

Python

Contoh ini menggunakan fungsi terpisah untuk inisialisasi klien, eksekusi perintah, penanyaan invokasi, dan polling penyelesaian.

Perilaku utama:

  • Memvalidasi jenis perintah terhadap RunShellScript, RunBatScript, dan RunPowerShellScript sebelum eksekusi.

  • Memastikan daftar ID instance tidak kosong.

  • Menggunakan exponential backoff saat polling: waktu tunggu berlipat ganda setiap percobaan (2 ^ retry_count detik).

  • Secara default menggunakan max(command_timeout // 2, 1) kali percobaan (30 kali untuk timeout 60 detik).

  • Menangani status terminal: Finished (sukses), Failed, dan Stopped.

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

# Konfigurasi logging.
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(
        "Variabel lingkungan wajib tidak ditemukan: ALIBABA_CLOUD_ACCESS_KEY_ID dan 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("Daftar ID instance tidak boleh kosong.")

    valid_command_types = ["RunShellScript", "RunBatScript", "RunPowerShellScript"]
    if command_type not in valid_command_types:
        raise ValueError(f"Jenis perintah tidak valid: {command_type}. Jenis yang valid adalah {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"Gagal mengeksekusi perintah: {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"Gagal menanyakan invokasi: {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("Hasil eksekusi perintah tidak ditemukan.")

        invocation_result = invocation_list[0]
        invocation_status = invocation_result.get('InvocationStatus')
        logging.info(f"Status invokasi saat ini: {invocation_status}")

        if invocation_status == "Finished":
            print("hasil query_invocations:", results)
            break
        elif invocation_status in ["Failed", "Stopped"]:
            raise RuntimeError(f"Eksekusi perintah gagal dengan status: {invocation_status}")
        else:
            retry_count += 1
    else:
        raise TimeoutError("Waktu eksekusi perintah habis.")


def main():
    # ID wilayah.
    region_id = "cn-chengdu"
    # ID instance ECS tempat perintah akan dijalankan.
    instance_ids = ["i-2vcXXXXXXXXXXXXXXXb8", "i-2vcXXXXXXXXXXXXXXXot"]
    # Perintah yang akan dijalankan.
    command_content = "#!/bin/bash\n cat /proc/meminfo"
    # Timeout eksekusi perintah, dalam detik.
    command_timeout = 60
    # Jenis perintah. Nilai yang valid: RunShellScript, RunBatScript, dan 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()