Deploy the Python Agent in the Application Container

To instrument a Python application, the required Python Agent packages must be deployed to the application container and loaded by the application at startup. The available options are:

  • Use a Dockerfile: This option uses a Dockerfile to deploy the Python Agent in the application Docker image at build time.
  • Use Init Containers: This option uses Kubernetes init containers to deploy the Python Agent into the application container when the application starts up. Using the init containers option does not require any changes to the application Docker image.

For each of these options, the steps assume the use of a sidecar to run the Dynamic Languages Proxy and that you have

Once you have deployed the Python Agent, see Validate the Python Agent Install.

Note: Note that Cluster Agent auto-instrumentation is not supported for Python applications running in Kubernetes clusters where the Cluster Agent is installed. See Container Installation Options.

Use a Dockerfile

Note: This option applies to containers running in Docker and Kubernetes.

This option uses a Dockerfile to deploy the Python Agent in the Docker image at build time. The built Docker image must contain the application and the Python Agent.

To deploy the agent in the application image during the image build:

  1. Copy the Application Files to the Image
  2. Perform the PIP Install
  3. Copy the Controller Certs to the Image (on-premises Controller only)
  4. Use Pyagent to Run the Application
  5. Set the Python Agent Environment Variables
  6. Validate the Python Agent Install

Copy the Application Files to the Image

Edit the Dockerfile to copy the application folder, and set up the requirements and start script:

COPY mypythonapp/ /app/
WORKDIR /app
COPY requirements.txt .
RUN chmod +x ./app.py
EXPOSE 8080

Perform the PIP Install

Run the pip install appdynamics Install the Python Agent. Specify the version of the latest AppDynamics Python project. For example:

RUN pip install -U appdynamics==21.12.2.4693 -r requirements.txt

Copy the Controller Certs to the Image (On-Premises Controller Only)

For Python Agents communicating with an on-premises Controller, edit the Dockerfile to copy the cacerts APPDYNAMICS_CONTROLLER_SSL_CERTFILE

For example:

COPY ./onprem-cacerts /opt/appdynamics/cacerts
ENV APPDYNAMICS_CONTROLLER_SSL_CERTFILE=/opt/appdynamics/cacerts

Use Pyagent to Run the Application

Use pyagent --use-manual-proxy Install the Python Agent for additional support of WSGI frameworks. Include the

CMD pyagent run --use-manual-proxy python ./app.py

A complete Dockerfile Pyagent example:

FROM python:3.7
# Use latest version from https://pypi.org/project/appdynamics/#history
ENV APPD_AGENT_VERSION=21.12.2.4693
COPY mypythonapp/ /app/
WORKDIR /app
RUN chmod +x ./app.py
EXPOSE 8080
RUN pip install -U appdynamics==${APPD_AGENT_VERSION} -r requirements.txt
CMD pyagent run --use-manual-proxy python ./app.py

Set the Python Agent Environment Variables

Note: Note that APPDYNAMICS_TCP_COMM_PORT should be set to an available port in the application and proxy container and is used for the agent to proxy communication. See TCP Mode Configuration.

How you set the Python Agent environment variables depends on how you deploy the image. For a Docker deployment, set the agent environment variables in the Dockerfile, or external file you supply, as a parameter to docker run

ENV APPDYNAMICS_TCP_COMM_PORT=9091
ENV APPDYNAMICS_AGENT_APPLICATION_NAME=<value>
ENV APPDYNAMICS_AGENT_TIER_NAME=<value>
ENV APPDYNAMICS_AGENT_REUSE_NODE_NAME=true
ENV APPDYNAMICS_AGENT_REUSE_NODE_NAME_PREFIX=<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_AGENT_CONTAINER_ENABLED=true

For Kubernetes applications, set these environment variables using configmaps, secrets, and the deployment spec as described in Best Practices to Configure Agents in Kubernetes.

  1. Use a configmap appd-python-config.yaml

    apiVersion: v1
    data:
    APPDYNAMICS_TCP_COMM_PORT: "9091"
    APPDYNAMICS_AGENT_APPLICATION_NAME: "<value>"
    APPDYNAMICS_AGENT_REUSE_NODE_NAME: "<value>"
    APPDYNAMICS_AGENT_ACCOUNT_NAME: "<value>"
    APPDYNAMICS_CONTROLLER_HOST_NAME: "<value>"
    APPDYNAMICS_CONTROLLER_PORT: "<value>"
    APPDYNAMICS_CONTROLLER_SSL_ENABLED: "<value>"
    kind: ConfigMap
    metadata:
    name: appd-python-config
  2. Apply the configmap

    $ kubectl -n <app-ns> apply -f appd-python-config.yaml
  3. Update the deployment spec to reference the configmap

    spec:
    containers:
    - name: python-app
    envFrom:
    - configMapRef:
    name: appd-python-config
    ...
  4. Create a secret for the Controller access key using kubectl

    $ kubectl -n <app-ns> create secret generic appd-agent-secret --from-literal=access-key=<access-key>
  5. Update the deployment spec to reference the secret:

    spec:
    containers:
    - name: python-app
    env:
    - name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
    valueFrom:
    secretKeyRef:
    name: appd-agent-secret
    key: access-key
    ...
  6. Set the application-specific tier name environment variable APPDYNAMICS_AGENT_TIER_NAME

    spec:
    containers:
    - name: python-app
    env:
    - name: APPDYNAMICS_AGENT_TIER_NAME
    value: python-service
    - name: APPDYNAMICS_AGENT_REUSE_NODE_NAME_PREFIX
    value: python-service
    ...
  7. Add the proxy container

    spec:
    containers:
    ...
    - name: proxy
    image: appdynamics/dl-proxy:latest
    imagePullPolicy: Always
    env:
    - name: APPDYNAMICS_DEBUG_LOG
    value: "on"
    - name: APPDYNAMICS_LOGGING_LEVEL
    value: "debug"
    - name: APPDYNAMICS_TCP_COMM_HOST
    value: "0.0.0.0"
    - name: APPDYNAMICS_TCP_COMM_PORT
    value: "9091"
    - name: APPDYNAMICS_TCP_PORT_RANGE
    value: "10000-10100"
    ports:
    - containerPort: 9091
    protocol: TCP
    resources:
    limits:
    cpu: 500m
    memory: 900M
    requests:
    cpu: 400m
    memory: 600M
    ...

    Below is a complete example of a Kubernetes Deployment spec:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: mypython-app
    spec:
    selector:
    matchLabels:
    name: mypython-app
    replicas: 1
    template:
    metadata:
    labels:
    name: mypython-app
    spec:
    containers:
    - name: mypython-app
    image: myrepo/python-app-with-appd:v1
    imagePullPolicy: Always
    env:
    - name: APPDYNAMICS_AGENT_TIER_NAME
    value: mypython-app
    - name: APPDYNAMICS_AGENT_REUSE_NODE_NAME_PREFIX
    value: python-service
    - name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
    valueFrom:
    secretKeyRef:
    key: access-key
    name: appd-agent-secret
    envFrom:
    - configMapRef:
    name: appd-python-config
    ports:
    - containerPort: 8080
    - name: proxy
    image: appdynamics/dl-proxy:latest
    imagePullPolicy: Always
    env:
    - name: APPDYNAMICS_DEBUG_LOG
    value: "on"
    - name: APPDYNAMICS_LOGGING_LEVEL
    value: "debug"
    - name: APPDYNAMICS_TCP_COMM_HOST
    value: "0.0.0.0"
    - name: APPDYNAMICS_TCP_COMM_PORT
    value: "9091"
    - name: APPDYNAMICS_TCP_PORT_RANGE
    value: "10000-10100"
    ports:
    - containerPort: 9091
    protocol: TCP
    resources:
    limits:
    cpu: 500m
    memory: 900M
    requests:
    cpu: 400m
    memory: 600M
    restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: mypython-app
    spec:
    selector:
    name: mypython-app
    ports:
    - name: "8080"
    port: 8080
    targetPort: 8080
    type: LoadBalancer
    status:
    loadBalancer: {}

Use Init Containers

Note: This option applies to containers running in Kubernetes.

This option uses Kubernetes init containers to install the Python Agent into the application container when the application starts up. The Use of init containers requires that the application image is built without the Python Agent. The benefit of this option is that it does not require changes to the application image.

The init container provides a startup script that is used to override the default application startup command. It runs pip APP_ENTRY_POINT

To instrument a Python application using init containers:

  1. Build the Application Image Without the Python Agent
  2. Add the Init Container to the Deployment Spec
  3. Set the Python Agent Environment Variables
  4. Validate the Python Agent Install

Build the Application Image Without the Python Agent

The following example is Dockerfile that builds an application image without including the Python Agent dependency.

FROM python:3.7
COPY mypythonapp/ /app/
WORKDIR /app
RUN chmod +x ./app.py
EXPOSE 8080
RUN pip install -r requirements.txt
CMD pyagent run python ./app.py

Add the Init Container to the Deployment Spec

The deployment spec below illustrates the changes required to use an init container:

  • Line 16: The appd-python-init init container is defined and copies the contents of the init container to the application container.
  • Line 22: The init container references the python-agent-init image from Docker Hub.
  • Line 78: A volume mount is defined to share the contents of the init container with the application container.
  • Line 30: The application startup command is overridden to run the script

  • Line 34: APP_ENTRY_POINT APPDYNAMICS_AGENT_VERSION run-with-agent.sh. APPDYNAMICS_AGENT_VERSION PyPi AppDynamics release page.

Note: We recommend you to deploy Dynamic Languages proxy for better performance.

Use the following code samples depending on your proxy type:

Dynamic Languages Proxy (Manual)
apiVersion: apps/v1
kind: Deployment
metadata:
name: mypython-app-init
spec:
selector:
matchLabels:
name: mypython-app-init
replicas: 1
template:
metadata:
labels:
name: mypython-app-init
spec:
initContainers:
- name: appd-python-init
command:
- cp
- -r
- /opt/appdynamics/.
- /opt/temp
image: docker.io/appdynamics/python-agent-init:1.0
imagePullPolicy: Always
volumeMounts:
- mountPath: /opt/temp
name: appd-python-init
containers:
- name: mypython-app-init
image: myrepo/python-app-no-appd:v1
command: ["/bin/sh"]
args: ["-c", "/opt/appdynamics-python/run-with-agent.sh"]
imagePullPolicy: Always
env:
- name: APP_ENTRY_POINT
value: "--use-manual-proxy python /app/app.py"
- name: APPDYNAMICS_AGENT_VERSION
# Use latest version from https://pypi.org/project/appdynamics/#history
value: 21.12.2.4693
- name: APPDYNAMICS_AGENT_TIER_NAME
value: mypython-app-init
- name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
valueFrom:
secretKeyRef:
key: access-key
name: appd-agent-secret
envFrom:
- configMapRef:
name: appd-python-config
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /opt/appdynamics-python
name: appd-python-init
- name: proxy
image: appdynamics/dl-proxy:latest
imagePullPolicy: Always
env:
- name: APPDYNAMICS_DEBUG_LOG
value: "on"
- name: APPDYNAMICS_LOGGING_LEVEL
value: "debug"
- name: APPDYNAMICS_TCP_COMM_HOST
value: "0.0.0.0"
- name: APPDYNAMICS_TCP_COMM_PORT
value: "9091"
- name: APPDYNAMICS_TCP_PORT_RANGE
value: "10000-10100"
ports:
- containerPort: 9091
protocol: TCP
resources:
limits:
cpu: 500m
memory: 900M
requests:
cpu: 400m
memory: 600M
volumes:
- name: appd-python-init
emptyDir: {}
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: mypython-app-init
spec:
selector:
name: mypython-app-init
ports:
- name: "8080"
port: 8080
targetPort: 8080
type: LoadBalancer
status:
loadBalancer: {}]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pod-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Default Proxy
apiVersion: apps/v1
kind: Deployment
metadata:
name: mypython-app-init
spec:
selector:
matchLabels:
name: mypython-app-init
replicas: 1
template:
metadata:
labels:
name: mypython-app-init
spec:
initContainers:
- name: appd-python-init
command:
- cp
- -r
- /opt/appdynamics/.
- /opt/temp
image: docker.io/appdynamics/python-agent-init:1.0
imagePullPolicy: Always
volumeMounts:
- mountPath: /opt/temp
name: appd-python-init
containers:
- name: mypython-app-init
image: myrepo/python-app-no-appd:v1
command: ["/bin/sh"]
args: ["-c", "/opt/appdynamics-python/run-with-agent.sh"]
imagePullPolicy: Always
env:
- name: APP_ENTRY_POINT
value: "python /app/app.py"
- name: APPDYNAMICS_AGENT_VERSION
# Use latest version from https://pypi.org/project/appdynamics/#history
value: 21.12.2.4693
- name: APPDYNAMICS_AGENT_TIER_NAME
value: mypython-app-init
- name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
valueFrom:
secretKeyRef:
key: access-key
name: appd-agent-secret
envFrom:
- configMapRef:
name: appd-python-config
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /opt/appdynamics-python
name: appd-python-init
volumes:
- name: appd-python-init
emptyDir: {}
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: mypython-app-init
spec:
selector:
name: mypython-app-init
ports:
- name: "8080"
port: 8080
targetPort: 8080
type: LoadBalancer
status:
loadBalancer: {}
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pod-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io

Set the Python Agent Environment Variables

When using an init container, set the Python Agent environment variables for Kubernetes as described in Use a Dockerfile.