From ab77787a21bdc72ea7d38da9a580c7f1b4e1a0b7 Mon Sep 17 00:00:00 2001 From: demo-bot Date: Fri, 17 Apr 2026 11:21:34 +0000 Subject: [PATCH] feat: add service discovery, OTel instrumentation, and k6 load tests --- overlays/deploy/k6-configmap.yaml | 59 +++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 overlays/deploy/k6-configmap.yaml diff --git a/overlays/deploy/k6-configmap.yaml b/overlays/deploy/k6-configmap.yaml new file mode 100644 index 0000000..bde0f88 --- /dev/null +++ b/overlays/deploy/k6-configmap.yaml @@ -0,0 +1,59 @@ +# FALLBACK ConfigMap. +# This static skeleton is only used when The Watcher agent fails to generate +# a bespoke k6 script. When generation succeeds, the agent produces a custom +# ConfigMap containing the tailored load-test.js that replaces this file in +# the scaffolded output repository. +apiVersion: v1 +kind: ConfigMap +metadata: + name: k6-test-${{ values.component_id }} + namespace: ${{ values.destination_namespace }} + labels: + app: ${{ values.component_id }} + app.kubernetes.io/managed-by: backstage + app.kubernetes.io/component: load-testing +data: + K6_OUT: "opentelemetry" + K6_OTEL_GRPC_EXPORTER_INSECURE: "true" + K6_OTEL_GRPC_EXPORTER_ENDPOINT: "otel-collector.monitoring.svc.cluster.local:4317" + K6_OTEL_METRIC_PREFIX: "k6_" + K6_OTEL_FLUSH_INTERVAL: "1000" + K6_OTEL_EXPORT_INTERVAL: "5000" + K6_OTEL_SERVICE_NAME: "k6-${{ values.component_id }}" + load-test.js: | + import http from 'k6/http'; + import { check, sleep } from 'k6'; + + const vus = parseInt(__ENV.TEST_VUS || '10'); + const duration = __ENV.TEST_DURATION || '30s'; + const targetUrl = __ENV.TARGET_URL || 'http://localhost'; + + export const options = { + scenarios: { + load_test: { + executor: 'ramping-vus', + startVUs: 0, + stages: [ + { duration: '10s', target: vus }, + { duration: duration, target: vus }, + { duration: '5s', target: 0 }, + ], + }, + }, + thresholds: { + http_req_duration: ['p(95)<500'], + http_req_failed: ['rate<0.075'], + }, + }; + + // Treat 2xx and 3xx responses as expected (redirects won't inflate http_req_failed) + http.setResponseCallback(http.expectedStatuses({ min: 200, max: 399 })); + + export default function () { + const res = http.get(targetUrl); + check(res, { + 'status is 200': (r) => r.status === 200, + 'response time < 500ms': (r) => r.timings.duration < 500, + }); + sleep(0.5); + }