All Products
Search
Document Center

Elastic Compute Service:Jalankan perintah menggunakan SDK

Last Updated:Feb 28, 2026

Cloud Assistant memungkinkan Anda menjalankan perintah shell, batch, atau PowerShell pada beberapa instance Elastic Compute Service (ECS) secara bersamaan tanpa perlu login ke masing-masing instance. Topik ini memandu Anda dalam penggunaan SDK ECS untuk menjalankan perintah Cloud Assistant dan mengambil hasil eksekusinya.

Skenario contoh

Dalam lingkungan komputasi awan, sistem manajemen O&M (operasi dan pemeliharaan) sangat penting untuk menjaga stabilitas bisnis. Untuk memastikan kesehatan instance ECS, Anda perlu memeriksa penggunaan sumber daya secara berkala, seperti pemanfaatan CPU, konsumsi memori, dan penggunaan disk.

Pertimbangkan untuk membangun sistem manajemen O&M otomatis. Dengan memanfaatkan kemampuan tanpa login dari Cloud Assistant—yaitu menjalankan perintah pada instance tanpa perlu login ke instance tersebut—sistem ini dapat mengeksekusi perintah Cloud Assistant secara jarak jauh pada instance ECS untuk menangani berbagai tugas O&M. Anda dapat mengirimkan perintah berbeda ke instance guna menjalankan fungsi seperti pemantauan sumber daya, pengumpulan log, dan troubleshooting. Pendekatan ini secara signifikan meningkatkan efisiensi O&M dan memberikan dukungan andal bagi operasi bisnis.

Prasyarat

Sebelum memulai, pastikan persyaratan berikut terpenuhi:

  • Instance ECS target berada dalam status Running, dan Cloud Assistant Agent telah diinstal pada setiap instance. Untuk petunjuk instalasi, lihat Install Cloud Assistant Agent.

  • Variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID dan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah dikonfigurasi di lingkungan runtime Anda. Untuk petunjuk penyiapan, lihat Configure environment variables in Linux, macOS, and Windows.

    Catatan

    Untuk melindungi akun Alibaba Cloud Anda, kami menyarankan agar Anda membuat pengguna Resource Access Management (RAM), memberikannya izin yang diperlukan untuk mengakses sumber daya ECS, dan menggunakan pasangan Kunci Akses pengguna RAM untuk memanggil operasi SDK ECS. Untuk informasi selengkapnya, lihat Pengguna RAM.

  • Pengguna RAM memiliki izin untuk menggunakan Cloud Assistant. Untuk informasi selengkapnya, lihat Grant a RAM user permissions to use Cloud Assistant.

  • Anda telah menyiapkan perintah Cloud Assistant yang ingin dijalankan. Perintah tersebut dapat berupa perintah shell, batch, atau PowerShell.

  • Dependensi SDK ECS telah diinstal untuk proyek Anda. Untuk informasi selengkapnya, kunjungi halaman Elastic Compute Service di SDK Center.

Operasi API yang digunakan

Topik ini menggunakan operasi API ECS berikut:

OperasiDeskripsi
RunCommandMenjalankan perintah pada satu atau beberapa instance ECS. Mengembalikan InvokeId yang mengidentifikasi tugas perintah tersebut.
DescribeInvocationsMenanyakan hasil eksekusi perintah Cloud Assistant berdasarkan InvokeId-nya.

Jenis perintah

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

Jenis NilaiDeskripsi
RunShellScriptPerintah shell, berlaku untuk instance Linux
RunBatScriptPerintah batch, berlaku untuk instance Windows
RunPowerShellScriptPerintah PowerShell, berlaku untuk instance Windows

Nilai status invocation

Saat melakukan polling terhadap hasil eksekusi perintah, bidang InvocationStatus menunjukkan status saat ini dari perintah tersebut:

StatusDeskripsi
PendingSistem sedang memverifikasi atau mengirim perintah.
RunningPerintah sedang dijalankan pada instance ECS.
StoppingPerintah sedang dihentikan.
FinishedPerintah berhasil diselesaikan.
FailedEksekusi perintah gagal.
StoppedPerintah dihentikan.

Kode contoh

Contoh kode berikut menunjukkan cara menggunakan SDK ECS untuk menjalankan perintah pada instance ECS dan melakukan polling terhadap hasil eksekusinya. Contoh dalam Java dan Python disediakan.

Java

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

Perilaku utama:

  • Menggunakan pola double-checked locking untuk membuat klien ECS singleton yang aman untuk thread.

  • Menjalankan perintah shell (cat /proc/meminfo) pada instance yang ditentukan.

  • Melakukan polling terhadap hasil eksekusi 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 yang menentukan 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. Metode ini pertama-tama
     * memeriksa apakah klien sudah ada, lalu memeriksa ulang dalam blok synchronized
     * sebelum membuat klien baru.
     */
    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 invocation (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 invocation 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 mendapatkan 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 invocation 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 Python menyediakan pendekatan modular dengan fungsi terpisah untuk inisialisasi klien, eksekusi perintah, penanyaan invocation, dan polling penyelesaian.

Perilaku utama:

  • Memvalidasi jenis perintah terhadap tiga nilai yang valid (RunShellScript, RunBatScript, RunPowerShellScript) sebelum eksekusi.

  • Memvalidasi bahwa daftar ID instance tidak kosong.

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

  • Jumlah maksimum percobaan secara default adalah max(command_timeout // 2, 1), yaitu 30 kali percobaan 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 yang diperlukan tidak tersedia: 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 invocation: {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 invocation saat ini: {invocation_status}")

        if invocation_status == "Finished":
            print("query_invocations result:", 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 telah 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()