こんにちは。香田です。
今回はNew Relic FlexをECS Fargateで実行しカスタム イベントを送信する方法を紹介していきます。
New Relicのアカウントについては、必要に応じて下記を参考にサインアップしてみてください。
New Relic Flexについて
New Relci Flexについて簡単に紹介します。
New Relic Flexを利用すると、特定のアプリケーション向けではなく、HTTP、ファイル、シェルコマンド等を利用し任意のデータをNew Relicへ送信することが可能となります。
New Relic Infrastructure Agentのプラグインとして組み込まれている為、Flex用の設定ファイルを追加することで利用可能となります。
ECS Fargate環境について
今回構築するNew Relic Flexは下記のようにECS Fargate上でコンテナとして実行していきます。
ECS FargateなどAWS環境の構築は、Terraformを利用し各リソースを作成していきます。
New Relic Flex コンテナイメージの作成
はじめにNew Relic Flexコンテナ用のDockerfileを作成します。
- Dockerfile
FROM newrelic/nri-ecs:1.8.0
ADD ./flex.yml /etc/newrelic-infra/integrations.d/
New Relic Flexの設定ファイルを作成します。
New Relic Flexの設定ファイル例は、GitHub リポジトリのほうも参考にしてみてください。
- flex.yml
integrations:
- name: nri-flex
interval: 60s
timeout: 5s
config:
name: sample
apis:
- event_type: JsonApiCallSample
url: https://jsonplaceholder.typicode.com/todos/1
method: GET
New Relic Flex 検証用のDocker Composeを作成
New Relic Flexの検証用にDocker Compose環境を用意します。
- docker-compose.yml
version: "3"
services:
newrelic-flex:
container_name: newrelic-flex
build:
context: .
dockerfile: ./Dockerfile
image: nri-ecs-custom:1.8.0
entrypoint: [ "/bin/bash" ]
volumes:
- ".:/workspace"
working_dir: /workspace
tty: true
コンテナ起動しログイン
$ docker-compose up -d
$ docker-compose exec newrelic-flex bash
下記コマンドを実行することで、New Relic Flexで送信されるカスタムイベントが確認可能です。
コマンド実行してもNew Relicへデータは転送されない為、開発時に有効かと思います。
$ /var/db/newrelic-infra/newrelic-integrations/bin/nri-flex \
--config_file flex.yml \
--verbose --pretty
コンテナからログアウト
$ exit
Terraform AWSプロバイダの設定
Terraformを利用し環境構築を進めてていきます。AWSリソース作成用にAWSプロバイダを設定します。
provider "aws" {
region = "ap-northeast-1"
}
IAM ロールの作成
ECSで利用するIAM ロールとして、「ECS タスク実行 IAM ロール」と「タスク用のIAM ロール」を作成します。
ECS タスク実行 IAM ロールを作成します。
resource "aws_iam_role" "ecs_task_execution_role" {
name = "newrelic-cluster-ecs-task-execution-role"
path = "/"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : "sts:AssumeRole",
"Principal" : {
"Service" : "ecs-tasks.amazonaws.com"
},
"Effect" : "Allow"
}
]
})
}
resource "aws_iam_role_policy" "ecs_task_execution_role" {
name = "newrelic-cluster-ecs-task-execution-role"
role = aws_iam_role.ecs_task_execution_role.name
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource" : "*"
},
{
"Effect" : "Allow",
"Action" : [
"ssm:GetParameters"
],
"Resource" : "*"
}
]
})
}
タスク用のIAM ロールを作成します。
resource "aws_iam_role" "ecs_task_role" {
name = "newrelic-cluster-ecs-task-role"
path = "/"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : "sts:AssumeRole",
"Principal" : {
"Service" : "ecs-tasks.amazonaws.com"
},
"Effect" : "Allow"
}
]
})
}
resource "aws_iam_role_policy" "ecs_task_role" {
name = "newrelic-cluster-ecs-task-role"
role = aws_iam_role.ecs_task_role.name
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Action" : [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel",
],
"Resource" : "*"
},
{
"Effect" : "Allow",
"Action" : [
"logs:DescribeLogGroups",
"logs:CreateLogStream",
"logs:DescribeLogStreams",
"logs:PutLogEvents"
],
"Resource" : "*"
}
]
})
}
CloudWatch Logsの作成
New Relic FlexコンテナとECS Exec実行時のログ出力先としてCloudWatch Logsを作成します。
resource "aws_cloudwatch_log_group" "ecs_exec" {
name = "/aws/ecs/newrelic-cluster/ecs-exec"
retention_in_days = 14
}
resource "aws_cloudwatch_log_group" "newrelic_flex" {
name = "/aws/ecs/newrelic-cluster/newrelic-flex"
retention_in_days = 14
}
SSM Parameter Storeの作成
New Relic Flexコンテナで利用するライセンスキーを設定します。
resource "aws_ssm_parameter" "newrelic_license_key" {
name = "/newrelic/license_key"
type = "SecureString"
value = "New Relic ライセンスキー"
}
ECR リポジトリの作成
コンテナイメージの保存先としてECRを作成します。
resource "aws_ecr_repository" "newrelic_flex" {
name = "newrelic-flex"
image_tag_mutability = "MUTABLE"
image_scanning_configuration {
scan_on_push = true
}
}
ECS クラスターの作成
ECS クラスターを作成します。
resource "aws_ecs_cluster" "newrelic" {
name = "newrelic-cluster"
setting {
name = "containerInsights"
value = "enabled"
}
configuration {
execute_command_configuration {
logging = "OVERRIDE"
log_configuration {
cloud_watch_log_group_name = aws_cloudwatch_log_group.ecs_exec.name
}
}
}
}
resource "aws_ecs_cluster_capacity_providers" "newrelic" {
cluster_name = aws_ecs_cluster.newrelic.name
capacity_providers = ["FARGATE", "FARGATE_SPOT"]
}
ECS タスク定義の作成
New Relic Flexコンテナ用のタスク定義を作成します。
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
resource "aws_ecs_task_definition" "newrelic_flex" {
family = "newrelic-flex"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = "256"
memory = "512"
task_role_arn = aws_iam_role.ecs_task_role.arn
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
container_definitions = jsonencode([
{
"name" : "newrelic-flex",
"image" : "${aws_ecr_repository.newrelic_flex.repository_url}:latest",
"cpu" : 256,
"memoryReservation" : 512,
"secrets" : [
{
"name" : "NRIA_LICENSE_KEY",
"valueFrom" : aws_ssm_parameter.newrelic_license_key.arn
}
],
"environment" : [
{
"name" : "NRIA_OVERRIDE_HOST_ROOT",
"value" : ""
},
{
"name" : "NRIA_IS_SECURE_FORWARD_ONLY",
"value" : "true"
},
{
"name" : "FARGATE",
"value" : "true"
},
{
"name" : "ENABLE_NRI_ECS",
"value" : "true"
},
{
"name" : "NRIA_PASSTHROUGH_ENVIRONMENT",
"value" : "ECS_CONTAINER_METADATA_URI,ENABLE_NRI_ECS,FARGATE"
}
],
"essential" : true,
"linuxParameters" : {
"initProcessEnabled" : true
}
"logConfiguration" : {
"logDriver" : "awslogs",
"options" : {
"awslogs-group" : aws_cloudwatch_log_group.newrelic_flex.name,
"awslogs-stream-prefix" : "newrelic-flex",
"awslogs-region" : data.aws_region.current.name
}
}
}
])
}
ECS サービスの作成
New Relic Flexコンテナ用のECS サービスを作成します。
ECS サービスで利用するサブネット、セキュリティグループは、デフォルトVPCのものを利用しています。
data "aws_vpc" "default" {
default = true
}
data "aws_security_group" "default" {
name = "default"
vpc_id = data.aws_vpc.default.id
}
data "aws_subnets" "default" {
filter {
name = "vpc-id"
values = [data.aws_vpc.default.id]
}
}
resource "aws_ecs_service" "newrelic_flex" {
name = "newrelic-flex"
cluster = "newrelic-cluster"
desired_count = 1
enable_execute_command = true
task_definition = aws_ecs_task_definition.newrelic_flex.arn
capacity_provider_strategy {
capacity_provider = "FARGATE"
weight = 1
}
network_configuration {
subnets = data.aws_subnets.default.ids
security_groups = [
data.aws_security_group.default.id
]
assign_public_ip = true
}
lifecycle {
ignore_changes = [
desired_count,
]
}
}
AWSリソースの作成
terraform applyを実行しAWSリソースを作成します。
$ terraform init
$ terraform apply
ECRへイメージ登録
イメージをビルドしECRへ登録していきます。
ECRへログインします。
$ export ECR_URI_BASE=$(aws sts get-caller-identity --query Account --output text).dkr.ecr.ap-northeast-1.amazonaws.com
$ aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URI_BASE
ビルドしECR リポジトリへ登録します。
$ docker build -t newrelic-flex:latest .
$ docker tag newrelic-flex:latest $ECR_URI_BASE/newrelic-flex:latest
$ docker push $ECR_URI_BASE/newrelic-flex:latest
New Relic Query builderで確認
しばらくするとNew Relicへデータ送信され確認できるはずです。
New RelicのQuery builderへアクセスします。
下記のクエリを実行し、New Relic Flexの設定ファイルで定義したカスタムイベントが取得されているか確認します。
SELECT event_type,api.StatusCode,title,userId FROM JsonApiCallSample SINCE 10 minutes ago
下記のようにデータが取得できていれば成功です。
New Relic Flexで環境変数の利用について
New Relic Flexで環境変数を元にカスタムイベントを送信したい場合があるかと思います。
環境変数を利用する場合、Flexの設定ファイルへ利用したい環境変数のprefixに$$
を設定します。
- 例) Postgres Databaseよりデータ取得
integrations:
- name: nri-flex
interval: 60s
timeout: 5s
config:
name: sample
apis:
- event_type: PgStatActivity
database: postgres
db_conn: dbname=$$DB_NAME user=$$DB_USER host=$$DB_HOST sslmode=disable port=5432
logging:
open: true
db_queries:
- name: PgStatActivity
run: select * FROM pg_stat_activity
ECS タスク定義に追加したい環境変数を設定し、追加した環境変数をNRIA_PASSTHROUGH_ENVIRONMENT
に追加することで、環境変数が利用可能となります。
"environment" : [
{
"name" : "DB_HOST",
"value" : "xxxx"
},
...
{
"name" : "NRIA_PASSTHROUGH_ENVIRONMENT",
"value" : "ECS_CONTAINER_METADATA_URI,ENABLE_NRI_ECS,FARGATE,DB_HOST"
},
さいごに
New Relic FlexをECS Fargateで実行しカスタム イベントを送信する方法如何でしたでしょうか?
データベースに登録されているデータや内部APIのHTTPステータスなど、様々なデータを取得したい場合メリットは大きいのではないでしょうか。
最後までご覧いただきありがとうございます。