# Run yc-360 Script in Sidecar Container on OpenShift

This guide walks you through deploying the yc-360 Script in an OpenShift environment using a sidecar container to monitor the BuggyApp application in M3 Mode (Micro-metrics Monitoring). It covers:

  • Creating the yc-360 script configuration as a Secret
  • Deploying BuggyApp with the yc-360 script as a sidecar
  • Enabling access logging and application log capture
  • Generating traffic with a lightweight sidecar container

Not sure what M3 Mode means? Learn more about Execution Modes

Follow the steps below to run the yc-360 script in an OpenShift Pod.

# 1. Create a Secret for yc-360 Script Configuration

The yc-360 script requires a configuration file named yc-config.yaml, which must be mounted as a secret in the container.

Create an OpenShift Secret manifest (yc-secret.yaml) to securely store the YAML configuration file.

Secret File: yc-secret.yaml

apiVersion: v1
kind: Secretn
metadata:
  name: yc-config
  namespace: yc-apps
stringData:
  yc-config.yaml: |
    version: "1"
    options:
      k: <API_KEY>
      s: <http://MY-YC-SERVER:PORT>
      j: /opt/java/openjdk
      kubernetes: false
      m3: true
      m3Frequency: 60s
      storagePath: /opt/workspace/yc-360-script/yc-output
      processTokens:
        - buggyapp$BuggyApp
      accessLogs:
        - /opt/workspace/ba/logs/app.log$BuggyApp
      accessLogFormats:
        - %h %l %u %t %r %s %b %D$BuggyApp
      accessLogSources:
        - Tomcat$BuggyApp
      appLogs:
        - /opt/workspace/ba/logs/app.log$BuggyApp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Replace the placeholders in the YAML configuration file with your actual values:

  • <API_KEY>: Your API key was provided with your license at the time of registration. If you're not sure where to find the API key, click here (opens new window).
  • <http://MY-YC-SERVER:PORT>: URL of the yCrash server (e.g., http://localhost:8080).
  • /opt/java/openjdk: The directory path where Java is installed in your container. If you're using the official yc-360 script image, set this to /opt/java/openjdk.

# Configuration Options Explained

Option Description
m3: true Enables Micro-metrics Monitoring mode
m3Frequency: 60s Interval between M3 metric submissions
storagePath Writable directory for yc-360 script output files
processTokens Token to identify the Java process (token$appName format)
accessLogs Path to the access log file (filePath$appName format)
accessLogFormats The log pattern format matching your access log output
accessLogSources The source type of the access log (e.g., Tomcat, Nginx)
appLogs Path to the application log file (filePath$appName format)
kubernetes: false Set to true if your ServiceAccount has cluster-level namespace listing permissions

For a full list of arguments, refer to the All yc-360 Script Arguments page.

Apply the Secret: Once your secret file is ready, apply it using:

oc apply -f yc-secret.yaml
1

# 2. Create a PersistentVolumeClaim for Logs

A PersistentVolumeClaim (PVC) is used to share logs between the BuggyApp container and the yc-360 script sidecar. Create a file ba-logs-pvc.yaml:

PVC File: ba-logs-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ba-logs-pvc
  namespace: yc-apps
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
1
2
3
4
5
6
7
8
9
10
11

Apply the PVC:

oc apply -f ba-logs-pvc.yaml
1

# 3. Configure ServiceAccount

The yc-360 script needs a ServiceAccount. Create yc-360-script-serviceaccount.yaml:

ServiceAccount File: yc-360-script-serviceaccount.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: yc-360-script-serviceaccount
  namespace: yc-apps
1
2
3
4
5

Apply the ServiceAccount:

oc apply -f yc-360-script-serviceaccount.yaml
1

TIP

If you need the yc-360 script to enrich data with Kubernetes namespace metadata, you'll also need a ClusterRoleBinding or RoleBinding. Set kubernetes: true in your yc-config.yaml and create the appropriate binding. See Step 5 below.

# 4. Deploy BuggyApp with yc-360 Script as a Sidecar

In this step, you'll deploy three containers within the same OpenShift Pod:

  • yc-360 Script: Collects performance metrics from the application.
  • BuggyApp: A sample Java application used for simulating performance scenarios. You can replace BuggyApp with your Java application.
  • Traffic Generator: A lightweight busybox container that generates HTTP requests to simulate real traffic and produce access log entries.

# Key Points

  • ServiceAccount: The yc-360 script container uses the yc-360-script-serviceaccount ServiceAccount.
  • shareProcessNamespace: Set to true so the yc-360 script can see the BuggyApp's Java process.
  • Volumes: The yc-360 script mounts yc-config.yaml from a Secret, logs from a shared PVC, and writes output to a writable emptyDir volume.
  • Access Logging: BuggyApp uses webapp-runner's --access-log flag to write Tomcat access logs to STDOUT, which are captured to a file via tee.
  • Ports: yc-360 Script listens on 8085, BuggyApp listens on 9010.

# Deployment Manifest: buggyapp-yc-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: yc-apps
  namespace: yc-apps
  labels:
    app: yc-apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: yc-apps
  template:
    metadata:
      labels:
        app: yc-apps
    spec:
      serviceAccountName: yc-360-script-serviceaccount
      shareProcessNamespace: true
      terminationGracePeriodSeconds: 180
      containers:
      - name: yc-360-script
        image: ycrash/yc-360-script:latest
        imagePullPolicy: Always
        env:
        - name: APP_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app']
        - name: HOST_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        ports:
        - containerPort: 8085
        resources:
          requests:
            memory: 100Mi
            cpu: "50m"
          limits:
            memory: 350Mi
            cpu: "100m"
        volumeMounts:
        - name: yc-config
          mountPath: "/opt/workspace/yc-360-script/yc-config.yaml"
          subPath: yc-config.yaml
        - name: ba-logs-pvc
          mountPath: "/opt/workspace/ba/logs"
          readOnly: true
        - name: yc-workspace
          mountPath: "/opt/workspace/yc-360-script/yc-output"
        - name: tmp
          mountPath: "/tmp"
      - name: traffic-gen
        image: busybox:latest
        imagePullPolicy: Always
        command: ["/bin/sh", "-c"]
        args:
        - >-
          while true; do
            wget -q -O /dev/null http://localhost:9010/ 2>/dev/null || true;
            sleep $(( RANDOM % 3 + 1 ));
          done
        resources:
          requests:
            memory: 16Mi
            cpu: "10m"
          limits:
            memory: 32Mi
            cpu: "25m"
      - name: buggyapp
        image: ycrash/buggyapp:alpine
        imagePullPolicy: Always
        env:
        - name: APP_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app']
        - name: HOST_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        command: ["/bin/sh", "-c"]
        args:
        - >-
          java -Xms512m -Xmx1g -verbose:gc
          -Xlog:gc*:file=/opt/workspace/ba/logs/ba-gclog-%p.gc:time,uptime,level,tags
          -XX:+UnlockDiagnosticVMOptions
          -XX:+HeapDumpOnOutOfMemoryError
          -XX:HeapDumpPath=/opt/workspace/ba/logs/ba-heapdump-%p.hprof
          -XX:ErrorFile=/opt/workspace/ba/logs/ba-log-hs_err_pid-%p.log
          -jar webapp-runner.jar --port 9010 --access-log --access-log-pattern '%h %l %u %t %r %s %b %D' buggyapp.war
          2>&1 | tee /opt/workspace/ba/logs/app.log
        ports:
        - containerPort: 9010
        resources:
          requests:
            memory: 512Mi
            cpu: "200m"
          limits:
            memory: 1Gi
            cpu: "500m"
        volumeMounts:
        - name: tomcat-files
          mountPath: "/opt/workspace/ba/target"
        - name: ba-logs-pvc
          mountPath: "/opt/workspace/ba/logs"
        - name: tmp
          mountPath: "/tmp"
      volumes:
      - name: yc-config
        secret:
          secretName: yc-config
          items:
          - key: yc-config.yaml
            path: yc-config.yaml
      - name: tomcat-files
        emptyDir: {}
      - name: ba-logs-pvc
        persistentVolumeClaim:
          claimName: ba-logs-pvc
      - name: yc-workspace
        emptyDir: {}
      - name: tmp
        emptyDir: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

TIP

This deployment uses the shareProcessNamespace: true flag. It allows containers within the same Pod to share the process namespace, enabling the yc-360 script to monitor processes running in the application container.

For more details on process namespace sharing, refer to the official Kubernetes documentation (opens new window).

Apply the deployment:

oc apply -f buggyapp-yc-deployment.yaml
1

# How Access Logging Works

The BuggyApp container uses a shell wrapper to enable Tomcat access logging:

java ... -jar webapp-runner.jar --port 9010 --access-log --access-log-pattern '%h %l %u %t %r %s %b %D' buggyapp.war 2>&1 | tee /opt/workspace/ba/logs/app.log
1
  • --access-log: Enables Tomcat's AccessLogValve to STDOUT
  • --access-log-pattern '%h %l %u %t %r %s %b %D': Sets the log format including response time (%D)
  • 2>&1 | tee /opt/workspace/ba/logs/app.log: Captures all output (access logs + application logs) to a file that the yc-360 script can read

# Access Log Pattern Reference

Token Description Example
%h Remote IP address 10.0.0.1
%l Remote logical username -
%u Authenticated user -
%t Timestamp [07/Aug/2026:16:10:46 +0000]
%r Request line GET / HTTP/1.1
%s HTTP status code 200
%b Bytes sent 15999
%D Response time (ms) 15

# Container Volumes Explained

Volume Mount Path Purpose
yc-config /opt/workspace/yc-360-script/yc-config.yaml yc-360 script configuration (from Secret)
ba-logs-pvc /opt/workspace/ba/logs Shared PVC for GC logs, access logs, and app logs
yc-workspace /opt/workspace/yc-360-script/yc-output Writable directory for yc-360 script output
tomcat-files /opt/workspace/ba/target BuggyApp Tomcat working directory
tmp /tmp Temporary files

# 5. Create Services

Define services to expose both BuggyApp and the yc-360 script within the cluster.

# Service for BuggyApp: buggyapp-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: buggyapp-service
  labels:
    app: yc-apps
  namespace: yc-apps
spec:
  selector:
    app: yc-apps
  ports:
    - protocol: TCP
      port: 9010
      targetPort: 9010
  type: ClusterIP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Service for yc-360 Script: yc-360-script-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: yc-360-script-service
  namespace: yc-apps
spec:
  selector:
    app: yc-apps
  ports:
    - protocol: TCP
      port: 8085
      targetPort: 8085
  type: ClusterIP
1
2
3
4
5
6
7
8
9
10
11
12
13

Apply the Services:

oc apply -f buggyapp-service.yaml
oc apply -f yc-360-script-service.yaml
1
2

# 6. Create Route for External Access

Expose the BuggyApp outside the cluster using an OpenShift Route.

# Route for BuggyApp: buggyapp-ingress.yaml

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: buggyapp-route
  namespace: yc-apps
spec:
  to:
    kind: Service
    name: buggyapp-service
  port:
    targetPort: 9010
  tls:
    termination: edge
  wildcardPolicy: None
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Apply the Route:

oc apply -f buggyapp-ingress.yaml
1

TIP

The yc-360 script does not serve HTTP traffic, so a Route for it is not required. You can access its logs and output via oc logs and oc exec.

# 7. Deploying the Configuration

# 1. Create the Namespace (if not already created)

oc new-project yc-apps --display-name 'yCrash Apps'
1

WARNING

If your OpenShift sandbox does not allow self-provisioning of new projects, use an existing namespace that you have access to. Replace yc-apps with your namespace in all YAML files.

# 2. Apply All Resources in Order

oc apply -f yc-360-script-serviceaccount.yaml
oc apply -f ba-logs-pvc.yaml
oc apply -f yc-secret.yaml
oc apply -f buggyapp-yc-deployment.yaml
oc apply -f buggyapp-service.yaml
oc apply -f yc-360-script-service.yaml
oc apply -f buggyapp-ingress.yaml
1
2
3
4
5
6
7

# 3. Verify the Deployment

# Check pods are running (should see 3 containers)
oc get pods -n yc-apps

# Check routes
oc get routes -n yc-apps

# Get the BuggyApp URL
oc get route buggyapp-route -n yc-apps -o jsonpath='{.spec.host}'
1
2
3
4
5
6
7
8

# 4. Access the Applications

  • BuggyApp: Open the route URL in your browser

# 8. Verify Log Capture

Once the pods are running, verify that logs are being captured:

# Get the pod name
POD=$(oc get pod -n yc-apps -l app=yc-apps -o jsonpath='{.items[0].metadata.name}')

# Check that app.log has both access logs and application output
oc exec $POD -c buggyapp -n yc-apps -- tail -10 /opt/workspace/ba/logs/app.log

# Check GC logs are being written
oc exec $POD -c buggyapp -n yc-apps -- ls -la /opt/workspace/ba/logs/

# Check yc-360-script logs for M3 metric submissions
oc logs $POD -c yc-360-script -n yc-apps --tail=20
1
2
3
4
5
6
7
8
9
10
11

Expected access log output:

127.0.0.1 - - [07/Aug/2026:17:35:12 +0000] GET / HTTP/1.1 200 15999 1
127.0.0.1 - - [07/Aug/2026:17:35:13 +0000] GET / HTTP/1.1 200 15999 1
1
2

# 9. Execute yc-360 Script Manually (Optional)

The yc-360 script in M3 mode automatically reads the yc-config.yaml file and executes. If you need to trigger a manual capture:

oc exec -it $POD -c yc-360-script -n yc-apps -- /bin/bash
/opt/workspace/yc-360-script/yc -onlyCapture -p buggyapp -j /opt/java/openjdk -a BuggyApp
1
2

Arguments:

  • -onlyCapture: Triggers a one-time capture instead of continuous monitoring
  • -p buggyapp: Unique token to identify the target Java process. Learn more about What is Unique Token?
  • -j /opt/java/openjdk: The directory path where Java is installed in your container
  • -a BuggyApp: Friendly name for the application (displayed in the yCrash dashboard)

# (Optional) Configure RBAC for Kubernetes Enrichment

If you want the yc-360 script to enrich data with Kubernetes namespace metadata, set kubernetes: true in your yc-config.yaml and create the appropriate RBAC resources.

# RoleBinding (namespace-scoped): yc-360-script-rolebinding.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: yc-360-script-rolebinding
  namespace: yc-apps
subjects:
- kind: ServiceAccount
  name: yc-360-script-serviceaccount
  namespace: yc-apps
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io
1
2
3
4
5
6
7
8
9
10
11
12
13

WARNING

A RoleBinding only grants permissions within the namespace. If you need cluster-wide namespace listing, you'll need a ClusterRoleBinding with cluster-admin or a custom ClusterRole. Not all OpenShift sandboxes allow creating ClusterRoleBindings.


# Troubleshooting

# 1. Check Pod Logs

# BuggyApp logs (includes access logs and application output)
oc logs <pod_name> -c buggyapp -n yc-apps --tail=50

# yc-360-script logs
oc logs <pod_name> -c yc-360-script -n yc-apps --tail=50
1
2
3
4
5

# 2. Check Service Routes

oc get routes -n yc-apps
1

# 3. Check ServiceAccount Permissions

oc describe serviceaccount yc-360-script-serviceaccount -n yc-apps
1

# Complete Deployment YAML Files

Below are all the YAML files needed for the complete deployment.

# yc-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: yc-config
  namespace: yc-apps
stringData:
  yc-config.yaml: |
    version: "1"
    options:
      k: <API_KEY>
      s: <http://MY-YC-SERVER:PORT>
      j: /opt/java/openjdk
      kubernetes: false
      m3: true
      m3Frequency: 60s
      storagePath: /opt/workspace/yc-360-script/yc-output
      processTokens:
        - buggyapp$BuggyApp
      accessLogs:
        - /opt/workspace/ba/logs/app.log$BuggyApp
      accessLogFormats:
        - %h %l %u %t %r %s %b %D$BuggyApp
      accessLogSources:
        - Tomcat$BuggyApp
      appLogs:
        - /opt/workspace/ba/logs/app.log$BuggyApp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# ba-logs-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ba-logs-pvc
  namespace: yc-apps
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
1
2
3
4
5
6
7
8
9
10
11

# yc-360-script-serviceaccount.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: yc-360-script-serviceaccount
  namespace: yc-apps
1
2
3
4
5

# buggyapp-yc-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: yc-apps
  namespace: yc-apps
  labels:
    app: yc-apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: yc-apps
  template:
    metadata:
      labels:
        app: yc-apps
    spec:
      serviceAccountName: yc-360-script-serviceaccount
      shareProcessNamespace: true
      terminationGracePeriodSeconds: 180
      containers:
      - name: yc-360-script
        image: ycrash/yc-360-script:latest
        imagePullPolicy: Always
        env:
        - name: APP_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app']
        - name: HOST_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        ports:
        - containerPort: 8085
        resources:
          requests:
            memory: 100Mi
            cpu: "50m"
          limits:
            memory: 350Mi
            cpu: "100m"
        volumeMounts:
        - name: yc-config
          mountPath: "/opt/workspace/yc-360-script/yc-config.yaml"
          subPath: yc-config.yaml
        - name: ba-logs-pvc
          mountPath: "/opt/workspace/ba/logs"
          readOnly: true
        - name: yc-workspace
          mountPath: "/opt/workspace/yc-360-script/yc-output"
        - name: tmp
          mountPath: "/tmp"
      - name: traffic-gen
        image: busybox:latest
        imagePullPolicy: Always
        command: ["/bin/sh", "-c"]
        args:
        - >-
          while true; do
            wget -q -O /dev/null http://localhost:9010/ 2>/dev/null || true;
            sleep $(( RANDOM % 3 + 1 ));
          done
        resources:
          requests:
            memory: 16Mi
            cpu: "10m"
          limits:
            memory: 32Mi
            cpu: "25m"
      - name: buggyapp
        image: ycrash/buggyapp:alpine
        imagePullPolicy: Always
        env:
        - name: APP_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app']
        - name: HOST_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        command: ["/bin/sh", "-c"]
        args:
        - >-
          java -Xms512m -Xmx1g -verbose:gc
          -Xlog:gc*:file=/opt/workspace/ba/logs/ba-gclog-%p.gc:time,uptime,level,tags
          -XX:+UnlockDiagnosticVMOptions
          -XX:+HeapDumpOnOutOfMemoryError
          -XX:HeapDumpPath=/opt/workspace/ba/logs/ba-heapdump-%p.hprof
          -XX:ErrorFile=/opt/workspace/ba/logs/ba-log-hs_err_pid-%p.log
          -jar webapp-runner.jar --port 9010 --access-log --access-log-pattern '%h %l %u %t %r %s %b %D' buggyapp.war
          2>&1 | tee /opt/workspace/ba/logs/app.log
        ports:
        - containerPort: 9010
        resources:
          requests:
            memory: 512Mi
            cpu: "200m"
          limits:
            memory: 1Gi
            cpu: "500m"
        volumeMounts:
        - name: tomcat-files
          mountPath: "/opt/workspace/ba/target"
        - name: ba-logs-pvc
          mountPath: "/opt/workspace/ba/logs"
        - name: tmp
          mountPath: "/tmp"
      volumes:
      - name: yc-config
        secret:
          secretName: yc-config
          items:
          - key: yc-config.yaml
            path: yc-config.yaml
      - name: tomcat-files
        emptyDir: {}
      - name: ba-logs-pvc
        persistentVolumeClaim:
          claimName: ba-logs-pvc
      - name: yc-workspace
        emptyDir: {}
      - name: tmp
        emptyDir: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

# buggyapp-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: buggyapp-service
  labels:
    app: yc-apps
  namespace: yc-apps
spec:
  selector:
    app: yc-apps
  ports:
    - protocol: TCP
      port: 9010
      targetPort: 9010
  type: ClusterIP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# yc-360-script-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: yc-360-script-service
  namespace: yc-apps
spec:
  selector:
    app: yc-apps
  ports:
    - protocol: TCP
      port: 8085
      targetPort: 8085
  type: ClusterIP
1
2
3
4
5
6
7
8
9
10
11
12
13

# buggyapp-ingress.yaml

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: buggyapp-route
  namespace: yc-apps
spec:
  to:
    kind: Service
    name: buggyapp-service
  port:
    targetPort: 9010
  tls:
    termination: edge
  wildcardPolicy: None
1
2
3
4
5
6
7
8
9
10
11
12
13
14