Profiling

If you have not yet configured Kubedim for baseline dimming, follow the steps here.

Configuring InfluxDB

Profiling requires an external InfluxDB instance to be configured and visible to the cluster, as it will be used as a data store used by Kubedim's profiler to assign priorities to users.

Ensure you provision the following:

  • An organisation for Kubedim
  • A token which has access to this organisation
  • A bucket to store sessions (e.g., session_history)
  • A bucket to store logs (e.g., profiling_log)

Deploying the Priority Database

Kubedim's profiler must write to a store which can be quickly retrieved by Kubedim. We use Redis for this.

Deployment

First, we create a new deployment manifest for the profiler database.

# Suggested path: kubedim/deployments/profiler-db.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: profiler-db
  labels:
    name: profiler-db
  namespace: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      name: profiler-db
  template:
    metadata:
      labels:
        name: profiler-db
    spec:
      containers:
        - name: profiler-db
          image: redis:alpine
          ports:
            - name: redis
              containerPort: 6379
          securityContext:
            capabilities:
              drop:
                - all
              add:
                - CHOWN
                - SETGID
                - SETUID
            readOnlyRootFilesystem: true
      nodeSelector:
        beta.kubernetes.io/os: linux

Service

Next, we create a service manifest for the profiler database.

# Suggested path: kubedim/services/profiler-db.yaml

apiVersion: v1
kind: Service
metadata:
  name: profiler-db
  labels:
    name: profiler-db
  namespace: my-app
spec:
  ports:
    - port: 6379
      targetPort: 6379
  selector:
    name: profiler-db

Scaffolding the Profiler

Kubedim's profiler is deployed as a separate service, so the appropriate manifest files must first be scaffolded as follows.

Deployment

First, we add a new deployment manifest for the profiler.

# Suggested path: kubedim/deployments/profiler.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: profiler
  labels:
    name: profiler
  namespace: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      name: profiler
  template:
    metadata:
      labels:
        name: profiler
    spec:
      containers:
        - name: profiler
          image: kcz17/profiler:0.0.15
          ports:
            # Necessary to expose the profiler to the main dimmer service.
            - containerPort: 8080
          securityContext:
            runAsNonRoot: true
            runAsUser: 10001
            capabilities:
              drop:
                - all
              add:
                - NET_BIND_SERVICE
            readOnlyRootFilesystem: true
          volumeMounts:
            - name: config-volume
              mountPath: /app/config.yaml
              subPath: config.yaml
          env:
            # We do not want to commit a sensitive token to version control,
            # so we will instead set the InflxuDB token configuration value via
            # a Kubernetes secret.
            - name: CONNECTIONS_INFLUXDB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: profiler-influxdb
                  key: token
      volumes:
        - name: config-volume
          configMap:
            # Points to configuration for the profiler.
            name: profiler-config
      nodeSelector:
        beta.kubernetes.io/os: linux

Instead of adding the InfluxDB token in a configuration file, make it available to the container using secret, by running the following: kubectl create secret generic profiler-influxdb --from-literal=token='[TOKEN]' -nmy-app

Service

# Suggested path: kubedim/services/profiler.yaml

apiVersion: v1
kind: Service
metadata:
  name: profiler
  labels:
    name: profiler
  namespace: my-app
spec:
  ports:
    - port: 80
      targetPort: 8080
  selector:
    name: profiler

ConfigMap

# Suggested path: kubedim/configmaps/profiler.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: profiler-config
  namespace: my-app
data:
  config.yaml: |
    connections:
      redis:
        addr: "profiler-db:6379"
        pass: ""
        storeDB: 0
        queueDB: 1
      influxdb:
        addr: "http://[InfluxDB IP]:[InfluxDB Port]"
        # The token should be set as a secret, separate from the ConfigMap.
        org: "[Bucket Organisation]"
        sessionBucket: "session_history" # Adjust this if your bucket name is different.
        loggingBucket: "profiling_log" # Adjust htis if your bucket name is different.
    profiling:
      # interval between fetching sessions to be profiled in seconds.
      interval: 10
    rules:
      # We will fill this out later.

Configuring Profiler Rules

An example of profiler rules in the above ConfigMap is as follows:

# ...
    rules:
      - description: "User has checked out items in past"
        path: "/cart"
        method:
          shouldMatchAll: false
          method: "POST"
        occurrences: 1
        result: "high"
      - description: "User is browsing and unlikely to buy"
        path: "/category.html"
        method:
          shouldMatchAll: true
        occurrences: 5
        result: "low"
      - description: "User is browsing for delivery updates"
        path: "/news"
        method:
          shouldMatchAll: true
        occurrences: 1
        result: "low"
# ...

The profiler works by running through the rules in sequential order, counting the number of times a session has encountered each path-method combination. If the number of occurrences is met or exceeded when testing a rule, then the resulting priority is assigned to the user and no further rules are tested.

Connecting Kubedim to the Profiler

To connect Kubedim to the profiler, we update the Kubedim ConfigMap, adding the following section nested under the dimming attribute.

    dimming:
      enabled: true
      # ...
      profiler:
        enabled: true
        # Session cookie is the name of the cookie which identifies unique
        # user sessions. This should be changed to the session cookie key.
        sessionCookie: "md.sid"
        influxdb:
          addr: "http://[InfluxDB Host]:[InfluxDB Port]]"
          # Recall we have set the profiler token as an environment variable.
          org: "[InfluxDB organisation]"
          bucket: "session_history" # Change this where appropriate.
        redis:
          addr: "profiler-db:6379"
          password: "" # The default Redis image does not use a password.
          # We use different databases to store priorities and the queue.
          prioritiesDB: 0 
          queueDB: 1