Как использовать AWS CloudWatch с локальными компонентами приложений?

AWS CloudWatch предлагает централизованное ведение журналов, мониторинг и анализ, чтобы упростить работу разработчика. Вопрос, который возникает для корпоративных приложений, которые следуют за развертыванием гибридного облака (то есть один или несколько компонентов приложения находятся локально), заключается в том, как мы можем использовать журналы CloudWatch для локального развертывания. компоненты? Это вообще возможно? Короткий ответ: да. И в этом посте мы увидим, как это сделать.

Зачем использовать CloudWatch для локальных компонентов?

Существует несколько преимуществ использования CloudWatch для локальных компонентов.

  • Использование централизованного ведения журналов: вы можете использовать те же возможности для централизованного хранения журналов для локальных компонентов, которые вы используете для остальных своих облачных компонентов.
  • Преобразование времени. Журналы CloudWatch хранятся в формате UTC. Таким образом, вам не нужно беспокоиться об утомительных преобразованиях, которые часто могут занимать ваше драгоценное время при анализе журналов по нескольким компонентам, особенно если они географически разбросаны.
  • Последовательный анализ. Вы можете использовать те же инструменты и методы, что и для облачных компонентов.
  • Избегайте таких проблем, как перенос журналов или затрудненный доступ к журналам. Часто локальные компоненты управляются клиентами или другими клиентами, что может потребовать некоторой координации и усилий.

Как публиковать в журналах CloudWatch локальные компоненты?

Для этого есть несколько подходов.

  1. Использование агента AWS CloudWatch Agent для публикации журналов: это может быть чрезвычайно полезно для локальных компонентов, которые следуют модели устройства для развертывания (например, предварительно подготовленный образ с компоненты приложения и зависимости). Таким образом, этот подход более ориентирован на конфигурацию и не требует изменений на уровне кода. Помимо сбора журналов, агент CloudWatch также может помочь в сборе системных показателей (таких как использование ЦП и памяти).
  2. Использование CloudWatch Logs API для публикации журналов. Этот подход требует улучшения кода для использования CloudWatch Logs API для публикации журналов. Конечно, вы можете сделать его повторно используемым модулем или рассмотреть возможность использования сторонней библиотеки. Но дело в том, что это подход, ориентированный на код, который обеспечивает большую гибкость.

В этом посте мы поговорим об использовании CloudWatch Logs API. Если вы заинтересованы в использовании агента CloudWatch, см. подробную информацию в документации Агент AWS CloudWatch.

Использование CloudWatch Logs API для публикации журналов

В следующем коде показано использование API CloudWatch Logs.

package com.cloudnineapps.samples.aws;

import java.util.ArrayList;
import java.util.List;

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.services.logs.AWSLogsClient;
import com.amazonaws.services.logs.AWSLogsClientBuilder;
import com.amazonaws.services.logs.model.CreateLogGroupRequest;
import com.amazonaws.services.logs.model.CreateLogStreamRequest;
import com.amazonaws.services.logs.model.DescribeLogGroupsRequest;
import com.amazonaws.services.logs.model.DescribeLogGroupsResult;
import com.amazonaws.services.logs.model.DescribeLogStreamsRequest;
import com.amazonaws.services.logs.model.DescribeLogStreamsResult;
import com.amazonaws.services.logs.model.InputLogEvent;
import com.amazonaws.services.logs.model.PutLogEventsRequest;
import com.amazonaws.services.logs.model.PutRetentionPolicyRequest;

/**
 * Sample client for AWS CloudWatch Logs API.
 */
public class AWSCloudWatchLogsSampleClient {

	/** The log group name. */
	private static final String LOG_GROUP = "/myapp/onprem/component-1";

	/** The log stream name. */
	private static final String LOG_STREAM = "app-log";
	
	/** The log retention period (in days). */
	private static final int LOG_RETENTION_PERIOD = 1;

	/** The AWS region. */
	private static String Region = "us-east-1";
	
	/** The CloudWatch client. */
	private static AWSLogsClient Client;
	
	
	/** Opens the CloudWatch log. */
	public static void openCloudWatchLog() throws Exception {
		AWSCredentialsProvider creds = new DefaultAWSCredentialsProviderChain();
		Client = (AWSLogsClient) AWSLogsClientBuilder.standard()
				     .withCredentials(creds)
				     .withRegion(Region)
				     .build();
		// Create and set up the log group if it doesn't exist
		DescribeLogGroupsRequest request = new DescribeLogGroupsRequest().withLogGroupNamePrefix(LOG_GROUP);
		DescribeLogGroupsResult result = Client.describeLogGroups(request);
		if (result.getLogGroups().isEmpty()) {
			CreateLogGroupRequest logGroupRequest = new CreateLogGroupRequest(LOG_GROUP);
			Client.createLogGroup(logGroupRequest);
			PutRetentionPolicyRequest policyRequest = new PutRetentionPolicyRequest(LOG_GROUP, LOG_RETENTION_PERIOD);
			Client.putRetentionPolicy(policyRequest);
			CreateLogStreamRequest logStreamRequest = new CreateLogStreamRequest(LOG_GROUP, LOG_STREAM);
			Client.createLogStream(logStreamRequest);
			log("Created the log group and the log stream.");
		}
	}
	
	/** Logs the specified message. */
	public static void log(String msg) throws Exception {
		// Retrieve the sequence token in the log stream
		DescribeLogStreamsRequest request = new DescribeLogStreamsRequest().withLogGroupName(LOG_GROUP).withLogStreamNamePrefix(LOG_STREAM);
		DescribeLogStreamsResult result = Client.describeLogStreams(request);
		String seqToken = result.getLogStreams().get(0).getUploadSequenceToken();

		// Write to the log stream
		List<InputLogEvent> logEvents = new ArrayList<InputLogEvent>();
		InputLogEvent logEvent = new InputLogEvent().withMessage(msg).withTimestamp(System.currentTimeMillis());
		logEvents.add(logEvent);
		PutLogEventsRequest logRequest = new PutLogEventsRequest(LOG_GROUP, LOG_STREAM, logEvents).withSequenceToken(seqToken);
		Client.putLogEvents(logRequest);
	}
		
	/** Main */
	public static void main(String[] args) throws Exception {
		System.out.println("Launching the application...");
		openCloudWatchLog();
		// Sample log statements
		log("Starting the app...");
		log("Another message");
		System.out.println("Execution completed.");
	}
}

Давайте пройдемся по коду. Полный код (включая maven pom, который можно использовать для компиляции и выполнения) можно найти в разделе Ресурсы.

  • Метод main() вызывает метод openCloudWatchLog() для инициализации клиента CloudWatch Logs SDK.
  • Метод openCloudWatchLog() проверяет, существует ли требуемая группа журналов (/myapp/onprem/component-1), используя вызовы DescribeLogGroupsRequest и Client.describeLogGroups(). Если нет, он создает группу журналов, используя вызовы CreateLogGroupRequest и Client.createLogGroup(). Мы всегда должны следить за тем, чтобы для группы журналов был установлен соответствующий период хранения журнала, чтобы избежать накопления огромного журнала, который может привести к высокой стоимости. Это достигается с помощью вызовов PutRetentionPolicyRequest и Client.putRetentionPolicy(). Затем мы создаем Log Stream, используя вызовы CreateLogStreamRequest и Client.createLogStream(). На следующем снимке экрана показана группа журналов в консоли CloudWatch.

  • Вот скриншот потока журналов в группе журналов.

  • Затем код использует метод log() для регистрации образцов сообщений. Он использует DescribeLogStreamsRequest и вызов Client.describeLogStreams() для извлечения потока журнала и получения маркера последовательности загрузки. Этот токен необходимо включать при публикации логов (кроме самой первой публикации). Затем мы создаем InputLogEvent с предоставленным сообщением и отметкой времени. Журнал публикуется с использованием вызовов PutLogEventsRequest и Client.putLogEvents(). Как вы могли заметить, вам не нужно публиковать отдельные операторы журнала. Вы вполне можете добавить несколько объектов InputLogEvent для публикации пакета журналов. На следующем снимке экрана показан пример выполнения кода.

Использование IAM-политики для ограничения доступа к определенному журналу

В рамках такой настройки важно использовать ограничительный доступ, чтобы локальный компонент мог получить доступ только к определенному журналу. Хорошо, что вы можете применить это с помощью IAM следующим образом.

  • Создайте одного или нескольких пользователей IAM для локальных компонентов. Предоставьте этим пользователям только программный доступ.
  • Создайте пользовательскую политику (или назначьте встроенную политику), подобную показанной ниже, и назначьте ее указанным выше пользователям IAM.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CloudWatchLogGroupQueryAccess",
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogGroups"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Sid": "CloudWatchLogsAccess",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:PutRetentionPolicy",
                "logs:DescribeLogStreams",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:log-group:/myapp/onprem/*:log-stream:*"
        }
    ]
}

Эта политика предоставляет доступ к необходимым вызовам API CloudWatch Logs только для локальных журналов.

Рекомендации по публикации журналов из локальных компонентов

Ниже приведены некоторые ключевые рекомендации, которые следует учитывать.

  • Ведение журнала может легко стать очень интенсивным в сети. Следовательно, будьте достаточно рассудительны в отношении того, какие журналы отправляются в журналы CloudWatch. Например, журналы ERROR и WARNING — хорошие кандидаты, а DEBUG — нет.
  • Избегайте регистрации любых конфиденциальных данных. Это очень важно, и часто не так хорошо продумано. Например, следует избегать регистрации паролей в виде простого текста, личной информации пользователей (PII) и т. д.
  • Всегда устанавливайте соответствующий период хранения журнала в группе журналов.
  • Используйте четко определенное соглашение об именах для группы журналов и потоков журналов. Например, /myapp/onprem/component-1.
  • Используйте ограничительную политику IAM для пользователя, который используется для публикации журналов, и убедитесь, что у него есть доступ только к журналам, относящимся к конкретному компоненту.
  • Для ведения журналов в нескольких приложениях предпочтительнее использовать пользователей IAM для конкретных приложений. Таким образом, вы сможете лучше отслеживать доступ и управлять им.

Вывод

При разработке гибридного облака или локальных компонентов оцените публикацию журналов в CloudWatch. Если следовать нескольким ключевым передовым методам, чтобы убедиться, что это делается в соответствии с потребностями приложения, а также соображениями готовности предприятия, такими как безопасность и производительность, это может быть весьма полезным для упреждающего мониторинга приложений и управления ими.

Ресурсы

Другие чтения





Удачной регистрации!
— Нитин

Первоначально опубликовано в Cloud Nine Apps.

Если вам понравился этот пост, вы найдете полезным мой курс AWS Advanced For Developers, посвященный передовым практикам и методам разработки и развертывания реальных приложений в AWS.