Tracing (“трасування”) дозволяє відстежувати запити між компонентами, тобто, наприклад, при використанні AWS і у Kubernetes ми можемо прослідкувати весь шлях запиту від AWS Load Balancer – до Kubernetes Pod – і до DynamoDB або RDS.
Це допомагає нам як відстежувати проблеми з performance – де і які запити виконуються довго – так і мати більше інформації при виникненні проблем, наприклад, коли наш API віддає клієнтам 500 помилки, і нам треба знайти в якому саме компоненті системи виникає проблема.
В AWS для трейсінгу існує є сервіс X-Ray, куди ми можемо відправляти дані за допомогою AWS X-Ray SDK for Python або AWS Distro for OpenTelemetry Python (або інших мов, але тут будемо говорити про Python).
AWS X-Ray до кожного запиту додає унікальний X-Ray ID і дозволяє будувати картину повного “маршруту” запиту.
Окрім X-Ray, в Kubernetes ми можемо трейсити за допомогою таких рішень як Jaeger або Zipkin, і потім будувати картину в Grafana Tempo.
Інше рішення – використовувати X-Ray Daemon, який ми можемо запустити в Kubernetes, і додати в Grafana плагін X-Ray. Див. приклади в Introducing the AWS X-Ray integration with Grafana.
Крім того, AWS Distro for OpenTelemetry теж працює з Trace ID, сумісними з AWS X-Ray – див. AWS Distro for OpenTelemetry and AWS X-Ray та Collecting traces from EKS with ADOT.
Проте сьогодні ми будемо додавати саме X-Ray коллектор, який створить Kubernetes DaemonSet та Kubernetes Service, в який Kubernetes Pods зможуть слати дані, які ми потім зможемо побачити або в AWS Console X-Ray, або в Grafana.
Зміст
AWS IAM
IAM Policy
Для доступу в AWS з подів з X-Ray нам потрібно створити IAM Role, яку ми потім будемо використовувати в ServiceAccount для X-Ray.
Ми все ще користуємось старим варіантом додавання IAM Role через ServiceAccounts, див. Kubernetes: ServiceAccount з AWS IAM Role для Kubernetes Pod, хоча нещодавно AWS анонсували Amazon EKS Pod Identity Agent add-on – див. AWS: EKS Pod Identities – заміна IRSA? Спрощуємо менеджмент IAM доступів.
Отже, створюємо IAM Policy з дозволами для запису в X-Ray:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords"
],
"Resource": [
"*"
]
}
]
}
Зберігаємо:
IAM Role
Далі додаємо IAM Role, яку зможе використовувати Kubernetes ServiceAccount.
Знаходимо Identity provider нашого EKS-кластеру:
Переходимо в IAM Role, додаємо нову роль.
В Trusted entity type вибираємо Web Identity, і в Web identity вибираємо Identity provider нашого EKS, в Audience – AWS STS:
Підключаємо створену вище політику:
Зберігаємо:
Запуск X-Ray Daemon в Kubernetes
Використаємо Helm-чарт okgolove/aws-xray.
Створюємо файл x-ray-values.yaml – див. дефолтні значення у values.yaml:
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::492***148:role/XRayAccessRole-test
xray:
region: us-east-1
loglevel: prod
Додаємо репозиторій:
$ helm repo add okgolove https://okgolove.github.io/helm-charts/
Встановлюємо чарт в кластер, який створить DaemonSet і Service:
$ helm -n ops-monitoring-ns install aws-xray okgolove/aws-xray -f x-ray-values.yaml
Перевіряємо поди:
$ kk get pod -l app.kubernetes.io/name=aws-xray NAME READY STATUS RESTARTS AGE aws-xray-5n2kt 0/1 Pending 0 41s aws-xray-6cwwf 1/1 Running 0 41s aws-xray-7dk67 1/1 Running 0 41s aws-xray-cq7xc 1/1 Running 0 41s aws-xray-cs54v 1/1 Running 0 41s aws-xray-mjxlm 0/1 Pending 0 41s aws-xray-rzcsz 1/1 Running 0 41s aws-xray-x5kb4 1/1 Running 0 41s aws-xray-xm9fk 1/1 Running 0 41s
Та Kubernetes Service:
$ kk get svc -l app.kubernetes.io/name=aws-xray NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE aws-xray ClusterIP None <none> 2000/UDP,2000/TCP 77s
Перевірка та робота з X-Ray
Створення Python Flask HTTP App з X-Ray
Створимо сервіс на Python Flask, який буде відповідати на HTTP-запити і логувати X-ray ID (ChatGPT промт – “Create a simple Python App with AWS X-Ray SDK for Python to run in Kubernetes. Add X-Ray ID output to requests“):
from flask import Flask
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.flask.middleware import XRayMiddleware
import logging
app = Flask(__name__)
# Configure AWS X-Ray
xray_recorder.configure(service='SimpleApp')
XRayMiddleware(app, xray_recorder)
# Set up basic logging
logging.basicConfig(level=logging.INFO)
@app.route('/')
def hello():
# Retrieve the current X-Ray segment
segment = xray_recorder.current_segment()
# Get the trace ID from the current segment
trace_id = segment.trace_id if segment else 'No segment'
# Log the trace ID
logging.info(f"Responding to request with X-Ray trace ID: {trace_id}")
return f"Hello, X-Ray! Trace ID: {trace_id}\n"
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
Створюємо requirements.txt:
flask==2.0.1 werkzeug==2.0.0 aws-xray-sdk==2.7.0
Додаємо Dockerfile:
FROM python:3.8-slim COPY requirements.txt . RUN pip install --force-reinstall -r requirements.txt COPY app.py . CMD ["python", "app.py"]
Збираємо Docker-образ – тут використовується репозиторій в AWS ECR:
$ docker build -t 492***148.dkr.ecr.us-east-1.amazonaws.com/x-ray-test .
Логінимось в ECR:
$ aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 492***148.dkr.ecr.us-east-1.amazonaws.com
Пушимо образ:
$ docker push 492***148.dkr.ecr.us-east-1.amazonaws.com/x-ray-test
Запуск Flask App в Kubernetes
Створюємо маніфест з Kubernetes Deployment, Service та Ingress.
Для Ingress включаємо логування в AWS S3 бакет – з нього логи будуть збиратись до Grafana Loki, див. Grafana Loki: збираємо логи AWS LoadBalancer з S3 за допомогою Promtail Lambda.
Для Deployment задаємо змінну оточення AWS_XRAY_DAEMON_ADDRESS, в якій вказуємо Kubernetes Service нашого X-Ray Daemon:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
spec:
replicas: 2
selector:
matchLabels:
app: flask-app
template:
metadata:
labels:
app: flask-app
spec:
containers:
- name: flask-app
image: 492***148.dkr.ecr.us-east-1.amazonaws.com/x-ray-test
ports:
- containerPort: 5000
env:
- name: AWS_XRAY_DAEMON_ADDRESS
value: "aws-xray.ops-monitoring-ns.svc.cluster.local:2000"
- name: AWS_REGION
value: "us-east-1"
---
apiVersion: v1
kind: Service
metadata:
name: flask-app-service
spec:
selector:
app: flask-app
ports:
- protocol: TCP
port: 80
targetPort: 5000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: flask-app-ingress
annotations:
alb.ingress.kubernetes.io/scheme: "internet-facing"
alb.ingress.kubernetes.io/target-type: "ip"
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/load-balancer-attributes: access_logs.s3.enabled=true,access_logs.s3.bucket=ops-1-28-devops-monitoring-ops-alb-logs
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: flask-app-service
port:
number: 80
Деплоїмо, та перевіряємо Ingress/ALB:
$ kk get ingress NAME CLASS HOSTS ADDRESS PORTS AGE flask-app-ingress alb * k8s-default-flaskapp-25042181e0-298318111.us-east-1.elb.amazonaws.com 80 10m
Робимо запит до ендпоінту:
$ curl k8s-default-flaskapp-25042181e0-298318111.us-east-1.elb.amazonaws.com Hello, X-Ray! Trace ID: 1-65e1d287-5fc6f0f34b4fb2120da8bbec
І бачимо X-Ray ID. Чудово.
Його ж бачимо в логах Load Balancer:
І в самому X-Ray:
Правда, я все ж очікував, що Load Balancer теж буде в мапі запиту – але ні.
Grafana X-Ray data source
Додаємо новий Data source:
Налаштовуємо доступ до AWS – тут просто з ACCESS та SECRET ключами (див. документацію X-Ray):
І тепер маємо новий data source в Explore:
Та новий тип візуалізації – Traces:
І десь вже окремим постом мабуть опишу побудову реальної дашборди з використанням X-Ray.










