APM

コンテナ環境におけるPHPエージェントの構成パターン

公開済み Updated 所要時間:約 7分

PHPエージェントの特徴

PHP環境でNew Relic APMを利用する場合、APMエージェントとデーモンプロセスをインストールします。これは、一般的にPHPではApache / NginxなどのWebサーバー上に複数のphpアプリケーションが稼働しているケースがあり、それぞれのPHPアプリケーション内でAPMエージェントが収集したデータをNew Relicへ送信する部分を効率化するためです。

1台のサーバー上にvirtualhostを設定したり別々のプロセスを起動し、複数のアプリケーションを稼働させるケースがあるため、デーモンプロセスはサーバーに1つにするよう工夫されている

この構成については、Webサーバー上に初めてPHPのAPMエージェントをインストールする際、そのサーバー上にデーモンプロセスがインストールされていない場合は自動的にインストールされるため、ご利用の皆様があまり意識する必要がありませんでした。しかし、昨今アプリケーションがコンテナ化され各phpアプリケーションが別々のコンテナに分散して起動されるようになると、このデーモンプロセスをどのように構成するかを明確に理解してデプロイする必要性が高まってきました。

本Postでは、このような背景を鑑み、コンテナアプリケーションにおけるNew Relic APM on PHP(APMエージェントとデーモンをどのようにデプロイするか)の構成パターンを整理します。コンテナ環境に対するセットアップ手順は公式ドキュメントに記載されていますので、詳細は割愛します。

コンテナ環境におけるエージェント構成パターン

大きく、以下の2パターンに分けることができます。

  1. APMエージェントとデーモンプロセスを同一のコンテナで稼働させる
  2. APMエージェントとデーモンプロセスを別々のコンテナで稼働させる

1. 同一コンテナパターン

まずは、アプリプロセス(APMエージェント)とデーモンプロセスを同一のコンテナで稼働させるパターンです。

前述した通り、New Relic APMのPHPエージェントはデフォルトでデーモンプロセスも同時にインストールされるため、仮想マシンの場合と同じ手順でセットアップするとこちらの構成になります。今までと変わらない手順でセットアップを行うことができるため、手順もシンプルで比較的簡単に利用を開始することができます。

しかしながら、同一コンテナ内にアプリケーションとデーモンプロセスが混在することになるため、デーモンプロセスの負荷を考慮したリソース管理ができません。
(Amazon ECSやKubernetesなどのオーケストレーションサービスは、コンテナ運用における前提(1コンテナ1プロセス)でリソース制御が可能となっているため、1コンテナ内に複数プロセスが起動していた場合にプロセス毎のリソース管理はできない)

また、オートスケールなどによって多くのコンテナが起動する場合や、マイクロサービス化によってPHPアプリケーションが増えた場合、デーモンプロセスが使用するリソースが増え、無駄なリソースを使ってしまうことにつながります。さらには、万が一デーモンプロセスに問題が発生してデータが送信できなくなった場合、デーモンプロセスの再起動などを行う必要になりますが、デーモンプロセスはアプリケーションと同一コンテナ内にいるため再起動するためにはアプリケーションコンテナ全体を再起動する必要があり、サービスに影響を与えることになります。


 

同一コンテナパターン

2. 別コンテナ(デーモン共通化)パターン

これらの課題を解決するのが、デーモンプロセスをアプリケーションコンテナと別々で起動させるパターンです。

New Relicでは、デーモンプロセスコンテナを公開しており、これをアプリケーションコンテナと別で起動することで簡単に分離することができます。
この際、クラスターの内部ロードバランサーを経由することで、デーモン自体のスケールも簡単に実現できます。


 

デーモン外だしパターン

Kubernetesマニフェスト例

例えばKubernetesを利用している場合、アプリケーションPodとは別のDeploymentでデーモンPodを起動し、合わせてClusterIPでServiceを作成することで、アプリケーションコンテナ内のAPMエージェントが収集したデータをデーモンPodに送信するようにします。
具体的なマニフェスト例は以下の通りです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: newrelic-php-daemon
  labels:
    app: newrelic-php-daemon
spec:
  replicas: 1
  selector:
    matchLabels:
      app: newrelic-php-daemon
  template:
    metadata:
      labels:
        app: newrelic-php-daemon
    spec:
      containers:
        - name: newrelic-php-daemon
          image: newrelic/php-daemon
          imagePullPolicy: Always
          ports:
          - containerPort: 31339
          livenessProbe:
            tcpSocket:
              port: 31339
            initialDelaySeconds: 5
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: newrelic-php-daemon-service
spec:
  type: ClusterIP
  selector:
    app: newrelic-php-daemon
  ports:
    - protocol: TCP
      port: 31339
      targetPort: 31339


この時、エージェント側は以下の設定を行います。

  • newrelic.daemon.dont_launch=3
    • エージェント側でデーモンプロセスを起動しないようにする
  • newrelic.daemon.address
    • デーモンのホスト名とポートNo 例)newrelic-php-daemon-service:31339
    • エージェントはここで指定した場所に対してデータを送信しようとする

Option構成. サイドカーパターン

デーモンプロセスをアプリケーションプロセスから分離させるアプローチとして、サイドカー構成も候補としてあり得ます。

少なくともアプリケーションPod内のリソース利用を明確に分離することができるので、デーモンプロセスを別のServiceやDeploymentとしてデプロイすることに何らかの制約がある場合でも、アプリケーションのリソース使用量を明確に管理したい場合はこちらの構成も良いでしょう。

サイドカーパターン

まとめ

各パターンのメリット・デメリットを整理すると以下の通りです。

サマリ

いかがでしょうか?New Relicとしては、デーモンプロセスを共通化することを推奨しておりますが、皆様の状況やスキルセット、組織的な管理体制によって最適なパターンはそれぞれかと思います。

本Postが皆様の最適な構成を検討する参考になれば幸いです。