通过云助手,您可以配置自动化批量处理日常运维任务,降低人工维护所耗费的大量时间和精力,提升故障排查效率。本教程示范如何通过云助手在ECS实例上批量执行一条echo 123的命令。

前提条件

使用云助手前,目标ECS实例必须满足以下条件:
  • 已安装云助手客户端。如何安装,请参见云助手客户端
  • 状态为运行中Running)。
  • 网络类型为专有网络VPC。
  • 执行PowerShell命令时,Windows实例已经配置了PowerShell模块。更多详情,请参见 微软官网文档 安装Windows PowerShell

使用方式

方法一:通过阿里云CLI调用API

通过阿里云CLI调用API之前,请确保已完成以下操作:

本示例仅传入了部分基本参数,执行结果采用默认设置。您可以阅读API文档后自定义运行命令,优化运行效果。

  1. 可选: 检查实例状态,若实例的状态不是运行中Running),调用StartInstance接口运行目标实例。
    aliyun ecs StartInstance --InstanceId i-bp1g6zv0ce8og******p
  2. 可选: 调用DescribeCloudAssistantStatus接口查询目标实例是否安装了云助手客户端。
    返回CloudAssistantStatus=true结果时,表示实例已安装云助手客户端。否则,请调用InstallCloudAssistant接口为实例安装客户端。
  3. 调用CreateCommand接口创建一份名为test的云助手命令,命令内容为echo 123,并使用Base64编码明文命令。
    aliyun ecs CreateCommand --RegionId TheRegionId --CommandContent ZWNobyAxMjM= --Type RunShellScript --Name test --Description test --output cols=CommandId

    如果目标实例为Windows实例,将Type修改为RunBatScript或者RunPowershellScript

  4. 调用InvokeCommand接口为一台或多台实例执行已创建的云助手命令,并获取返回参数InvokeId
    aliyun ecs InvokeCommand --RegionId TheRegionId --InstanceId.1 i-bp1g6zv0ce8og******p --InstanceId.2 i-bp1g6zv0ce8og******p --CommandId your-command-id --Timed false --output cols=InvokeId
    周期性任务可以通过Timed=true和参数Frequency指定运行周期,例如0 */20 * * * *表示周期为每20分钟。 更多关于Cron表达式详情,请参见Cron表达式
  5. 调用DescribeInvocations接口查看命令执行状态。
    aliyun ecs DescribeInvocations --RegionId TheRegionId --InvokeId your-invoke-id
  6. 调用DescribeInvocationResults查看指定实例的命令的实际执行结果。
    aliyun ecs DescribeInvocationResults --RegionId TheRegionId --InstanceId i-bp1g6zv0ce8og******p --InvokeId your-invoke-id

方法二:通过ECS Python SDK调用API

通过ECS Python SDK调用API之前,请确保已完成以下操作:
示例代码如下:
# coding=utf-8
# If the Python sdk is not installed, run 'sudo pip install aliyun-python-sdk-ecs'.
# Make sure you're using the latest sdk version.
# Run 'sudo pip install --upgrade aliyun-python-sdk-ecs' to upgrade.

import json
import logging
import os
import time
import datetime
import base64
from aliyunsdkcore import client

from aliyunsdkecs.request.v20140526.CreateCommandRequest import CreateCommandRequest
from aliyunsdkecs.request.v20140526.InvokeCommandRequest import InvokeCommandRequest
from aliyunsdkecs.request.v20140526.DescribeInvocationResultsRequest import DescribeInvocationResultsRequest

# configuration the log output formatter, if you want to save the output to file,
# append ",filename='ecs_invoke.log'" after datefmt.
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',filename='aliyun_assist_openapi_test.log', filemode='w')
#access_key = 'Your Access Key Id'
#acess_key_secrect = 'Your Access Key Secrect'
#region_name = 'cn-shanghai'
#zone_id = 'cn-shanghai-b'

access_key = 'LTAIXXXXXXXXXXXX'  # 请根据实际情况填写
acess_key_secrect = '4dZXXXXXXXXXXXXXXXXXXXXXXXX'  # 请根据实际情况填写
region_name = 'cn-hangzhou'  # 请根据实际情况填写
zone_id = 'cn-hangzhou-f'  # 请根据实际情况填写

clt = client.AcsClient(access_key, acess_key_secrect, region_name)

def create_command(command_content, type, name, description):
    request = CreateCommandRequest()
    request.set_CommandContent(command_content)
    request.set_Type(type)
    request.set_Name(name)
    request.set_Description(description)
    response = _send_request(request)
    if response is None:
        return None
    command_id = response.get('CommandId')
    return command_id;

def invoke_command(instance_id, command_id, timed, cronat):
    request = InvokeCommandRequest()
    request.set_Timed(timed)
    InstanceIds = [instance_id]
    request.set_InstanceIds(InstanceIds)
    request.set_CommandId(command_id)
    request.set_Frequency(cronat)
    response = _send_request(request)
    invoke_id = response.get('InvokeId')
    return invoke_id;

def get_task_output_by_id(instance_id, invoke_id):
    logging.info("Check instance %s invoke_id is %s", instance_id, invoke_id)
    request = DescribeInvocationResultsRequest()
    request.set_InstanceId(instance_id)
    request.set_InvokeId(invoke_id)
    response = _send_request(request)
    invoke_detail = None
    output = None
    if response is not None:
        result_list = response.get('Invocation').get('InvocationResults').get('InvocationResult')
        for item in result_list:
            invoke_detail = item
            output = base64.b64decode(item.get('Output'))
            break;
        return output;

def execute_command(instance_id):
    command_str = 'yum check-update'
    command_id = create_command(base64.b64encode(command_str), 'RunShellScript', 'test', 'test')
    if(command_id is None):
        logging.info('create command failed')
        return

    invoke_id = invoke_command(instance_id, command_id, 'false', '')
    if(invoke_id is None):
        logging.info('invoke command failed')
        return

    time.sleep(15)

    output = get_task_output_by_id(instance_id, invoke_id)
    if(output is None):
        logging.info('get result failed')
        return

    logging.info("output: %s is \n", output)

# send open api request
def _send_request(request):
    request.set_accept_format('json')
    try:
        response_str = clt.do_action(request)
        logging.info(response_str)
        response_detail = json.loads(response_str)
        return response_detail
    except Exception as e:
        logging.error(e)

if __name__ == '__main__':
    execute_command('i-bp17zhpbXXXXXXXXXXXXX')
				

方法三:通过ECS控制台使用云助手

通过ECS控制台使用云助手的步骤,请参见新建命令

方法四:通过OOS控制台使用云助手

通过OOS控制台使用云助手的步骤,请参见 运维编排服务OOS文档 在多台ECS实例内批量执行命令