このページでは、コンテナ化された環境に Java エージェントをインストールする方法について説明します。オプションについては、「コンテナのインストールオプション」を参照してください。コンテナを使用して Java エージェントをインストールする場合、次の 3 つのオプションがあります。

自動インストゥルメンテーションを使用する

このシナリオは、クラスタエージェントがインストールされている Kubernetes で実行されているコンテナに適用されます。

このオプションでは、クラスタエージェントの自動インストゥルメンテーション機能を使用します。これは、最高の自動化レベルと最もシンプルな操作エクスペリエンスを提供することから、Kubernetes クラスタで Java アプリケーションをインストゥルメント化する場合に推奨されるオプションです。

開始するには、「クラスタエージェントを使用したアプリケーションの自動インストゥルメンテーション」を参照してください。

Init コンテナを使用する

このシナリオは、Kubernetes で実行されているコンテナに適用されます。

このオプションでは、Kubernetes init コンテナを使用してエージェントバイナリをアプリケーションコンテナにコピーします。これは、自動インストゥルメンテーションが利用できない場合に推奨されるオプションです。このユースケースでは、次の 2 つのコンテナがあることを前提としています。

  • アプリケーションイメージが Java エージェントバイナリなしで作成されている。
  • Java エージェントバイナリのみを含む 2 つ目の init コンテナイメージが作成されている。

アプリケーションの導入仕様が構成され、実行中のアプリケーションコンテナにエージェントバイナリをコピーします。init コンテナを使用してエージェントバイナリをコピーするには、次の手順を実行します。

  1. Java アプリケーションイメージの作成
  2. Java エージェント Init コンテナイメージの作成
  3. エージェント出力の Stdout へのリダイレクト
  4. 導入仕様への Init コンテナの追加
  5. Java エージェント環境変数の設定
  6. 導入仕様への -javaagent 引数の追加
  7. (OpenShift のみ)APPDYNAMICS_AGENT_UNIQUE_HOST_ID 環境変数の設定
  8. (オンプレミスコントローラのみ)コンテナへのコントローラ証明書のコピー

Java アプリケーションイメージの作成

Java アプリケーションイメージを作成する場合は、Java エージェントバイナリを含めないでください。

Java エージェント Init コンテナイメージの作成

Java エージェントイメージは、アプリケーションイメージとは別に作成され、複数の Java アプリケーションの導入時に再利用できます。この Dockerfile は、マルチステージビルドを使用して Java エージェントの init コンテナイメージを作成している例です。または、init コンテナで Docker HubSplunk AppDynamics から事前に作成されたイメージを参照できます。

エージェント出力の Stdout へのリダイレクト

エージェント出力を、コンテナ化された環境の stdout にリダイレクトすることがベストプラクティスです。独自の Java エージェント init コンテナイメージを作成する場合は、ダウンロードパッケージで提供される ver<version>/conf/logging/log4j2.xml ファイルを更新することで、Java エージェントの出力を stdout にリダイレクトできます。例の log4j2.xml ファイルに示すように、2 つの <AppenderRef ref="Console"/>  要素を追加します。Docker ハブSplunk AppDynamics で事前に作成されたイメージを使用する場合は、ConfigMap を使用し、例となる log4j2.xml ファイルに基づいてデフォルトの ver<version>/conf/logging/log4j2.xml ファイルを置き換えることができます。「コンテナへのコントローラ証明書のコピー」と同じ手順に従います。

導入仕様への Init コンテナの追加

導入仕様を編集して必要なセクションを追加し、エージェントバイナリを init コンテナからアプリケーションイメージにコピーできるようにします。

導入仕様の次のスニペットは、必須の volumesvolumeMounts、および initContainer の定義を示しています。このコード例では、Java アプリケーションイメージが myrepo/java-app:v1 にパブリッシュされ、init コンテナイメージが事前に構築されたイメージ(docker.io/appdynamics/java-agent:20.6.0)を使用することを前提としています。

kind: Deployment
spec:
  containers:
  - name: java-app
    image: myrepo/java-app:v1
    volumeMounts:
    - mountPath: /opt/appdynamics
      name: appd-agent-repo
  initContainers:
  - command:
    - cp
    - -r
    - /opt/appdynamics/.
    - /opt/temp
    name: appd-agent
	image: docker.io/appdynamics/java-agent:20.8.0
    volumeMounts:
    - mountPath: /opt/temp
      name: appd-agent-repo
  volumes:
    - name: appd-agent-repo
      emptyDir: {}
YML

Java エージェント環境変数の設定

必要な Java エージェント環境変数をすべて設定するには、「Kubernetes でエージェントを設定するためのベストプラクティス」で説明されている次の手順を実行する必要があります。

ConfigMap を使用したアプリケーション サーバ エージェントの設定

  1. ConfigMap を使用して、名前空間内のアプリケーション間で共有する Java エージェント環境変数を設定します。

    apiVersion: v1
    data:
      APPDYNAMICS_AGENT_APPLICATION_NAME: "eCommerce"
      APPDYNAMICS_AGENT_ACCOUNT_NAME: "<value>"
      APPDYNAMICS_CONTROLLER_HOST_NAME: "<value>"
      APPDYNAMICS_CONTROLLER_PORT: "<value>"
      APPDYNAMICS_CONTROLLER_SSL_ENABLED: "<value>"
      APPDYNAMICS_JAVA_AGENT_REUSE_NODE_NAME: "true"
      APPDYNAMICS_JAVA_AGENT_REUSE_NODE_NAME_PREFIX: "<value>"
    kind: ConfigMap
    metadata:
      name: ecommerce-java-config
    YML
  2. 名前空間に ConfigMap を適用します。

    kubectl -n ecommerce apply -f ecommerce-java-config.yaml
    BASH
  3. 導入仕様を更新して ConfigMap を参照します。

    spec:
     containers:
     - name: java-app
       envFrom:
       - configMapRef:
           name: ecommerce-java-config
     ...
    YML

コントローラのアクセスキーへの秘密の使用

  1. kubectl を使用して秘密を作成します。

    kubectl -n ecommerce create secret generic appd-agent-secret --from-literal=access-key=<access-key>
    BASH
  2. 導入仕様を更新して、秘密を参照します。

    spec:
      containers:
      - name: java-app
        env:
        - name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: appd-agent-secret
              key: access-key
    YML

導入仕様でのアプリケーション固有の設定

導入仕様でアプリケーション固有の階層名環境変数(APPDYNAMICS_AGENT_TIER_NAME)を設定します。

spec:
  containers:
  - name: java-app
    env:
    - name: APPDYNAMICS_AGENT_TIER_NAME
      value: ecommerce-service
YML

導入仕様への -javaagent 引数の追加

導入仕様を編集して、次の例に示すように、アプリケーションコンテナのスタートアップコマンドに -javaagent 引数を追加します。

spec:
  containers:
    command: ["/bin/sh"]
    args: ["-c", "java -javaagent:/opt/appdynamics/javaagent.jar -jar /myapp.jar"]
YML

Spring Boot など一部の Java フレームワークでは、標準的な JAVA_TOOL_OPTIONS 環境変数を利用して -javaagent 引数を含めることができます。

(OpenShift のみ)APPDYNAMICS_AGENT_UNIQUE_HOST_ID 環境変数の設定

OpenShift で実行する Java アプリケーションの場合は、APPDYNAMICS_AGENT_UNIQUE_HOST_ID 環境変数を設定して、クラスタエージェントとの APM 相関を有効にします。APPDYNAMICS_AGENT_UNIQUE_HOST_ID 値はランタイム値に依存するため、コンテナのスタートアップコマンドでこの環境変数を設定します。 

たとえば、OpenShift 3.10 または 3.11 環境の場合は、次のように環境変数を設定します。

spec:
  containers:
    command: ["/bin/sh"]
    args: ["-c", "APPDYNAMICS_AGENT_UNIQUE_HOST_ID=$(sed -rn '1s#.*/##; 1s/docker-(.{12}).*/\\1/p' /proc/self/cgroup) && java -javaagent:/opt/appdynamics/javaagent.jar -jar /myapp.jar"]
YML

ユースケースについては、「アプリケーション エージェントを手動で設定してクラスタエージェントと関連付ける」に記載されている値を参照してください。 

(オンプレミスコントローラのみ)コンテナへのコントローラ証明書のコピー

オンプレミスのコントローラ証明書が必要な場合は、ConfigMap を定義して cert ファイルを参照し、導入仕様で volume mount を使用して ConfigMap の内容をコンテナにマウントします。

$ kubectl create configmap appd-cert --from-file=cacerts.jks
BASH

この例では、導入仕様のスニペットに示すように、volumes および volumeMounts を使用して証明書ファイル( appd-cert)をコンテナファイルシステムに追加します。

kind: Deployment
spec:
  containers:
    image: myrepo/java-app:v1
    volumeMounts:
    - name: appd-cert
      subPath: cacerts.jks 
      mountPath: /opt/appdynamics/ver4.5.11.26665/conf/cacerts.jks
  volumes:
    - name: appd-cert
      configMap:
        name: appd-cert
YML

Init コンテナを使用するための設定例

init コンテナを使用してエージェントバイナリをコピーする導入仕様の完全な例は、Github(java-app.yaml)にあります。

Dockerfile の使用

このシナリオは、Docker および Kubernetes で実行されているコンテナに適用されます。

このオプションでは、Dockerfile を使用して、作成時に Java エージェントを Docker イメージにコピーします。オプションを使用するには、アプリケーションと Java エージェントの両方のバイナリが含まれた単一のイメージを作成します。

Docker イメージの作成時にエージェントをアプリケーションイメージにコピーするには、次の手順を実行します。

  1. Java エージェントのダウンロードと解凍
  2. エージェント出力の Stdout へのリダイレクト
  3. イメージへのエージェントバイナリのコピー
  4. Java エージェント環境変数の設定
  5. -javaagent 引数のスタートアップコマンドへの追加
  6. (OpenShift のみ)APPDYNAMICS_AGENT_UNIQUE_HOST_ID 環境変数の設定
  7. (オンプレミスコントローラのみ)コントローラ証明書のイメージへのコピー

Java エージェントのダウンロードと解凍

AppDynamics ダウンロードセンターから Java エージェントをダウンロードするか、またはプログラムでエージェントをダウンロードします。エージェントは zip ファイルとしてパッケージ化されます。シェルで、AppServer エージェントを AppServerAgent ディレクトリに解凍します。

$ unzip AppServerAgent-<version>.zip  -d AppServerAgent
BASH

エージェント出力の Stdout へのリダイレクト

エージェント出力を、コンテナ化された環境の stdout にリダイレクトすることがベストプラクティスです。Java エージェントの出力を stdout にリダイレクトするには、ver<version>/conf/logging/log4j2.xml ファイルを編集し、log4j2.xml ファイルの例に示すように 2 つの <AppenderRef ref="Console"/>  要素を追加します。

イメージへのエージェントバイナリのコピー

Dockerfile を編集して、パッケージ化されていないエージェントバイナリをターゲットフォルダにコピーします。

COPY AppServerAgent/ /opt/appdynamics/
BASH

Java エージェント環境変数の設定

非 Kubernetes 環境でアプリケーションを実行している場合(たとえば docker run  を使用)、Dockerfile でエージェント環境変数を設定します。次に例を示します。

ENV APPDYNAMICS_AGENT_APPLICATION_NAME=<value>
ENV APPDYNAMICS_AGENT_TIER_NAME=<value>
ENV APPDYNAMICS_AGENT_ACCOUNT_NAME=<value>
ENV APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY=<value>
ENV APPDYNAMICS_CONTROLLER_HOST_NAME=<value>
ENV APPDYNAMICS_CONTROLLER_PORT=<value>
ENV APPDYNAMICS_CONTROLLER_SSL_ENABLED=<value>
ENV APPDYNAMICS_JAVA_AGENT_REUSE_NODE_NAME=true
ENV APPDYNAMICS_JAVA_AGENT_REUSE_NODE_NAME_PREFIX=<value>
YML

Kubernetes アプリケーションの場合は、これらの環境変数を Dockerfile から除外し、「Kubernetes でエージェントを設定するためのベストプラクティス」の説明に従って ConfigMaps と秘密を使用して設定します。 

再利用ノード名とプレフィックス環境変数は、同じアプリケーションイメージの複数のコンテナインスタンスに一意の名前を付けることをサポートするために必要です。「ノード名を再利用」を参照してください。

-javaagent 引数のスタートアップコマンドへの追加

Dockerfile を編集し、エージェントのバイナリがコピーされた場所に基づいて image start コマンドに -javaagent 引数を含めます。次に例を示します。

ENV JAVA_OPTS -javaagent:/opt/appdynamics/javaagent.jar
CMD ["java", "$JAVA_OPTS", "-jar", "/myapp.jar"]
BASH

一部の Java フレームワーク(Spring Boot など)では、既存の JAVA_TOOL_OPTIONS 環境変数を利用して -javaagent 引数を含めることができます。

(OpenShift のみ)APPDYNAMICS_AGENT_UNIQUE_HOST_ID 環境変数の設定

OpenShift で実行する Java アプリケーションの場合は、APPDYNAMICS_AGENT_UNIQUE_HOST_ID 環境変数を設定して、クラスタエージェントとの APM 相関を有効にします。この値はランタイム値に依存するため、アプリケーション エージェントを手動で設定してクラスタエージェントと関連付ける」に記載されている値を使用してイメージ スタートアップ スクリプトでこの環境変数を設定します。たとえば、OpenShift 3.10 または 3.11 環境では、次のスタートアップスクリプト(startup.sh)を Docker イメージに追加します。

#!/bin/bash
# OpenShift 3.10 or 3.11:
APPDYNAMICS_AGENT_UNIQUE_HOST_ID=$(sed -rn '1s#.*/##; 1s/docker-(.{12}).*/\\1/p' /proc/self/cgroup)
exec java $JAVA_OPTS -jar /myapp.jar
BASH

また、Dockerfile のスタートアップコマンドを更新して次を参照します。

CMD ["/startup.sh"]
BASH

(オンプレミスコントローラのみ)コントローラ証明書のイメージへのコピー

オンプレミスのコントローラと通信する Java エージェントの場合は、Dockerfile を編集して、オンプレミスの証明書を含む証明書ファイルをエージェントの conf フォルダにコピーします。 {{2}}は特定の属性を識別し、 {{3}} はこの属性に割り当てる新規の値を指定します。

COPY ./onprem-cacerts.jks /opt/appdynamics/ver4.5.11.26665/conf/cacerts.jks
BASH

詳細については、Javaエージェント用SSLの有効化を参照してください。 

Dockerfile を使用するための設定例

この Dockerfile は、アプリケーションとエージェントの両方のバイナリが含まれる単一のイメージを作成し、この Kubernetes 導入仕様はその Docker イメージを参照します。この Dockerfile はマルチステージビルドを使用してエージェントをダウンロードし、解凍します。

Log4j 構成ファイルの例

次は、Java エージェントログを stdout にリダイレクトする、更新された ver<version>/conf/logging/log4j2.xml 構成ファイルです。<AppenderRef ref="Console"/> が Root 要素に追加されます。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO" monitorInterval="2">
   <Appenders>
      <Console name="Console" target="SYSTEM_OUT">
         <PatternLayout pattern="[%t] %d{ABSOLUTE} %5p %c{1} - %m%n" />
      </Console>
      <ADRRAFAppender name="DefaultAppender" fileName="agent.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p %c{1} - %m%n" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
         <RegexFilter regex=".*REST.*" onMatch="DENY" onMismatch="ACCEPT" />
      </ADRRAFAppender>
      <ADRRAFAppender name="BCTAppender" fileName="ByteCodeTransformer.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p - %m%n" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
      </ADRRAFAppender>
      <ADRRAFAppender name="RESTAppender" fileName="REST.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p %c{1} - %m%n" />
         <RegexFilter regex=".*REST.*" onMatch="ACCEPT" onMismatch="DENY" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
      </ADRRAFAppender>
      <ADRRAFAppender name="DynamicServiceAppender" fileName="dynamic-service.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p %c - %m%n" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
      </ADRRAFAppender>
      <ADRRAFAppender name="BusinessTransactionsLogger" fileName="BusinessTransactions.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p - %m%n" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
      </ADRRAFAppender>
      <ADRRAFAppender name="DataPipelineAppender" fileName="data-pipeline.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p %c - %m%n" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
      </ADRRAFAppender>
      <ADRRAFAppender name="APIAppender" fileName="api.log">
         <PatternLayout pattern="[%t] %d{DATE} %5p %c - %m%n" />
         <SizeBasedTriggeringPolicy size="20 MB" />
         <ADRolloverStrategy max="5" />
      </ADRRAFAppender>
   </Appenders>
   <Loggers>
      <!--  to control the logging level of the agent log files, change "level" attribute. level="all|trace|debug|info|warn|error"-->
      <AsyncLogger name="com.singularity" level="info" additivity="false">
         <AppenderRef ref="DefaultAppender" />
         <AppenderRef ref="RESTAppender" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.BusinessTransactions" level="info" additivity="false">
         <AppenderRef ref="BusinessTransactionsLogger" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.dynamicservice" level="info" additivity="false">
         <AppenderRef ref="DynamicServiceAppender" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.ee.service.datapipeline" level="info" additivity="false">
         <AppenderRef ref="DataPipelineAppender" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.datapipeline" level="info" additivity="false">
         <AppenderRef ref="DataPipelineAppender" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.BCTLogger" level="info" additivity="false">
         <AppenderRef ref="BCTAppender" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.api" level="info" additivity="false">
         <AppenderRef ref="APIAppender" />
      </AsyncLogger>
      <AsyncLogger name="com.singularity.segment.TxnTracer" level="info" additivity="false">
         <AppenderRef ref="DefaultAppender" />
      </AsyncLogger>
      <Root level="error">
         <AppenderRef ref="DefaultAppender" />
         <AppenderRef ref="Console" />
      </Root>
   </Loggers>
</Configuration>
CODE