Работая с различными поставщиками облачных услуг в моей роли разработчика программного обеспечения в DLT Labs, я натолкнулся на очень полезную технику, которую мы можем использовать для запуска команд или сценариев на виртуальных машинах Amazon Web Services (AWS). - Экземпляры EC2 - без необходимости доступа по SSH и без разрешения доступа к портам.
Для этого я буду использовать службу под названием AWS System Manager.
AWS System Manager (SSM) - один из многих популярных сервисов AWS, который помогает легко запускать удаленные команды или сценарии на одной или нескольких машинах EC2.
В этом блоге я расскажу, как это сделать с помощью AWS SDK NodeJS.
Цели
Во время реализации кода нашей целью будет выполнение следующих команд на машине EC2 с помощью AWS SSM:
- Нажмите sample.txt
- Эхо Я с целевой машины ›› sample.txt
- Ls
- Cat sample.txt
Кроме того, мы узнаем, как просмотреть статус команды и соответствующие журналы на сервере приложений.
Предварительные требования
Ожидается, что читатели будут иметь некоторые знания об Amazon AWS, например, они должны знать о ролях IAM, пользователях IAM и о том, как прикреплять роли к инстансам EC2. Кроме того, я буду использовать технический стек NodeJS. Подробности обоих описаны ниже:
1. Необходимые конфигурации и политики.
- Учетные данные пользователя IAM: создайте пользователя IAM и прикрепите к нему политики EC2 и SSM, чтобы он мог выполнять команды на целевых машинах. .
- Роль IAM: создайте новую роль IAM и прикрепите к ней политику AWSEC2RoleforSSM. Всем целевым машинам должна быть назначена эта роль, чтобы служба SSM могла связываться с машинами EC2.
2. Программное обеспечение / библиотеки
- Механизм NodeJS
- Модуль AWS-SDK. Чтобы установить этот модуль, используйте: npm i aws-sdk.
- Bluebird: используйте npm i bluebird.
- Lodash: используйте npm i lodash.
›› Реализация кода будет проходить в следующие этапы:
- Перед отправкой команд на целевую машину сначала мы проверим, готова ли целевая машина к приему команд.
- Если машина готова, то мы пришлем команды.
- После этого мы будем постоянно следить за статусом команды.
- Как только команда будет выполнена, мы сможем увидеть их журналы в консоли удаленного компьютера.
Все готово, давайте начнем с фактической реализации кода.
Реализация нашего кода
Шаг 1. Создайте файл samplefile.js.
Шаг 2. Импортируйте все модули и укажите учетные данные пользователя IAM в объекте SSM.
// Importing modules const AWS = require(‘aws-sdk’) const Promise = require(‘bluebird’) const _ = require(‘lodash’) const ssm = new AWS.SSM({ accessKeyId: ‘KLIAT7SDWDFRR4HBJ3E4N’, // Insert your IAM User Access Key secretAccessKey: ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’, //User secret key region: ‘us-east-2’ })
Шаг 3. Добавьте следующий фрагмент кода в samplefile.js.
// @params {Array} instanceIds : Array of instance ids async function mainFunction(instanceIds) { if (!Array.isArray(instanceIds)) instanceIds = [instanceIds]; console.info(“\n”); console.info(“Input Instances are: “, instanceIds, “\n”); try { let managedInstanceIds = await checkInstanceIsReady(instanceIds) console.info(“Managed Instances list ready to receive commands : “, managedInstanceIds, “\n”); if (!_.isEmpty(managedInstanceIds)) { let commandParameters = { DocumentName: “AWS-RunShellScript”, Targets: [{ Key: “InstanceIds”, Values: managedInstanceIds }], Parameters: { workingDirectory: [“/home/mydir”], commands: [“touch sample.txt”, “echo I am from target machine >> sample.txt”, “ls”, “cat sample.txt”] }, TimeoutSeconds: 60000, MaxConcurrency: “50”, MaxErrors: “0”, }; let data = await sendCommandToInstances(commandParameters); let commandExecStatus = await checkCommandStatus(data.Command.CommandId, 80); console.info(“Command Status is “, commandExecStatus , “\n”); for (let eachInstance = 0; eachInstance < managedInstanceIds.length; eachInstance++) { let logs = await getCommandsLogs(managedInstanceIds[eachInstance], data.Command.CommandId, commandExecStatus); console.info(“Commands logs for instance id “, managedInstanceIds[eachInstance], “ is \n”, logs); } return Promise.resolve(commandExecStatus); } else { console.error(“No Instances are ready for receiving the command”) return “No Instances are ready for receiving the commands” } } catch (err) { console.error(“Error came while sending commands “, err); return Promise.reject(err); } } try { mainFunction([“i-0b34cbaf7ff6aa3fd”]); } catch(err){ console.error(“Error while calling main function “, err); }
Когда мы запускаем samplefile.js, mainFunction (instanceIds) будет первой, откуда начинается выполнение.
Затем mainFunction(instanceIds
) вызовет другую функцию checkInstanceIsReady(instanceids)
.
Вызов CheckInstanceIsReady (instanceIdList)
/** * Function to check whether instances are ready to receive commands * and return an array of such instances * @params {Array} instanceId : Array of instance ids */ function checkInstanceIsReady(instanceIdList) { let readyInstancesList = [] let params = { InstanceInformationFilterList: [ { key: “InstanceIds”, valueSet: instanceIdList } ] } return new Promise((resolve, reject) => { ssm.describeInstanceInformation(params, function (err, data) { if (err) { console.error(err); reject(err); } let instanceObj = data.InstanceInformationList for (let eachInstance = 0; eachInstance < instanceObj.length; eachInstance++) { readyInstancesList.push(instanceObj[eachInstance][“InstanceId”]); } resolve(readyInstancesList); }) }) }
Функция checkInstanceIsReady(instanceIds)
, в свою очередь, вызывает встроенную функцию AWS SSM describeInstanceInformation()
и возвращает массив всех идентификаторов экземпляров, готовых к приему команд с удаленного компьютера.
Эти экземпляры называются управляемыми экземплярами, поскольку их можно настроить с помощью System Manager (SSM).
ПРИМЕЧАНИЕ. Если какой-либо экземпляр запущен, но все еще отсутствует в массиве, нам необходимо проверить следующее:
›Требуемая роль настроена правильно (описано в предварительных требованиях)
›Агент SSM установлен (если не установлен по умолчанию)
Теперь создайте объект commandParameters, который будет иметь следующие ключи:
- DocumentName: имя документа System Manager для запуска. Это может быть публичный документ или специальный документ. Здесь мы используем AWS-RunShellScript, который является общедоступным документом и используется для удаленного выполнения команд на компьютерах EC2.
- Параметры: . Обладает следующими свойствами.
- WorkingDirectory: массив целевых местоположений, в которых будут выполняться команды.
например,“/home/mydir”
- Команды: массив команд, которые мы хотим выполнить на целевой машине. Эти команды будут выполняться последовательно.
- Цели: он принимает пары "ключ-значение" для идентификации экземпляров.
- Ключ: определяемые пользователем критерии для отправки команд, нацеленных на экземпляры, соответствующие критериям.
- Значения: определяемые пользователем критерии, которые сопоставляются с ключом.
Например, если ключ - "InstanceIds", то соответствующие ему значения должны быть массивом идентификаторов экземпляров.
Этот объект commandParameters будет передан функции sendCommandToInstances(commandParameters)
.
Вызов sendCommandToInstances (commandParameters)
/** * Function will send the command to EC2 machines * @params {Object} commandParameters : command parameters information */ async function sendCommandToInstances(commandParameters) { return new Promise(function (resolve, reject) { ssm.sendCommand(commandParameters, function (err, data) { if (err) { console.error(“Unable to sendCommandToinstances:”, err.message); reject(“Request Failed! Instance Id/Credentials is not valid or Role not assigned to Ec2”); } resolve(data); }); }); }
Функция sendCommandToInstance(commandParameters)
вызовет другую встроенную функцию AWS SSM ssm.sendCommand()
и вернет объект, содержащий информацию о командах, то есть commandId, DocumentName, Status и т. Д.
Теперь мы вызовем функцию checkCommandStatus(commandId, maxRetry)
, которая впоследствии вызовет встроенную функцию AWS SSM ssm.listCommands()
. На основе commandId
, ssm.listCommands()
вернет соответствующий статус команды.
Вызов checkCommandStatus (commandId, maxRetry)
/** * Function will check the command status i.e. Success, Failed * @params {String} commandId : command Id * @params {Number} maxRetry */ async function checkCommandStatus(commandId, maxRetry) { let currentTry = 1; return new Promise((resolve, reject) => { let params = { CommandId: commandId }; let toStopInterval = setInterval(() => { ssm.listCommands(params, (err, data) => { if (err) reject(“Command id not found”); if (currentTry > maxRetry) { clearInterval(toStopInterval); reject(“Max Limit Reached! Status cannot determined”); } let commandStatus = data.Commands[0].Status; if (commandStatus === ‘InProgress’) { currentTry += 1; } else { clearInterval(toStopInterval); resolve(data.Commands[0].Status); } }); }, 1500); }); }
Здесь мы можем использовать setInterval().
для непрерывного мониторинга.
Если статус команды - Успешно или Неудачный, элемент управления сразу вернется к mainFunction()
, но если статус - InProgress
тогда ssm.listCommands()
function будет проверять статус, пока не будет достигнут maxRetry
предел.
На данный момент мы отправили команды на целевые машины и готовы просматривать их журналы.
Для этого мы вызываем функцию getCommandsLogs(instanceId, commandId, commandExecStatus)
, которая вызывает встроенную функцию AWS SSM ssm.getCommandInvocation()
и возвращает журналы команд в mainFunction()
.
Вызов getCommandsLogs (instanceId, commandId, commandExecStatus)
/** * Function will help to get the command logs * @params {Array} instanceId : Instance Id of Ec2 machine * @params {String} commandId : command Id * @params {String} commandExecStatus : command status */ async function getCommandsLogs(instanceId, commandId, commandExecStatus) { let params = { CommandId: commandId, InstanceId: instanceId } return new Promise((resolve, reject) => { ssm.getCommandInvocation(params, (err, data) => { if (err) { console.error(“Error came while fetching the logs “, err); reject(err); } let logs = commandExecStatus === “Success” ? data.StandardOutputContent : data.StandardErrorContent return resolve(logs); }) }) }
Вывод кода
Таким образом мы можем легко выполнять команды удаленно и видеть соответствующие журналы команд в консоли. С помощью SSM мы можем легко управлять нашими экземплярами и настраивать их, не входя в них.
Автор - Шивам Дхама, DLT Labs ™
Об авторе - Шивам в настоящее время связан с командой DL Tools и имеет практический опыт работы с веб-сервисами Amazon, NodeJS, Python, машинным обучением.
Amazon Web Services и AWS являются товарными знаками Amazon.com, Inc. или ее дочерних компаний в США и / или других странах. Node.js является зарегистрированным товарным знаком Joyent, Inc. npm является зарегистрированным товарным знаком npm, Inc. DLT Labs является товарным знаком DLT Global, Inc.
Ссылки:
Https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html
Https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/IAM.html