Install - Multiplexer to run OpenTelemetry and vFunction .NET Agents simultaneously on a Linux Container


Overview

Docker Sidecars can be used for the .NET Datadog Multiplexer Agent, .NET OpenTelemetry Agent and .NET vFunction Agent to separate the components from the main application.

This workflow does the following:

  1. In the Build process of the Init Container, move the .NET Agents onto the Container
  2. In the Build process of the Init Container, unpack the .NET Agents to the /tmp/ directory
  3. In the Startup process of the Init Container, move the /tmp/ contents to a /shared/ folder that is used by the Sidecar Container
  4. In the Startup process of the Application Container, add the .NET Datadog Multiplexer Agent parameters as environmental variables and start the Application

Configuring the Init Container

  1. Download the latest vFunction Sudoless Controller Installation TGZ
  2. Download a sample installation.yaml
  3. Modify the installation.yaml to be relevant to your environment
  • Find-and-replace the CHANGE_ME values below based on the directions in the Comments
controller:
 name: CHANGE_ME #... use a string that indicates what and where this is, e.g. UAT tomcat1
 host: CHANGE_ME #... use the VF Server's address, e.g. http://10.0.0.49
 org_id: CHANGE_ME #... taken from the VF Server UI after you've created the Application
 app_id: CHANGE_ME #... taken from the VF Server UI after you've created the Application
 client_id: CHANGE_ME #... taken from the VF Server UI after you've created the Application
 client_secret: CHANGE_ME #... taken from the VF Server UI after you've created the Application
 instance_id: CHANGE_ME # ... use the same string as used in the "name" field
 type: dotnet
 instrconf_additions:
   inclusions:
#      - a.b.c.
   exclusions:
#      - a.b.c.
 tags:
#    - CHANGE_ME # ... use the same string as used in the "name" field

server_application:
#  name: 
#  include_classes: 
#  allowed_users:

agent:
#  application_name:
#  architecture: x86
#  application_command:
  1. Download or create the Init Container’s startup-init.sh script
#!/usr/bin/env bash

set -x

echo "Moving controller files to shared folder"
mv /tmp/vfunction /shared/
mkdir /shared/binaries-for-viper
  1. Create a folder for vFunction artifacts in the Artifact Repository accessible by the Docker Build
  2. Add the vFunction Sudoless Controller Installation TGZ, the installation.yaml and the startup.sh to the Artifact Repository
  3. Create a vFunction specific branch to add the vFunction artificats to the Init Container’s Dockerfile
  4. Download or create the Init Container’s Dockerfile
### In the Dockerfile, replace ARTIFACT_REPOSITORY with the actual path to the Build location where the vFunction artifacts are stored
### If planning to just run the Agent without Viper in the Sidecars, add the -a flag to the end of the bash line. This will run the installation in AgentMode
FROM almalinux:9

### Datadog Multiplexer Agent

MKDIR /shared/datadog/
COPY ARTIFACT_REPOSITORY/datadog/Datadog.Trace.ClrProfiler.Native.so /shared/datadog/
COPY ARTIFACT_REPOSITORY/datadog/loader-sidecars-otel-vf.conf /shared/datadog/datadog/loader.conf

### OpenTelemetry Agent

RUN curl -sSfL https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/latest/download/otel-dotnet-auto-install.sh -O /shared/otel-dotnet-auto-install.sh && \
 sh ./otel-dotnet-auto-install.sh && \
 mv ./otel-dotnet-auto /shared/
 chmod +x /shared/.otel-dotnet-auto/instrument.sh

### vFunction Agent

COPY ARTIFACT_REPOSITORY/vfunction/vfunction-controller-sudo-less-installation*.tgz /tmp/vfunction-controller-sudo-less-installation.tgz
COPY ARTIFACT_REPOSITORY/vfunction/vfunction/*.yaml /tmp/
COPY ARTIFACT_REPOSITORY/vfunction/startup-*-init.sh /usr/bin/startup-init.sh

RUN mkdir /shared && cd /shared && mv /tmp/vfunction-controller-sudo-less-installation.tgz /shared/     && \
   tar zxvf /shared/vfunction-controller-sudo-less-installation.tgz      && \
   rm -rf /shared/vfunction-controller-sudo-less-installation.tgz        && \
   mv /tmp/installation.yaml /shared/vfunction/etc/sysconfig/vfunction/installation/instances/default-dotnet/  && \
   bash /shared/vfunction/opt/vfunction/controller-installation/install.sh -i default-dotnet -n  && \
   mv /shared/vfunction /tmp/      && \
   rm -rf /shared                  && \
   chmod +x /usr/bin/startup-init.sh      && \
   chmod -R 777 /usr/bin/ /tmp  && \

ENTRYPOINT ["/bin/sh"]
CMD ["/usr/bin/startup-init.sh"]
  1. Build the Init Dockerfile

Configuring the Controller Container

  1. Download or create the Controller Container’s startup-controller.sh script
#!/usr/bin/env bash

set -x

echo "Starting the controller"

bash /shared/vfunction/opt/vfunction/controller/instances/default-dotnet/bin/vf-controller start || echo "Failed to start the controller"

while true; do
 sleep 600
 echo "Still alive..." 
done
  1. Add the startup-controller.sh script to the folder for vFunction artifacts in the Artifact Repository accessible by the Docker Build
  2. Download or create the Controller Container’s Dockerfile
### In the Dockerfile, replace ARTIFACT_REPOSITORY with the actual path to the Build location where the vFunction artifacts are stored
FROM almalinux:9

ARG NAME
ARG VERSION
ARG RELEASE

ENV SUMMARY="Linux .NET Sidecar application wrapper for vFunction Controller."          \
   DESCRIPTION="Linux .NET Sidecar application wrapper for vFunction Controller."

LABEL summary="$SUMMARY"                                \
     description="$DESCRIPTION"                        \
     io.k8s.description="$DESCRIPTION"                 \
     name="vfunction/$NAME"                            \
     vendor="vFunction"                                \
     version="$VERSION"                                \
     release="$RELEASE"                                

RUN adduser -l -u "1500" "appuser"

COPY ARTIFACT_REPOSITORY/vfunction/startup-controller.sh /usr/bin/startup-controller.sh

RUN chmod +x /usr/bin/startup-controller.sh                                                 && \
   chmod -R 777 /usr/bin/

USER 1500

ENTRYPOINT ["/bin/sh"]
CMD ["/usr/bin/startup-controller.sh"]
  1. Build the Controller Dockerfile

Configuring the Viper Container

Viper is the most resource intensive vFunction process when compared with the Agent and Controller. Some organizations choose to run Viper in a separate location and skip the step of setting up the Viper Container as a Sidecar.

  1. Download or create the Viper Container’s startup-viper.sh script
#!/usr/bin/env bash

set -x

echo "Starting Viper"

bash /shared/vfunction/opt/vfunction/viper/instances/default-dotnet/bin/vf-viper start || echo "Failed to start viper"
  1. Add the startup-viper.sh script to the folder for vFunction artifacts in the Artifact Repository accessible by the Docker Build
  2. Download or create the Viper Container’s Dockerfile
### In the Dockerfile, replace ARTIFACT_REPOSITORY with the actual path to the Build location where the vFunction artifacts are stored
### Replace the APPLICATION_ASSEMBLIES with the path to the DLLs for the Application
FROM almalinux:9

ARG NAME
ARG VERSION
ARG RELEASE

ENV SUMMARY="Linux .NET Sidecar application wrapper for vFunction Controller."          \
   DESCRIPTION="Linux .NET Sidecar application wrapper for vFunction Controller."

LABEL summary="$SUMMARY"                                \
     description="$DESCRIPTION"                        \
     io.k8s.description="$DESCRIPTION"                 \
     name="vfunction/$NAME"                            \
     vendor="vFunction"                                \
     version="$VERSION"                                \
     release="$RELEASE"                                

RUN adduser -l -u "1500" "appuser"                                                          && \
   mkdir -p /opt/application/lib

COPY /APPLICATION_ASSEMBLIES /shared/binaries-for-viper/
COPY ARTIFACT_REPOSITORY/vfunction/startup-viper.sh /usr/bin/startup-viper.sh

RUN chmod +x /usr/bin/startup-viper.sh                                                      && \
   chmod -R 777 /usr/bin/

USER 1500

ENTRYPOINT ["/bin/sh"]
CMD ["/usr/bin/startup-viper.sh"]
  1. Build the Viper Dockerfile

Create the configMap with vFunction Agent Environment Variables

  1. Download or create the vf-agent-env-vars.yaml
    #!/usr/bin/env sh
apiVersion: v1
kind: ConfigMap
metadata:
   name: vf-agent-env-vars
data:
   VF_AGENT_CONF_LOCATION: "/shared/vfunction/etc/sysconfig/vfunction/agent/instances/default-dotnet/conf.json"
   CORECLR_PROFILER_PATH_64: "/shared/vfunction/opt/vfunction/agent/libvfagent.net.so"
   CORECLR_ENABLE_PROFILING: "1"
   CORECLR_PROFILER_PATH_64: "/shared/vfunction/opt/vfunction/agent/libvfagent.net.so"
   DOTNET_TailCallOpt: "0"
  1. Apply the configMap to the Cluster

Configuring the Deployment Manifest

  1. Download or modify the manifest for the environment to ensure that the Volumes are created and accessible for each Container
# Find-and-replace 
#    INIT_IMAGE, 
#    VIPER_IMAGE, 
#    CONTROLLER_IMAGE
#    APPLICATION_IMAGE 
# ...with the actual names of the images
#
# Find-andreplace ARTIFACT_REPOSITORY with the actual path to the Build location 
#   where the vFunction artifacts are stored

apiVersion: apps/v1
kind: Deployment
metadata:
 name: application-with-vfunction-controller
  namespace: vfunction
  labels:
    app: application-with-vfunction-controller
spec:
 replicas: 1
  selector:
   matchLabels:
      app: application-with-vfunction-controller
  template:
   metadata:
    labels:
     app: application-with-vfunction-controller
    spec:
      initContainers:
      - image: INIT_IMAGE
        imagePullPolicy: IfNotPresent
        name: init
        securityContext:
          runAsNonRoot: true
          runAsUser: 1500
        volumeMounts:
        - mountPath: /shared/
          name: shared
      containers:
      - name: application
        image: APPLICATION_IMAGE
        env:
        - name: CORECLR_ENABLE_PROFILING
          valueFrom:
            configMapKeyRef:
              name: vf-agent-env-vars
              key: CORECLR_ENABLE_PROFILING
        - name: CORECLR_PROFILER
          valueFrom:
            configMapKeyRef:
              name: vf-agent-env-vars
              key: CORECLR_PROFILER
        - name: CORECLR_PROFILER_PATH_64
          valueFrom:
            configMapKeyRef:
              name: vf-agent-env-vars
              key: CORECLR_PROFILER_PATH_64
        - name: DOTNET_TailCallOpt
          valueFrom:
            configMapKeyRef:
              name: vf-agent-env-vars
              key: DOTNET_TailCallOpt
        - name: VF_AGENT_CONF_LOCATION
          valueFrom:
            configMapKeyRef:
              name: vf-agent-env-vars
              key: VF_AGENT_CONF_LOCATION
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
        securityContext:
          runAsNonRoot: true
          runAsUser: 1500
        volumeMounts:
        - mountPath: /shared/
          name: shared
      - name: controller
        image: CONTROLLER_IMAGE
        imagePullPolicy: IfNotPresent
        securityContext:
          runAsNonRoot: true
          runAsUser: 1500
        volumeMounts:
        - mountPath: /shared/
          name: shared
      - name: viper
        image: VIPER_IMAGE
        imagePullPolicy: IfNotPresent
        securityContext:
          runAsNonRoot: true
          runAsUser: 1500
        volumeMounts:
        - mountPath: /shared/
          name: shared
      volumes:
      - emptyDir: {}
        name: shared

Deploy the Application and vFunction Sidecars

  1. Apply the Deployment Manifest in the Cluster
  2. Confirm that the Application comes up and functions as expected
  3. If any issues arise: