ECS Fargate に New Relic を導入してみた
はじめに
おはようございます、もきゅりんです。
皆さん、日々可観測してますか?
自分は最近、稼働サービス収益に直結する、アプリケーションにおけるレイテンシや分散システムのトレーシングの課題について相談されるといったことが続いておりました。
目の前の課題に対して、暫定的な対応や処置を進めていくにせよ、中長期にどのようなモニタリングを目指していくのか、しっかりと検討の上、取り組めるようなオトナになりたいと思いました。
そんな気持ちもあって、弊社とも関係があります New Relic で、まずは ECS Fargate 設定を一通りしてみてよう、ということで コンテナアプリケーションのオブザーバビリティ実現手順 で紹介されている下図を参考に一通り設定してみました。
本稿では、アラートシステムの検討、設定についての対応はしません。
なお、そもそも New Relic の概要などは、下記ブログも参考として下さい。
今回の構成
AWS のチュートリアル 現代的なウェブアプリケーションの構築 の Mythical Mysfits というサンプルウェブサイトを構築して New Relic を導入していきます。
出来合いで、かつそれなりのアプリケーションが欲しかったので選択したのですが、構築にそれなりにかかります。。(2時間くらい構築だけでかかる)
前提
- 上記の構築が終わっていること
- New Relic アカウントを持っていること
1 AWS Cloud Integration
選択した枠を設定します。
この設定は、Amazon CloudWatch Metric Streams で New Relic にメトリックデータを流し込んでみる(Step-by-Step) | DevelopersIO のブログでの手順が丁寧です。
参照下さい。
CloudFormatin テンプレートで作成すると速いです。
完了して、 DynamoDB のメトリクスを Infrastructure で確認しているイメージです。
2 ECS Integration
選択した枠を設定します。
以下リンクを参考にすれば、すんなりと設定できます。
本稿では、 AWSCloudFormation テンプレート を使用します。何を作成するかは上記ページを参照下さい。ライセンスキーをパラメータ入力して実行します。
cd ~/enviroment/aws-modern-application-workshop/module-2/aws-cli/ curl -O https://download.newrelic.com/infrastructure_agent/integrations/ecs/newrelic-infra-ecs-fargate-example-latest.json
次に、実際に監視したいタスク定義にダウンロードしたタスク定義の例を追加し、以下の部分を修正します。タスク実行ロール及び Secret ARN は、デプロイした Cloudformation で自動生成されています。
- executionRoleArn: タスク起動に使用する IAM Role であるタスク実行ロールのARNを指定します
- containerDefinitions: newrelic-infra コンテナ部分を追加します
- containerDefinitions - newrelic-infra - secret - valueFrom: New Relic のライセンスキーが格納されている Secret ARN を指定します
ちなみに、 このSecret ARN は APM エージェントでも使います。
こんな感じで稼働コンテナのメトリクスが Container , APM 画面で表示されています。
3 Application Logs
選択した枠を設定します。
ログの収集には、 Three Ways To Forward Logs From Amazon ECS To New Relic | New Relic の通り、3つの方法がありますが、とりあえず Lambdaから収集する方法にします。
ログの用途が明確ではない場合、必要そうなログから収集して利用してみて、用途に応じて整形するなりしてログ送信する、さらには必要なログだけに限定して収集するなどを検討すると良いのでは、と考えています。
設定は、以下を参照下さい。
- AWS Lambda for sending CloudWatch logs | New Relic Documentation
- 無料枠の New Relic を使って WordPress を監視してみる(設定編) | DevelopersIO
4 APM (Python agent)
選択した枠を設定します。
このアプリのバックエンドは Python で動いているので、以下リンクを参考にベースイメージを作成して進めます。
なお、 下記リンクの通り、 Python agent version 7.0.0.166 or higher では、Distributed Tracing はデフォルトで設定済みです。
やること
- New Relic の環境変数を追加してタスク定義の更新
- APM Agentを導入したベースイメージの作成
- ECR or DockerHub に登録 (ECRの場合、タスクロールにイメージDL権限を付与)
- Logs in Context 用に Python コードを更新
- 新タスク定義で実行
- 2を反映したアプリイメージの更新/プッシュから CodePipeline でデプロイ
Codepipeline のローリングデプロイは、 実行中のタスク定義を更新するので、タスク定義をAWS CLI で更新したら別途サービスを更新する必要があります。
その後にコード変更して別途デプロイします。
1. NewRelic の環境変数を追加してタスク定義の更新
// cd ~/environment/aws-modern-application-workshop/module-2/app { "family": "mythicalmysfitsservice", "cpu": "256", "memory": "512", "networkMode": "awsvpc", "requiresCompatibilities": ["FARGATE"], "executionRoleArn": "arn:aws:iam::ACCOUNT_ID:role/ecsTaskExecutionRole", "taskRoleArn": "arn:aws:iam::ACCOUNT_ID:role/ECS_TASK_ROLE_NAME", "containerDefinitions": [ { "name": "MythicalMysfits-Service", "image": "ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/mythicalmysfits/service:latest", "portMappings": [ { "containerPort": 8080, "protocol": "http" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "mythicalmysfits-logs", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "awslogs-mythicalmysfits-service" } }, "secrets": [ { "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:ACCOUNT_ID:secret:NewRelicLicenseKeySecret-xxxxxxxxxx", "name": "NEW_RELIC_LICENSE_KEY" } ], "environment": [ { "name": "NEW_RELIC_APP_NAME", "value": "MythicalMysfits" }, { "name": "NEW_RELIC_LOG", "value": "stdout" } ], "essential": true }, { "environment": [ { "name": "NRIA_OVERRIDE_HOST_ROOT", "value": "" }, { "name": "NRIA_IS_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" }, { "name": "NRIA_CUSTOM_ATTRIBUTES", "value": "{\"nrDeployMethod\":\"downloadPage\"}" } ], "secrets": [ { "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:ACCOUNT_ID:secret:NewRelicLicenseKeySecret-xxxxxxxx", "name": "NRIA_LICENSE_KEY" } ], "cpu": 256, "memoryReservation": 512, "image": "newrelic/infrastructure-bundle:2.6.4", "name": "newrelic-infra" } ] }
NEW_RELIC_LICENSE_KEY
と NRIA_LICENSE_KEY
には、ECS Integration で作成した SecretsManger の ARN を記入します。
完了したら更新します。
// タスク定義の更新 aws ecs register-task-definition --cli-input-json file://~/environment/aws-modern-application-workshop/module-2/aws-cli/task-definition.json
タスク実行ロールに SecretsManager を参照する権限を付与するのを忘れずにして、ECS サービスを更新した新しいタスク定義で実行しておきます。
2. APM Agentを導入したベースイメージの作成
FROM ubuntu:latest RUN echo Updating existing packages, installing and upgrading python and pip. RUN apt-get update -y RUN apt-get install -y python3-pip python3-dev build-essential RUN pip3 install --upgrade pip RUN pip3 install --no-cache-dir newrelic ENTRYPOINT ["newrelic-admin", "run-program"]
2. ECR に登録
docker build . -t ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/mythicalmysfits/python_newrelic:latest aws ecr create-repository --repository-name mythicalmysfits/python_newrelic $(aws ecr get-login --no-include-email) docker push
// ~/environment/MythicalMysfitsService-Repository/Dockerfile FROM ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/mythicalmysfits/python_newrelic:latest RUN echo Copying the Mythical Mysfits Flask service into a service directory. COPY ./service /MythicalMysfitsService WORKDIR /MythicalMysfitsService RUN echo Installing Python packages listed in requirements.txt RUN pip3 install -r ./requirements.txt RUN echo Starting python and starting the Flask service... CMD ["python3","mythicalMysfitsService.py"]
3. Logs in Context 用に Python コードを更新
上記を参考に Python ファイルに以下のようにコピペします。
// cd ~/environment/MythicalMysfitsService-Repository/service from flask import Flask, jsonify, json, Response, request from flask_cors import CORS import mysfitsTableClient # Import the logging module and the New Relic log formatter import logging from newrelic.agent import NewRelicContextFormatter # Instantiate a new log handler handler = logging.StreamHandler() # Instantiate the log formatter and add it to the log handler formatter = NewRelicContextFormatter() handler.setFormatter(formatter) # Get the root logger and add the handler to it root_logger = logging.getLogger() root_logger.addHandler(handler) app = Flask(__name__) ...(省略)
ECR を使う場合は、 CodeBuild のロールに以下ポリシーを付与しておきましょう。
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- ecr:BatchCheckLayerAvailability
git add . git commit -m "Add NewRelic APM Python Agent." git push
設定完了すると、 APM 画面で以下のような表示がされます。
Logs 画面で以下のように表示されています。
trace.id
、span.id
を含んでいるログであることが分かります。
5 Browser
ついでなので、Browserモニタリングエージェントのインストール | New Relic Documentation を参考にしてエージェントをインストールします。
Browserモニタリングにより、リアルユーザーモニタリング(RUM)を行うことができます。
詳細は、Browserモニタリングの概要 | New Relic Documentation を参照ください。
今回は、S3 の静的サイトが対象なので、コピー/ペーストで有効化します。
埋め込む場所は、上記ページに記載されていますが、ページ内のできるだけ<head>
要素の最上部付近、ただし位置に敏感な <meta>
タグ(例、X-UA-Compatibleまたはcharset情報)の後に埋め込む形でペーストします。
完了すると、Browser 画面で以下のような表示がされます。
オマケ Diagnostics CLI (nrdiag)
なぜだかうまくいかない状況を確認するのに、 Run the Diagnostics CLI (nrdiag) | New Relic Documentation が役立ちます。
以下のような感じで利用して、うまくいかない原因を随時調査します。
wget http://download.newrelic.com/nrdiag/nrdiag_latest.zip unzip nrdiag_latest.zip cd nrdiag/linux ./nrdiag --help suites ./nrdiag_x64 --suites python
さいごに
ようやく可観測の準備が整ってきました。(Synthetics は設定必須ですが)
本当は分析まで検討したかったのですが、本稿は以上となります。
次回以降に、どのようなアプローチで New Relic では分析を進めていくのか、各機能を掘り下げながら触っていきたいと考えています。
以上です。
どなたかのお役に立てば幸いです。