【New Relic】ECS上のPythonアプリケーションへのAPM導入までの流れ

記事タイトルとURLをコピーする

はじめに

こんにちは、サーバーワークスの福田です。

今回は、PythonアプリケーションにNew Relic APMを導入する方法について、ECS Fargate環境での具体的な設定例を交えてご紹介します。

私はインフラメインのエンジニアなので当初はAPM導入に抵抗があったものの、New Relic APMの導入はすごく簡単です。とはいえ、「簡単」と言われても何もわからない状態での導入は抵抗があると思います。

New Relicでは、Docker環境含めPython APM導入手順が「Guided Install」として提供されています。 今回は、このGuided Install画面をベースにしつつ、ECS Fargate + GitHub Actions環境へのAPM導入方法を備忘録として残しておきます。

今回の構成

今回APMを導入した環境は以下の通りです。

Install the agent 画面での操作

ディレクトリ構成

New RelicのGuided Instalでは、以下のようなディレクトリ構成が例として記載されています。

python-docker
├── newrelic
│   └── Dockerfile
├── src
│   ├── Dockerfile
│   ├── your_app.py
│   ├── newrelic.ini
│   └── requirements.txt

補足: Guided Installでは newrelic/Dockerfilesrc/Dockerfile を分けてベースイメージを作成する構成ですが、今回は1つのDockerfileで完結する構成にしています。

ポイントは newrelic.ini をアプリケーションコード(src/)と同じディレクトリに配置することです。これにより、Dockerイメージに設定ファイルが含まれ、NEW_RELIC_CONFIG_FILE 環境変数でパスを指定できるようになります。


requirements.txtへの追加

Guided Install画面の「② Install the APM agent」および「③ Create the requirements file」に該当する部分です。

まずはNew Relic Pythonエージェントをインストールします。

# APM Monitoring
newrelic==11.3.0

Guided Installでは pip install newrelic でインストール後、pip freeze > requirements.txt でファイルを生成する手順が紹介されています。既存のアプリケーションに追加する場合は、上記のように requirements.txt に直接追記する形でも問題ありません。

補足: Guided Installでは pip install newrelic を実行する手順が紹介されていますが、Dockerfileで pip install -r requirements.txt を実行する構成の場合、requirements.txtnewrelic を記載しておけばビルド時に自動でインストールされます。そのため、手動で pip install newrelic を実行する必要はありません。

バージョンについては PyPI で最新版を確認することをお勧めします。古いバージョンだと新機能が使えなかったり、既知のバグが残っていたりすることがあります。

Configure the agent 画面での操作

newrelic.ini設定ファイルの作成

Guided Install画面の「② Create a basic configuration file」および「③ Customize the configuration file」に該当する部分です。

New Relicの設定ファイルを作成します。Guided Installでは以下のコマンドで自動生成することもできます。

newrelic-admin generate-config YOUR_LICENSE_KEY newrelic.ini

その後、app_name を任意の名前に変更します。今回は手動で作成しました。

設定例

[newrelic]

# ライセンスキー
license_key = YOUR_LICENSE_KEY_HERE

# アプリケーション名(New Relic UIでの表示名)
app_name = APPNAME

# 監視モード(falseにするとデータ送信が無効化される)
monitor_mode = true

# ログ出力先(コンテナ環境ではstdoutを推奨)
log_file = stdout

# ログレベル(debug, info, warning, error, critical)
log_level = info

# High Security Mode(機密データの送信を制限)
high_security = false

# ---------------------------------------------------------------------------
# Transaction Tracer(遅いトランザクションの詳細情報を収集)
# ---------------------------------------------------------------------------
transaction_tracer.enabled = true
transaction_tracer.transaction_threshold = apdex_f
transaction_tracer.record_sql = obfuscated
transaction_tracer.stack_trace_threshold = 0.5
transaction_tracer.explain_enabled = true
transaction_tracer.explain_threshold = 0.5

# ---------------------------------------------------------------------------
# Error Collector(エラー情報の収集)
# ---------------------------------------------------------------------------
error_collector.enabled = true
# 特定のエラーを無視する場合(スペース区切りで指定)
# error_collector.ignore_classes = module:ExceptionClass
# 想定内のエラーとしてマークする場合
# error_collector.expected_classes = module:ExceptionClass

# ---------------------------------------------------------------------------
# Browser Monitoring(Real User Monitoring)
# ---------------------------------------------------------------------------
browser_monitoring.auto_instrument = true

# ---------------------------------------------------------------------------
# Thread Profiler
# ---------------------------------------------------------------------------
thread_profiler.enabled = true

# ---------------------------------------------------------------------------
# Distributed Tracing(分散トレーシング)
# ---------------------------------------------------------------------------
distributed_tracing.enabled = true

# ---------------------------------------------------------------------------
# Application Logging(Logs in Context)
# ---------------------------------------------------------------------------
# application_logging.enabled = true
# application_logging.forwarding.enabled = true
# application_logging.local_decorating.enabled = true
# application_logging.metrics.enabled = true

設定のポイント

各セクションの代表的な設定項目について補足します。 New Relic公式ドキュメントも合わせて確認ください

docs.newrelic.com

基本設定

設定項目 説明
license_key New Relicのライセンスキー。
app_name New Relic UIでの表示名。わかりやすい名前を設定しましょう
monitor_mode false にするとデータ送信が無効化される。
log_file コンテナ環境では stdout を推奨。CloudWatch Logsで確認可能
log_level 通常は info。トラブル時は debug に変更して詳細ログを確認
high_security true にするとリクエストパラメータ収集やSQL raw送信が制限される

Transaction Tracer

遅いトランザクションの詳細情報を収集する機能です。

設定項目 説明
transaction_tracer.enabled トランザクショントレースの有効/無効
transaction_tracer.transaction_threshold トレース収集の閾値。apdex_f はApdex Tの4倍
transaction_tracer.record_sql obfuscated(難読化)、raw(生SQL)、off(無効)から選択。機密データ保護のため obfuscated 推奨
transaction_tracer.explain_enabled 遅いSQLの実行計画(EXPLAIN)を取得。MySQL/PostgreSQL対応

Error Collector

エラー情報を収集する機能です。

設定項目 説明
error_collector.enabled エラー収集の有効/無効
error_collector.ignore_classes 無視するエラークラス(スペース区切り)。例: werkzeug.exceptions:NotFound
error_collector.expected_classes 想定内エラーとしてマーク。Apdexやエラーレートに影響しない

Distributed Tracing

マイクロサービス間のリクエスト追跡機能です。

設定項目 説明
distributed_tracing.enabled 分散トレーシングの有効/無効。外部API呼び出しがある場合は必須

Application Logging(Logs in Context)

アプリケーションログをNew Relicに転送する機能です。

設定項目 説明
application_logging.enabled ログ機能全体の有効/無効
application_logging.forwarding.enabled ログ転送の有効/無効。トレースとログを紐づけて確認可能
application_logging.local_decorating.enabled ローカルログにトレースIDを付与

注意: すでにFluentdやCloudWatch Logsなどでログ基盤を構築している場合、APMエージェントからもログを送ると「全く同じログデータに対して二重にコストが発生」することになります。その場合は application_logging.forwarding.enabled = false にして、コストとリソースを節約しましょう。

APM設定ファイルのチューニングについては以下ブログも参考にしていただければと思います。

blog.serverworks.co.jp

Create Application container 画面での操作

Dockerfileの修正

Guided Install画面の「Create the base container (New Relic)」および「① Create a container for your app」「② Run the container」に該当する部分です。

Guided Installで紹介されている構成(参考)

Guided Install画面では、New Relic用のベースコンテナとアプリケーションコンテナを分けて作成する構成が紹介されています。

ベースコンテナ(newrelic/Dockerfile)

FROM python:3.9.14-alpine3.16
RUN pip install --no-cache-dir newrelic
ENTRYPOINT ["newrelic-admin", "run-program"]

アプリケーションコンテナ(src/Dockerfile)

FROM python_newrelic:latest
# ... アプリケーションのセットアップ
CMD ["python3", "app.py"]

また、docker run 時に環境変数でライセンスキーとアプリ名を渡す方法も紹介されています。

docker run \
  -e NEW_RELIC_LICENSE_KEY=YOUR_LICENSE_KEY \
  -e NEW_RELIC_APP_NAME="Your-App-Name" \
  -p 8000:8000 -it --rm --name CONTAINER-NAME my_python_api:latest

今回の構成

今回は、シンプルに 1つのDockerfileで完結する構成 にしました。また、環境変数ではなく newrelic.ini を使用する方法を使用しています。

ポイントは、Gunicorn起動コマンドを newrelic-admin run-program でラップすることです。

変更前(APM導入前)

CMD ["gunicorn", "--bind", "0.0.0.0:5001", "--workers", "2", "app:app"]

変更後(APM導入後)

ENV NEW_RELIC_CONFIG_FILE=/app/newrelic.ini
CMD ["newrelic-admin", "run-program", "gunicorn", "--bind", "0.0.0.0:5001", "--workers", "2", "app:app"]

newrelic-admin run-program は、指定したプログラム(この場合はGunicorn)を起動する際に、自動的にNew Relicエージェントを組み込んでくれます。アプリケーションコードを一切変更せずにAPMを導入できるのが大きなメリットです。

今回のDockerfile全体

FROM python:3.11-slim

WORKDIR /app

# 依存関係インストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションコピー
COPY src/ ./

# ポート公開
EXPOSE 5001

# 非rootユーザーで実行
RUN useradd -m -u 1000 appuser
USER appuser

# New Relic設定
ENV NEW_RELIC_CONFIG_FILE=/app/newrelic.ini

# New Relic Agentでアプリケーションを起動
CMD ["newrelic-admin", "run-program", "gunicorn", "--bind", "0.0.0.0:5001", "--workers", "2", "app:app"]

Guided Install以外の追加設定(APM導入し、アプリケーション情報をNew Relicに送った後の作業)

ここからはGuided Installには含まれていない、追加で設定しておきたい内容です。

Change Trackingの設定

APMを導入したら、ぜひ一緒に設定しておきたいのが「Change Tracking(デプロイマーカー)」です。

Change Trackingを設定すると、「いつデプロイしたか」がNew RelicのUI上に表示されるようになります。これにより、パフォーマンスの変化とデプロイの相関が可視化され、「あれ、なんかパフォーマンスが悪化してるな...あ、さっきのデプロイが原因か」といった切り分けが格段に楽になります。

docs.newrelic.com

GitHub Actionsでの設定

今回のアプリケーションはGitHub Actionを用いて自動デプロイを実装しておりますのでGithub Actionが動いたタイミングで デプロイマーカを記録してもらうよう設定しました。

Github Actionのデプロイ設定ファイルに以下を追加します。

- name: New Relic Change Tracking Marker
  uses: newrelic/deployment-marker-action@v2.3.0
  with:
    apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
    guid: ${{ secrets.NEW_RELIC_DEPLOYMENT_ENTITY_GUID }}
    version: "${{ github.sha }}"
    user: "${{ github.actor }}"

必要なSecrets

GitHub リポジトリの Settings > Secrets and variables > Actions で以下を設定します。

Secret名 説明 取得方法
NEW_RELIC_API_KEY User API Key New Relic UI > API Keys > User Key
NEW_RELIC_DEPLOYMENT_ENTITY_GUID アプリケーションのGUID APM > アプリ選択 > Metadata

動作確認

Guided Install画面では、docker run 後に New Relic UI でデータが表示されることを確認する「Test the connection」のステップがあります。

デプロイが完了したら、以下のポイントを確認します。

1. コンテナログの確認

ECSのログ(CloudWatch Logs)で以下のようなメッセージが表示されていれば、エージェントは正常に起動しています。

New Relic Python Agent (11.3.0)

2. New Relic UIでの確認

  • APM & Services にアプリケーションが表示される
  • Transactions タブにデータが表示される
  • Agent version が想定通りのバージョンになっている

ちなみにGitHubレポジトリもリンク付けできます。

3. Change Trackingの確認(Change Trackingの設定した場合のみ)

  • デプロイマーカーが表示される

デプロイ前後のパフォーマンス情報を把握可能

ハマったポイント

導入時にハマったポイントをいくつか共有します。

Agent Versionが古いまま

Agent Versionを最新のものに変更しようとDockerイメージをビルドし直しても、Agentのバージョンが古いままということがありました。 調べていくとDockerのキャッシュが原因なのでと思い一時的に--no-cache 追加したら正常にバージョン更新されました。

docker build --no-cache -t your-app .

GitHub ActionsでもDockerレイヤーキャッシュを使っている場合は、一時的に --no-cache を追加してみてください。私はこれで30分ほど悩みました...。

APMにデータが表示されない

確認ポイントをまとめておきます。

  1. license_key が正しいか
  2. monitor_mode = true になっているか
  3. NEW_RELIC_CONFIG_FILE 環境変数が正しいパスを指しているか
  4. コンテナログにNew Relic Agentの起動メッセージがあるか

デバッグ時は log_level = debug に変更して詳細ログを確認すると原因を特定しやすくなります。

設定の優先順位

Python Agent は newrelic.ini よりも 環境変数(NEW_RELIC_...)の設定が優先されます。iniファイルを書き換えても反映されない場合は、環境変数側で上書きされていないかを確認する必要があります。

まとめ

今回の内容をまとめます。

  • requirements.txtnewrelic パッケージを追加
  • newrelic.ini 設定ファイルを作成し、Dockerイメージに含める
  • Dockerfileで newrelic-admin run-program を使用してアプリケーションを起動
  • GitHub ActionsでChange Trackingを設定してデプロイを可視化

APM導入自体は、そこまで難しくありません。newrelic-admin run-program でラップするというポイントさえ押さえれば、アプリケーションコードを変更せずに導入できます。

導入後は、Transactionsやエラー情報、分散トレーシングなど、New Relicを活用してアプリケーションのパフォーマンス改善に役立ててみてください。

宣伝

弊社では、お客様環境のオブザーバビリティを加速するためのNew Relicアカウント開設を含めた伴走型のNew Relic導入支援サービスをご提供しております。もしご興味をお持ちの方は、こちらのNew Relic導入支援サービスのページよりお問合せ頂けましたら幸いでございます。

・福田 圭(記事一覧)

・マネージドサービス部 所属
・X(Twitter):@soundsoon25

2023 New Relic Partner Trailblazer。New Relic Trailblazer of the Year 2025受賞。New Relic User Group運営。