Работая с различными поставщиками облачных услуг в моей роли разработчика программного обеспечения в 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. Перед отправкой команд на целевую машину сначала мы проверим, готова ли целевая машина к приему команд.
  2. Если машина готова, то мы пришлем команды.
  3. После этого мы будем постоянно следить за статусом команды.
  4. Как только команда будет выполнена, мы сможем увидеть их журналы в консоли удаленного компьютера.

Все готово, давайте начнем с фактической реализации кода.

Реализация нашего кода

Шаг 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