Configure Embedded Analytics Agent for OpenShift and Connect Java Workloads

Use this procedure to deploy the Machine Agent Analytics image on OpenShift, expose the embedded Analytics Agent as a shared in-cluster service, and configure Java workloads to send Business Transaction Analytics data through the node-local agent.

The Machine Agent Analytics image contains both the Machine Agent and the embedded Analytics Agent. The Analytics Agent starts automatically with the Machine Agent when you deploy the image directly from an authorized container registry.

Deploy Machine Agent Analytics Image on OpenShift Using Registry Pull

Prerequisites

  • A supported Splunk AppDynamics Operator installed in the target OpenShift namespace.
  • Access to the published Machine Agent Analytics image.
  • Controller hostname, account name, global account name, application or cluster name, and controller access key.
  • Events Service URL associated with the controller account.
  • Permission to create namespace resources and configure the required OpenShift SecurityContextConstraints access.
  • Required Machine Agent, Server Visibility, and Transaction Analytics licenses.
Table 1. Required values
Value Placeholder
Namespace <namespace>
Registry <registry>
Image version <version>
Controller hostname <controller-host-without-protocol>
Controller port <controller_port>
Account name <account-name>
Global account name <global-account-name>
Application or cluster name <application-name>
Events Service URL https://<events-service-host>

Installation Procedure

Warning: On Windows, copying and pasting multiline commands that use a backslash \ for line continuation may introduce CR-LF characters next to the backslash. This can cause unexpected or inconsistent behavior when the command runs. If you use a Windows terminal, review each pasted multiline command and remove any hidden line-ending characters before running it.
  1. Create a namespace for appdynamics.

    SHELL
    kubectl create namespace appdynamics
  2. Install Splunk AppDynamics Operator.

    1. Go to your OpenShift Cluster Console.
    2. Go to Operators > OperatorHub.
    3. Search for appdynamics.
    4. Click Install.
  3. Create the image pull secret.

    Set the registry credentials in the terminal without placing their values in this file:

    SHELL
    read -r -p "Registry username: " REGISTRY_USERNAME
    read -r -s -p "Registry token: " REGISTRY_TOKEN
    echo
    
    oc create secret docker-registry machine-agent-registry-secret \
      --docker-server=<registry> \
      --docker-username="$REGISTRY_USERNAME" \
      --docker-password="$REGISTRY_TOKEN" \
      -n <namespace>
    
    unset REGISTRY_USERNAME REGISTRY_TOKEN

    Verify the resource:

    SHELL
    oc get secret machine-agent-registry-secret -n <namespace>
    Note: If registry access is already included in the cluster-wide OpenShift pull configuration, a namespace-level pull secret might not be required.
  4. Create the controller access Secret.

    Create appdynamics-infraviz-secret with a key named controller-key:

    SHELL
    read -r -s -p "Controller access key: " CONTROLLER_ACCESS_KEY
    
    oc create secret generic appdynamics-infraviz-secret \
      --from-literal=controller-key="$CONTROLLER_ACCESS_KEY" \
      -n <namespace>
    
    unset CONTROLLER_ACCESS_KEY
    CAUTION: Do not put the access key in a ConfigMap, InfraViz YAML, shell history, or application logs.
  5. Create the environment ConfigMap.

    Create analytics-agent-config.yaml:

    YAML
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: analytics-agent-config
      namespace: <namespace>
    data:
      APPDYNAMICS_CONTROLLER_HOST_NAME: "<controller-host-without-protocol>"
      APPDYNAMICS_CONTROLLER_PORT: "<controller_port>"
      APPDYNAMICS_CONTROLLER_SSL_ENABLED: "true"
      APPDYNAMICS_AGENT_ACCOUNT_NAME: "<account-name>"
      APPDYNAMICS_AGENT_GLOBAL_ACCOUNT_NAME: "<global-account-name>"
      APPDYNAMICS_AGENT_APPLICATION_NAME: "<application-name>"
      EVENT_ENDPOINT: "https://<events-service-host>"

    Apply it:

    SHELL
    oc apply -f analytics-agent-config.yaml
  6. Verify the InfraViz ServiceAccount and SCC.

    The Operator bundle might create the ServiceAccount automatically:

    SHELL
    oc get serviceaccount appdynamics-infraviz -n <namespace>

    If it is missing:

    SHELL
    oc create serviceaccount appdynamics-infraviz -n <namespace>

    Grant the SCC required by the privileged MA DaemonSet:

    SHELL
    oc adm policy add-scc-to-user privileged \
      -z appdynamics-infraviz \
      -n <namespace>
  7. Create the InfraViz resource.

    Create infraviz.yaml:

    YAML
    apiVersion: cluster.appdynamics.com/v1alpha1
    kind: InfraViz
    metadata:
      name: appdynamics-infraviz
      namespace: <namespace>
    spec:
      controllerUrl: "<controller-host-with-protocol>"
      account: "<account-name>"
      globalAccount: "<global-account-name>"
      accessSecret: appdynamics-infraviz-secret
      appName: "<application-name>"
      eventServiceUrl: "https://<events-service-host>"
    
      image: "<registry>/appdynamics/machine-agent-analytics:<version>"
      imagePullPolicy: Always
      imagePullSecret: machine-agent-registry-secret
    
      enableContainerHostId: true
      enableServerViz: true
    
      env:
        - name: APPDYNAMICS_CONTROLLER_HOST_NAME
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: APPDYNAMICS_CONTROLLER_HOST_NAME
    
        - name: APPDYNAMICS_CONTROLLER_PORT
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: APPDYNAMICS_CONTROLLER_PORT
    
        - name: APPDYNAMICS_CONTROLLER_SSL_ENABLED
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: APPDYNAMICS_CONTROLLER_SSL_ENABLED
    
        - name: APPDYNAMICS_AGENT_ACCOUNT_NAME
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: APPDYNAMICS_AGENT_ACCOUNT_NAME
    
        - name: APPDYNAMICS_AGENT_GLOBAL_ACCOUNT_NAME
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: APPDYNAMICS_AGENT_GLOBAL_ACCOUNT_NAME
    
        - name: APPDYNAMICS_AGENT_APPLICATION_NAME
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: APPDYNAMICS_AGENT_APPLICATION_NAME
    
        - name: EVENT_ENDPOINT
          valueFrom:
            configMapKeyRef:
              name: analytics-agent-config
              key: EVENT_ENDPOINT
    
        - name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: appdynamics-infraviz-secret
              key: controller-key
    
        - name: APPDYNAMICS_AGENT_DEFAULT_ACCOUNT_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: appdynamics-infraviz-secret
              key: controller-key
    
        - name: APPDYNAMICS_AGENT_UNIQUE_HOST_ID
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
    
      resources:
        requests:
          cpu: 200m
          memory: 800Mi
        limits:
          cpu: 500m
          memory: 1Gi
    CAUTION: Do not add port 9090 under spec.ports. The Operator already configures the Analytics/BIQ port. Adding it again can produce a duplicate host-port error.
  8. Deploy Infraviz in the cluster.

    SHELL
    oc apply -f infraviz.yaml
    oc rollout status daemonset/appdynamics-infraviz -n <namespace> --timeout=5m
  9. Validate the deployment.

    Confirm the pods are running:

    SHELL
    oc get pods -n <namespace> -l infraViz_cr=appdynamics-infraviz -o wide

    Confirm the image and digest:

    SHELL
    oc get pods -n <namespace> \
      -l infraViz_cr=appdynamics-infraviz \
      -o 'custom-columns=NAME:.metadata.name,IMAGE:.spec.containers[0].image,IMAGE_ID:.status.containerStatuses[0].imageID'

    Select one pod:

    SHELL
    POD=$(oc get pod -n <namespace> \
      -l infraViz_cr=appdynamics-infraviz \
      -o jsonpath='{.items[0].metadata.name}')

    Verify Machine Agent registration without displaying credential values:

    SHELL
    oc exec "$POD" -n <namespace> -- sh -c \
      'grep -E "registration response|Registered|401|ERROR|WARN" /opt/appdynamics/logs/machine-agent.log | tail -n 160'

    Verify that Analytics Agent is enabled:

    SHELL
    oc exec "$POD" -n <namespace> -- \
      grep "<enabled>" /opt/appdynamics/monitors/analytics-agent/monitor.xml

    Expected:

    XML
    <enabled>true</enabled>

    Verify the Analytics Agent transaction sink:

    SHELL
    oc exec "$POD" -n <namespace> -- \
      curl -sS -o /dev/null -w 'HTTP %{http_code}' \
      http://127.0.0.1:9090/v1/sinks/bt
    Note: Expected result: HTTP 405 for GET. The sink accepts POST requests; HTTP 405 confirms that Analytics Agent is listening and reachable.

Expose the shared Analytics Agent service

  1. Create the backend Service.

    Create a ClusterIP Service in the Machine Agent namespace. The selector must match the infraViz_cr label on the ready Machine Agent pods.

    Create appdynamics-analytics-agent-service.yaml:

    YAML
    apiVersion: v1
    kind: Service
    metadata:
      name: appdynamics-analytics-agent
      namespace: <machine-agent-namespace>
    spec:
      type: ClusterIP
      internalTrafficPolicy: Local
      selector:
        infraViz_cr: <infraviz-resource-name>
      ports:
        - name: analytics
          protocol: TCP
          port: 9090
          targetPort: 9090

    Apply the manifest:

    SHELL
    oc apply -f appdynamics-analytics-agent-service.yaml
    Note:

    Routing behavior

    internalTrafficPolicy: Local routes each workload to the embedded Analytics Agent on the same worker node. Use this setting when InfraViz pods use host networking and cross-node access to node IP endpoints is unreliable. Before you rely on local routing, ensure that every eligible workload node has a ready InfraViz pod with a healthy embedded Analytics Agent.
  2. Confirm every expected Analytics Agent endpoint is ready.

    List the InfraViz or Machine Agent pods and the EndpointSlices for the backend Service:

    SHELL
    oc get pods -n "$NAMESPACE" \
      -l infraViz_cr="$INFRAVIZ_NAME" -o wide
    
    oc get endpointslice -n "$NAMESPACE" \
      -l kubernetes.io/service-name=appdynamics-analytics-agent -o wide

    The number of ready Service endpoints must match the number of ready InfraViz or Machine Agent pods on worker nodes that will host monitored workloads.

    CAUTION: Do not deploy or reconfigure application workloads until all expected backend endpoints are ready.
  3. Create the application namespace proxy Service.

    Create an ExternalName Service in each application namespace. This gives workloads a stable namespace-local name for the shared Analytics Agent Service.

    Create analytics-proxy-service.yaml:

    YAML
    apiVersion: v1
    kind: Service
    metadata:
      name: analytics-proxy
      namespace: <application-namespace>
    spec:
      type: ExternalName
      externalName: appdynamics-analytics-agent.<machine-agent-namespace>.svc.cluster.local
      ports:
        - name: analytics
          protocol: TCP
          port: 9090
          targetPort: 9090

    Apply the manifest:

    SHELL
    oc apply -f analytics-proxy-service.yaml

Configure Java workloads

  1. Create the application controller Secret.

    Kubernetes Secrets are namespace-scoped. Create this Secret in the same namespace as the application workload. This Secret is separate from the InfraViz or Machine Agent access Secret in the Machine Agent namespace.

    Run the following commands to create or update application-controller-secret without storing the access key in a YAML file:

    SHELL
    read -r -p "Controller host (without https://): " APPD_CONTROLLER_HOST
    read -r -p "Controller port [443]: " APPD_CONTROLLER_PORT
    APPD_CONTROLLER_PORT="${APPD_CONTROLLER_PORT:-443}"
    read -r -p "Controller account name: " APPD_ACCOUNT_NAME
    read -r -s -p "Controller access key: " APPD_ACCESS_KEY
    echo
    
    oc create secret generic application-controller-secret \
      -n "$APP_NAMESPACE" \
      --from-literal=controller-host="$APPD_CONTROLLER_HOST" \
      --from-literal=controller-port="$APPD_CONTROLLER_PORT" \
      --from-literal=account-name="$APPD_ACCOUNT_NAME" \
      --from-literal=access-key="$APPD_ACCESS_KEY" \
      --dry-run=client -o yaml | oc apply -f -
    
    unset APPD_CONTROLLER_HOST APPD_CONTROLLER_PORT APPD_ACCOUNT_NAME APPD_ACCESS_KEY

    Confirm that the expected keys exist without displaying their values:

    SHELL
    oc get secret application-controller-secret -n "$APP_NAMESPACE" \
      -o go-template='{{range $key, $value := .data}}{{printf "%s\n" $key}}{{end}}'

    Expected keys include:

    PLAINTEXT
    access-key
    account-name
    controller-host
    controller-port
    CAUTION:

    Security

    Do not place real controller access keys in committed YAML, ConfigMaps, or documentation. Use an approved external secret management integration when one is available.
  2. Attach the Java Agent and configure the shared sink.

    The application JVM must attach the AppDynamics Java Agent and explicitly set the shared Analytics Agent sink URL. The APPDYNAMICS_ANALYTICS_HOST and APPDYNAMICS_ANALYTICS_PORT environment variables can help compose the URL, but the Java Agent does not use those variables by itself for this purpose. Set -Dappdynamics.analytics.agent.url explicitly.

    Add configuration similar to the following to the application Deployment:

    YAML
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: <application-deployment>
      namespace: <application-namespace>
    spec:
      template:
        spec:
          containers:
            - name: <application-container>
              image: <instrumented-application-image>
              env:
                - name: APPDYNAMICS_ANALYTICS_HOST
                  value: analytics-proxy
                - name: APPDYNAMICS_ANALYTICS_PORT
                  value: "9090"
                - name: JAVA_OPTS
                  value: >-
                    -javaagent:/opt/appdynamics/javaagent.jar
                    -Dappdynamics.analytics.agent.url=http://$(APPDYNAMICS_ANALYTICS_HOST):$(APPDYNAMICS_ANALYTICS_PORT)/v1/sinks/bt
                - name: APPDYNAMICS_CONTROLLER_HOST_NAME
                  valueFrom:
                    secretKeyRef:
                      name: application-controller-secret
                      key: controller-host
                - name: APPDYNAMICS_CONTROLLER_PORT
                  valueFrom:
                    secretKeyRef:
                      name: application-controller-secret
                      key: controller-port
                - name: APPDYNAMICS_CONTROLLER_SSL_ENABLED
                  value: "true"
                - name: APPDYNAMICS_AGENT_ACCOUNT_NAME
                  valueFrom:
                    secretKeyRef:
                      name: application-controller-secret
                      key: account-name
                - name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
                  valueFrom:
                    secretKeyRef:
                      name: application-controller-secret
                      key: access-key
                - name: APPDYNAMICS_AGENT_APPLICATION_NAME
                  value: <controller-application-name>
                - name: APPDYNAMICS_AGENT_TIER_NAME
                  value: <controller-tier-name>
                - name: APPDYNAMICS_AGENT_NODE_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
    Note:

    Path check

    Replace /opt/appdynamics/javaagent.jar with the actual Java Agent JAR path inside the application image. The -javaagent argument is required for Controller registration and Business Transaction instrumentation.
  3. Verify application reachability to the sink.

    From a running application pod, send a request to the Analytics sink to verify reachability:

    SHELL
    APP_POD=$(oc get pods -n "$APP_NAMESPACE" \
      -l app=<application-label> -o jsonpath='{.items[0].metadata.name}')
    
    oc exec -n "$APP_NAMESPACE" "$APP_POD" -- \
      curl -sS -o /dev/null -w '%{http_code}\n' \
      http://analytics-proxy:9090/v1/sinks/bt
    Note: Expected result: 405. The sink accepts only POST requests. An HTTP 405 response confirms DNS resolution, Service routing, and port reachability.

    After the workload registers with the Controller, enable Transaction Analytics for the application and the required Business Transactions, generate traffic, and verify Analytics Agent receive and publish activity.

Troubleshooting

Symptom Action
ImagePullBackOff Verify the image path, tag, registry authorization, and imagePullSecret. Do not rely on a node-cached image for customer deployment.
Missing appdynamics-infraviz ServiceAccount Create the ServiceAccount and grant the required SCC.
Duplicate host port 9090 Remove the explicit 9090 entry from spec.ports.
Machine Agent registration returns 401 Verify the account name, global account name, controller access key, and Secret reference. Restart the DaemonSet after updating the Secret.
Analytics Agent port 9090 is not listening Confirm Machine Agent registration succeeded, verify <enabled>true</enabled>, and inspect Machine Agent and Analytics Agent logs.
Existing pods do not receive an updated Secret Restart daemonset/appdynamics-infraviz after the Secret update.

Rollback

Run rollback commands only for resources created by this procedure:

SHELL
oc delete infraviz appdynamics-infraviz -n <namespace>
oc adm policy remove-scc-from-user privileged -z appdynamics-infraviz -n <namespace>
oc delete serviceaccount appdynamics-infraviz -n <namespace>
oc delete configmap analytics-agent-config -n <namespace>
oc delete secret appdynamics-infraviz-secret -n <namespace>
oc delete secret machine-agent-registry-secret -n <namespace>
CAUTION: Do not delete a shared Operator, Secret, ServiceAccount, or ConfigMap used by other AppDynamics components.