Skip to content

Commit df09a04

Browse files
committed
Initial commit
0 parents  commit df09a04

21 files changed

+544
-0
lines changed

Dockerfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Use an official Python runtime as the base image.
2+
FROM python:3.9-slim
3+
4+
# Set environment variables
5+
ENV PYTHONDONTWRITEBYTECODE 1
6+
ENV PYTHONUNBUFFERED 1
7+
8+
# Set the working directory to /app inside the container.
9+
WORKDIR /app
10+
11+
# Copy the requirements file into the container.
12+
COPY requirements.txt .
13+
14+
# Install the required packages.
15+
RUN pip install --upgrade pip && \
16+
pip install --no-cache-dir -r requirements.txt
17+
18+
# Copy the rest of the application code into the container.
19+
COPY . .
20+
21+
# Expose the port that the app runs on.
22+
EXPOSE 5000
23+
24+
# Set the environment variable to tell Flask it's in production mode if needed (optional).
25+
ENV FLASK_ENV production
26+
27+
# Set the default command to run the Flask app.
28+
CMD ["flask", "run", "--host=0.0.0.0"]

README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# 🚀 **Module 5: Using Red Hat build of OpenTelemetry**
2+
3+
**Technology Stack:**
4+
5+
- Python
6+
- OpenTelemetry
7+
8+
---
9+
10+
## 🎯 **Scenario**
11+
12+
We will explore the Kubernetes Sidecar design pattern which deploys an agent sidecar container within an application pod that sends traces to a centralized Grafana Tempo. The application will send tracing data to a collector agent (sidecar) that offloads responsibility by sending the data to a storage backend, in our case, the central Grafana Tempo instance.
13+
14+
Instrumentation is the process of adding observability code to an application. Auto instrumentation creates this tracing framework without significant code changes by automatically injecting and configuring auto-instrumentation libraries in a variety of supported languages. Auto instrumentation of .NET sends data on port 4318 via the OTLP/HTTP protocol.
15+
16+
Inside your workspace is a Python Application that listens at `/api/check` for web requests and returns an HTTP 200 or 500 status code based on the payload.
17+
18+
From the Terminal, deploy the Python Application in your project using:
19+
20+
```sh
21+
oc new-build --binary --name workshop-<your username>
22+
oc start-build workshop-<your username> --from-dir=.
23+
oc new-app workshop-<your username> --name workshop-<your username>
24+
```
25+
26+
**NOTE: Please keep your application name unique from others in the workshop, otherwise you won’t be able to find your web requests in Jaeger UI.**
27+
28+
---
29+
30+
## 🐾 **Guided Walkthrough**
31+
32+
1. Deploy the sidecar with the OpenTelemetryCollector sidecar manifest:
33+
34+
```sh
35+
oc apply -f manifests/sidecar.yaml
36+
```
37+
38+
2. Create an Instrumentation manifest in the project that will be used by the OpenTelemetry operator:
39+
40+
```sh
41+
oc apply -f manifests/instrumentation.yaml
42+
```
43+
44+
3. Configure your deployment with annotations for .NET auto instrumentation:
45+
46+
```sh
47+
oc edit deployment workshop-<your username>
48+
49+
spec:
50+
template:
51+
metadata:
52+
annotations:
53+
..
54+
instrumentation.opentelemetry.io/inject-python: "true"
55+
sidecar.opentelemetry.io/inject: sidecar
56+
```
57+
58+
---
59+
60+
## 🧩 **Challenge**
61+
62+
- [ ] There is a cronjob at `curl-cron/cronjob.yaml` that will poll the application at service port 5000 every minute.
63+
- Modify the environment variable `ENDPOINT` to match the service name `workshop-<your username>` and deploy it with `oc apply -f curl-cron/cronjob.yaml`
64+
- [ ] A centralized Grafana Tempo instance has been deployed for the workshop. In OpenShift web console, navigate to the Applications Menu -> Jaeger UI to view the web requests.
65+
- [ ] The cronjob polling the application returns an HTTP 500. Fix the application so that it returns HTTP 200.
66+
- [ ] (Optional) To generate additional web traffic, without waiting 1 minute for the cronjob to kickoff, we have provided a shell script that will randomly generate 20 HTTP POST requests to your service. To run this in the terminal of your Dev Space, run the following:
67+
68+
```sh
69+
sh traffic-generator.sh workshop-<your username>:5000
70+
```
71+
72+
- [ ] You can create a new build of the application with the following command:
73+
74+
```sh
75+
oc start-build workshop-<your username> --from-dir=.
76+
```
77+
78+
---
79+
80+
## 🥚 **Easter Eggs!**
81+
82+
- [ ] There is an easter egg in Jaeger
83+
84+
---
85+
86+
## **Key Takeaways**
87+
88+
- Explored Kubernetes Sidecar design pattern
89+
- Auto-instrumented application to collect tracing data
90+
- Generated application traffic to produce tracing data
91+
- Used tracing data to troubleshoot application

app.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from flask import Flask
2+
from dotenv import load_dotenv
3+
import os
4+
5+
# Load environment variables
6+
load_dotenv()
7+
8+
app = Flask(__name__)
9+
from routes.main import main as main_blueprint
10+
11+
app.register_blueprint(main_blueprint)

catalog-info.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: backstage.io/v1alpha1
2+
kind: Component
3+
metadata:
4+
name: workshop-module5-python
5+
title: Module 5 - Python
6+
description: |
7+
Using Red Hat build of OpenTelemetry
8+
annotations:
9+
backstage.io/techdocs-ref: dir:.
10+
tags:
11+
- opentelemetry
12+
- python
13+
spec:
14+
type: module
15+
lifecycle: production
16+
owner: group:default/cluster-admins
17+
subcomponentOf: component:default/workshop-repository

curl-cron/Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Dockerfile
2+
FROM registry.access.redhat.com/ubi8/ubi-minimal
3+
4+
ENV ENDPOINT localhost:5000
5+
6+
# Install bash and curl
7+
USER root
8+
RUN microdnf install bash curl && \
9+
microdnf clean all
10+
11+
# Copy the script into the container at /opt
12+
COPY api-check.sh /opt/api-check.sh
13+
RUN chmod +x /opt/api-check.sh
14+
15+
# Set the default command to run the script
16+
ENTRYPOINT /opt/api-check.sh $ENDPOINT

curl-cron/api-check.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
# curl_random.sh
3+
# Randomly send either a valid or an invalid POST request to /api/check
4+
5+
if [ "$#" -ne 1 ]; then
6+
echo "Usage: ./api_check.sh host:port (i.e. localhost:5000)" >&2
7+
exit 1
8+
fi
9+
10+
# Generate a random number: either 0 or 1.
11+
if [ $(( RANDOM % 2 )) -eq 0 ]; then
12+
echo "$(date): Sending valid request"
13+
# Valid request: includes the required "musthave" key in JSON.
14+
curl -s -X POST -H "Content-Type: application/json" \
15+
-d '{ "customerName" : "ACME", "dateOfTransaction" : "04/17/2025", "amount": 30000 }' \
16+
http://$1/api/check -v
17+
echo "" # Optional: adds a newline for clarity.
18+
else
19+
echo "$(date): Sending invalid request"
20+
# Invalid request: missing the "musthave" key.
21+
curl -s -X POST -H "Content-Type: application/json" \
22+
-d '{ "customerName" : "ACME", "dateOfTransaction" : "04/17/2025", "amount": 20000 }' \
23+
http://$1/api/check -v
24+
echo ""
25+
fi

curl-cron/cronjob.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: batch/v1
2+
kind: CronJob
3+
metadata:
4+
name: module5-curl
5+
spec:
6+
# Runs every minute (adjust to "*/1 * * * *")
7+
schedule: "*/1 * * * *"
8+
jobTemplate:
9+
spec:
10+
template:
11+
spec:
12+
containers:
13+
- name: module5-curl-random
14+
env:
15+
- name: ENDPOINT
16+
### REPLACE THIS VALUE WITH YOUR UNIQUE SERVICE NAME i.e. ocp-workshop-<your username> ###
17+
value: <REPLACEME>:5000
18+
### REPLACE THIS VALUE WITH YOUR CLUSTER DOMAIN NAME ###
19+
image: default-route-openshift-image-registry.apps.<REPLACEME>/openshift/module5-curl:latest
20+
# Optional: if your script requires no parameters,
21+
# you can rely on the CMD set in the image.
22+
# Otherwise, you can override with:
23+
# command: ["/bin/bash", "/opt/curl-cron.sh"]
24+
restartPolicy: OnFailure

devfile.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
schemaVersion: 2.2.2
2+
metadata:
3+
name: workshop-module5-python
4+
version: 1.0.0
5+
description: DevSpaces workspace for Python app
6+
attributes:
7+
che-editor: vscode
8+
components:
9+
- container:
10+
args:
11+
- tail
12+
- -f
13+
- /dev/null
14+
endpoints:
15+
- name: https-python
16+
protocol: https
17+
targetPort: 5000
18+
- exposure: none
19+
name: debug
20+
targetPort: 5858
21+
env:
22+
- name: DEBUG_PORT
23+
value: "5858"
24+
image: image-registry.openshift-image-registry.svc.cluster.local:5000/openshift/devspaces-dotnet-python:latest
25+
mountSources: true
26+
name: py
27+
28+
commands:
29+
- exec:
30+
commandLine: pip install -r requirements.txt
31+
component: py
32+
group:
33+
isDefault: true
34+
kind: build
35+
workingDir: ${PROJECT_SOURCE}
36+
id: pip-install-requirements
37+
- exec:
38+
commandLine: flask run --host=0.0.0.0 --port=5000
39+
component: py
40+
group:
41+
isDefault: true
42+
kind: run
43+
workingDir: ${PROJECT_SOURCE}
44+
id: run-python

docs/index.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# 🚀 **Module 5: Using Red Hat build of OpenTelemetry**
2+
3+
**Technology Stack:**
4+
5+
- Python
6+
- OpenTelemetry
7+
8+
---
9+
10+
## 🎯 **Scenario**
11+
12+
We will explore the Kubernetes Sidecar design pattern which deploys an agent sidecar container within an application pod that sends traces to a centralized Grafana Tempo. The application will send tracing data to a collector agent (sidecar) that offloads responsibility by sending the data to a storage backend, in our case, the central Grafana Tempo instance.
13+
14+
Instrumentation is the process of adding observability code to an application. Auto instrumentation creates this tracing framework without significant code changes by automatically injecting and configuring auto-instrumentation libraries in a variety of supported languages. Auto instrumentation of .NET sends data on port 4318 via the OTLP/HTTP protocol.
15+
16+
Inside your workspace is a Python Application that listens at `/api/check` for web requests and returns an HTTP 200 or 500 status code based on the payload.
17+
18+
From the Terminal, deploy the Python Application in your project using:
19+
20+
```sh
21+
oc new-build --binary --name workshop-<your username>
22+
oc start-build workshop-<your username> --from-dir=.
23+
oc new-app workshop-<your username> --name workshop-<your username>
24+
```
25+
26+
**NOTE: Please keep your application name unique from others in the workshop, otherwise you won’t be able to find your web requests in Jaeger UI.**
27+
28+
---
29+
30+
## 🐾 **Guided Walkthrough**
31+
32+
1. Deploy the sidecar with the OpenTelemetryCollector sidecar manifest:
33+
34+
```sh
35+
oc apply -f manifests/sidecar.yaml
36+
```
37+
38+
2. Create an Instrumentation manifest in the project that will be used by the OpenTelemetry operator:
39+
40+
```sh
41+
oc apply -f manifests/instrumentation.yaml
42+
```
43+
44+
3. Configure your deployment with annotations for .NET auto instrumentation:
45+
46+
```sh
47+
oc edit deployment workshop-<your username>
48+
49+
spec:
50+
template:
51+
metadata:
52+
annotations:
53+
..
54+
instrumentation.opentelemetry.io/inject-python: "true"
55+
sidecar.opentelemetry.io/inject: sidecar
56+
```
57+
58+
---
59+
60+
## 🧩 **Challenge**
61+
62+
- [ ] There is a cronjob at `curl-cron/cronjob.yaml` that will poll the application at service port 5000 every minute.
63+
- Modify the environment variable `ENDPOINT` to match the service name `workshop-<your username>` and deploy it with `oc apply -f curl-cron/cronjob.yaml`
64+
- [ ] A centralized Grafana Tempo instance has been deployed for the workshop. In OpenShift web console, navigate to the Applications Menu -> Jaeger UI to view the web requests.
65+
- [ ] The cronjob polling the application returns an HTTP 500. Fix the application so that it returns HTTP 200.
66+
- [ ] (Optional) To generate additional web traffic, without waiting 1 minute for the cronjob to kickoff, we have provided a shell script that will randomly generate 20 HTTP POST requests to your service. To run this in the terminal of your Dev Space, run the following:
67+
68+
```sh
69+
sh traffic-generator.sh workshop-<your username>:5000
70+
```
71+
72+
- [ ] You can create a new build of the application with the following command:
73+
74+
```sh
75+
oc start-build workshop-<your username> --from-dir=.
76+
```
77+
78+
---
79+
80+
## 🥚 **Easter Eggs!**
81+
82+
- [ ] There is an easter egg in Jaeger
83+
84+
---
85+
86+
## **Key Takeaways**
87+
88+
- Explored Kubernetes Sidecar design pattern
89+
- Auto-instrumented application to collect tracing data
90+
- Generated application traffic to produce tracing data
91+
- Used tracing data to troubleshoot application

manifests/instrumentation.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: Instrumentation
3+
metadata:
4+
name: instrumentation
5+
spec:
6+
exporter:
7+
endpoint: http://tempo-sample-distributor.observability.svc.cluster.local:4318
8+
sampler:
9+
type: always_on
10+
python:

0 commit comments

Comments
 (0)