You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wa...@apache.org on 2026/10/15 06:11:15 UTC
(skywalking-showcase) branch feat/otlp-trace-astronomy-shop created (now 99efef5)
This is an automated email from the ASF dual-hosted git repository.
wankai123 pushed a change to branch feat/otlp-trace-astronomy-shop
in repository https://gitbox.apache.org/repos/asf/skywalking-showcase.git
at 99efef5 Trace the otlp-trace feature with the OpenTelemetry Astronomy Shop
This branch includes the following new commits:
new 99efef5 Trace the otlp-trace feature with the OpenTelemetry Astronomy Shop
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(skywalking-showcase) 01/01: Trace the otlp-trace feature with the OpenTelemetry Astronomy Shop
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
wankai123 pushed a commit to branch feat/otlp-trace-astronomy-shop
in repository https://gitbox.apache.org/repos/asf/skywalking-showcase.git
commit 99efef5b560a6a6b01114bb206268d69f40a7852
Author: wankai123 <wa...@foxmail.com>
AuthorDate: Thu Oct 15 14:11:08 2026 +0800
Trace the otlp-trace feature with the OpenTelemetry Astronomy Shop
The otlp-trace feature no longer runs a second copy of the music application: OpenTelemetry-only code
would have had to go into services the SkyWalking-agent copy shares. It runs the OpenTelemetry
Astronomy Shop instead, whose services are instrumented by the OpenTelemetry SDKs, with its collector
sending every span to the OAP. Its Postgres, Valkey and Kafka calls feed the OTLP virtual database,
cache and MQ layers.
On Docker Compose the demo is transcribed from its own 3.1.0 compose files on its own network, without
its Jaeger, Grafana, Prometheus, OpenSearch, feature-flag UI and docs site; the storefront is published
on 8088. Its init.sql, flag definitions and product-catalog SDK config are copied unchanged, and its
collector config is replaced by one that sends traces to the OAP and drops metrics and logs. On
Kubernetes the demo's Helm chart is installed by the Makefile as its own release in the otel-demo
namespace, since its services take fixed names, with the same parts off and the collector config
replaced through alternateConfig.
The OAP moves to a master image with the Trace Analysis Language, which builds the OTLP layers, and the
UI to a Horizon image with their dashboards. skywalking-helm moves to d6d0344, whose fresh installs
carry only the Kubernetes recommended labels, so the cilium policies match OAP and Satellite by both
label styles.
Also fixed on the way: the Docker music-application services are named agent::*, as on Kubernetes, so
recommendation no longer shares a service with the Astronomy Shop's; ActiveMQ's `expose` lists a
container port, which Compose v2.3x+ rejects as `1616:1616`; and the recommendation image reinstalls
apache-skywalking 1.2.0 from PyPI, since the agent wheel in apache/skywalking-python's 1.2.0 image
lacks skywalking.protocol and the agent never started.
---
.licenserc.yaml | 3 +
Makefile.in | 17 +-
.../platform/config/opentelemetry-demo/values.yaml | 108 +++
.../docker/config/apisix-otlp-trace/apisix.yaml | 41 --
.../docker/config/apisix-otlp-trace/config.yaml | 41 --
.../config/opentelemetry-demo/demo.flagd.json | 201 ++++++
.../docker/config/opentelemetry-demo/init.sql | 94 +++
.../opentelemetry-demo/otel-collector-config.yaml | 54 ++
.../config/opentelemetry-demo/otel-config.yml | 37 +
deploy/platform/docker/docker-compose.agent.yaml | 14 +-
.../platform/docker/docker-compose.otlp-trace.yaml | 750 +++++++++++++++++----
deploy/platform/kubernetes/Chart.yaml | 2 +-
deploy/platform/kubernetes/Makefile | 19 +-
deploy/platform/kubernetes/Makefile.in | 4 +
.../templates/feature-ciilum/policy.yaml | 46 ++
.../templates/feature-otlp-trace/resources.yaml | 492 --------------
deploy/platform/kubernetes/values.yaml | 12 -
docs/readme.md | 2 +-
services/recommendation-service/Dockerfile | 3 +
19 files changed, 1203 insertions(+), 737 deletions(-)
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 87a7fd8..a8b5b30 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -31,5 +31,8 @@ header:
- '**/gradlew.bat'
- 'LICENSE'
- 'NOTICE'
+ # The OpenTelemetry Astronomy Shop's own files, copied unchanged; they carry the OpenTelemetry Authors' Apache-2.0 header.
+ - 'deploy/platform/docker/config/opentelemetry-demo/init.sql'
+ - 'deploy/platform/docker/config/opentelemetry-demo/otel-config.yml'
comment: on-failure
diff --git a/Makefile.in b/Makefile.in
index a025ee2..4e53427 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -37,11 +37,13 @@ ES_IMAGE ?= docker.elastic.co/elasticsearch/elasticsearch-oss
ES_IMAGE_TAG ?= 7.10.2
SW_OAP_IMAGE ?= ghcr.io/apache/skywalking/oap
-# banyandb-tail-sampling needs the bydb.yml `pipeline` block, which lands in c66a476a (#13965).
-SW_OAP_IMAGE_TAG ?= 03ecf41fd7ac34635370c91e2bf01e0424fa85eb
+# banyandb-tail-sampling needs the bydb.yml `pipeline` block, which lands in c66a476a (#13965); otlp-trace needs the
+# Trace Analysis Language, which lands in 7f6a353a (#14129), for the OTLP layers.
+SW_OAP_IMAGE_TAG ?= cf1c2be22c6ac8c85910de5199f2ce655161c0ad
SW_UI_IMAGE ?= ghcr.io/apache/skywalking-horizon-ui
-SW_UI_IMAGE_TAG ?= dc31135cadee387263931f359819e7a8c7971bdc
+# otlp-trace needs the OpenTelemetry layer dashboards, which land in f3e3f193 (#193).
+SW_UI_IMAGE_TAG ?= 1401336608215a6dfbcaafbb6d80a4a5d927bd0e
# The AI Sessionizer. No real Claude Code runs in the showcase, so its scenario feed is the
# only traffic of the AI_AGENT layer.
@@ -74,10 +76,11 @@ GRAFANA_IMAGE ?= grafana/grafana:12.4.2
OTEL_COLLECTOR_IMAGE ?= otel/opentelemetry-collector
OTEL_COLLECTOR_IMAGE_TAG ?= 0.102.1
-# @feature: otlp-trace; the OpenTelemetry Operator's auto-instrumentation images, copied into the music application's containers at start
-OTEL_INSTRUMENTATION_JAVA_IMAGE ?= ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.11.0
-OTEL_INSTRUMENTATION_NODEJS_IMAGE ?= ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:0.56.0
-OTEL_INSTRUMENTATION_PYTHON_IMAGE ?= ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:0.50b0
+# @feature: otlp-trace; the OpenTelemetry Astronomy Shop. Its images are tagged <version>-<service>; the chart's version
+# is the one whose appVersion is OTEL_DEMO_IMAGE_TAG.
+OTEL_DEMO_IMAGE ?= ghcr.io/open-telemetry/demo
+OTEL_DEMO_IMAGE_TAG ?= 3.1.0
+OTEL_DEMO_CHART_VERSION ?= 0.42.4
SW_R3_IMAGE ?= ghcr.io/skyapm/r3
SW_R3_IMAGE_TAG ?= 0.1.0
diff --git a/deploy/platform/config/opentelemetry-demo/values.yaml b/deploy/platform/config/opentelemetry-demo/values.yaml
new file mode 100644
index 0000000..2d0c017
--- /dev/null
+++ b/deploy/platform/config/opentelemetry-demo/values.yaml
@@ -0,0 +1,108 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# @feature: otlp-trace; values for the OpenTelemetry Astronomy Shop chart
+# (oci://ghcr.io/open-telemetry/opentelemetry-helm-charts/opentelemetry-demo), installed by the kubernetes Makefile as
+# its own release in its own namespace. The image and the OAP address the collector exports to are set there.
+#
+# The demo's own observability backends and its AI and docs components are off; its collector sends every span to the
+# OAP, and accepts and drops the metrics and logs the services also send.
+
+components:
+ agent:
+ enabled: false
+ chatbot:
+ enabled: false
+ mcp:
+ enabled: false
+ telemetry-docs:
+ enabled: false
+
+jaeger:
+ enabled: false
+prometheus:
+ enabled: false
+grafana:
+ enabled: false
+opensearch:
+ enabled: false
+
+opentelemetry-collector:
+ # One collector for the whole demo; the chart's default daemonset and its node and cluster metrics need cluster-wide
+ # permissions that a trace feed does not.
+ mode: deployment
+ presets:
+ annotationDiscovery:
+ metrics:
+ enabled: false
+ clusterMetrics:
+ enabled: false
+ hostMetrics:
+ enabled: false
+ kubeletMetrics:
+ enabled: false
+ kubernetesAttributes:
+ enabled: false
+ command:
+ extraArgs: []
+ # Replaces the demo's collector config instead of merging into it, which would keep its exporters to the backends
+ # turned off above.
+ alternateConfig:
+ receivers:
+ otlp:
+ protocols:
+ grpc:
+ endpoint: ${env:MY_POD_IP}:4317
+ http:
+ endpoint: ${env:MY_POD_IP}:4318
+ # The storefront page sends its browser spans through frontend-proxy's /otlp-http route.
+ cors:
+ allowed_origins:
+ - "http://*"
+ - "https://*"
+ processors:
+ memory_limiter:
+ check_interval: 5s
+ limit_percentage: 80
+ spike_limit_percentage: 25
+ exporters:
+ otlp_grpc/oap:
+ # Set by the Makefile to the showcase OAP's gRPC port.
+ endpoint: ""
+ tls:
+ insecure: true
+ sending_queue:
+ batch: {}
+ nop: {}
+ extensions:
+ health_check:
+ endpoint: ${env:MY_POD_IP}:13133
+ service:
+ extensions: [ health_check ]
+ pipelines:
+ traces:
+ receivers: [ otlp ]
+ processors: [ memory_limiter ]
+ exporters: [ otlp_grpc/oap ]
+ metrics:
+ receivers: [ otlp ]
+ processors: [ memory_limiter ]
+ exporters: [ nop ]
+ logs:
+ receivers: [ otlp ]
+ processors: [ memory_limiter ]
+ exporters: [ nop ]
diff --git a/deploy/platform/docker/config/apisix-otlp-trace/apisix.yaml b/deploy/platform/docker/config/apisix-otlp-trace/apisix.yaml
deleted file mode 100644
index ed0981d..0000000
--- a/deploy/platform/docker/config/apisix-otlp-trace/apisix.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-apisix:
-
-# The two routes the page calls, traced by APISIX's opentelemetry plugin; the plugin's default sampler is always_off,
-# so each route turns it on. The static page is served by the nginx location in config.yaml and is not traced.
-routes:
- - uri: /homepage
- service_id: 1
- plugins:
- opentelemetry:
- sampler:
- name: always_on
- - uri: /test
- service_id: 1
- plugins:
- opentelemetry:
- sampler:
- name: always_on
-services:
- - id: 1
- upstream_id: 1
-upstreams:
- - id: 1
- nodes:
- "app:80": 1
- type: roundrobin
-#END
diff --git a/deploy/platform/docker/config/apisix-otlp-trace/config.yaml b/deploy/platform/docker/config/apisix-otlp-trace/config.yaml
deleted file mode 100644
index 435f7a6..0000000
--- a/deploy/platform/docker/config/apisix-otlp-trace/config.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-apisix:
-
-apisix:
- node_listen: 80
- enable_ipv6: false
- enable_admin: false
- config_center: yaml
-plugin_attr:
- opentelemetry:
- resource:
- service.name: frontend
- service.namespace: otel-services
- collector:
- address: oap:12800
- request_timeout: 3
-plugins:
- - opentelemetry
-nginx_config:
- # Two workers rather than one per CPU: the frontend proxies two routes and serves a static page, and APISIX's
- # default sizes the workers by the node, not by the container's memory limit.
- worker_processes: 2
- http_server_configuration_snippet: |
- location ~ \.(gif|jpg|png|js|css|html)$ {
- root /app/build;
- index index.html;
- }
diff --git a/deploy/platform/docker/config/opentelemetry-demo/demo.flagd.json b/deploy/platform/docker/config/opentelemetry-demo/demo.flagd.json
new file mode 100644
index 0000000..1b8ab34
--- /dev/null
+++ b/deploy/platform/docker/config/opentelemetry-demo/demo.flagd.json
@@ -0,0 +1,201 @@
+{
+ "$schema": "https://flagd.dev/schema/v0/flags.json",
+ "flags": {
+ "adFailure": {
+ "defaultVariant": "off",
+ "description": "Fail ad service",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "adHighCpu": {
+ "defaultVariant": "off",
+ "description": "Triggers high cpu load in the ad service",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "adManualGc": {
+ "defaultVariant": "off",
+ "description": "Triggers full manual garbage collections in the ad service",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "aiRunawayAgent": {
+ "defaultVariant": "off",
+ "description": "forces the agent to keep looping tool calls until it hits its recursion limit",
+ "state": "ENABLED",
+ "variants": {
+ "off": 0,
+ "on": 20
+ }
+ },
+ "aiSlowResponse": {
+ "defaultVariant": "off",
+ "description": "slow LLM responses in the agent service",
+ "state": "ENABLED",
+ "variants": {
+ "10sec": 10000,
+ "5sec": 5000,
+ "off": 0
+ }
+ },
+ "cartFailure": {
+ "defaultVariant": "off",
+ "description": "Fail cart service n% of the time",
+ "state": "ENABLED",
+ "variants": {
+ "10%": 0.1,
+ "100%": 1,
+ "25%": 0.25,
+ "50%": 0.5,
+ "75%": 0.75,
+ "90%": 0.9,
+ "off": 0
+ }
+ },
+ "emailMemoryLeak": {
+ "defaultVariant": "off",
+ "description": "Memory leak in the email service.",
+ "state": "ENABLED",
+ "variants": {
+ "10000x": 10000,
+ "1000x": 1000,
+ "100x": 100,
+ "10x": 10,
+ "1x": 1,
+ "off": 0
+ }
+ },
+ "emitRawPii": {
+ "defaultVariant": "off",
+ "description": "Emit raw PII attributes (user.email, demo.payment.card_number, demo.payment.card_cvv) from checkout and payment for the collector redaction example. Not a failure scenario -- controls PII emission, independent of collector-side redaction which always runs.",
+ "metadata": {
+ "schedulable": false
+ },
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "failedReadinessProbe": {
+ "defaultVariant": "off",
+ "description": "readiness probe failure for cart service",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "imageSlowLoad": {
+ "defaultVariant": "off",
+ "description": "slow loading images in the frontend",
+ "state": "ENABLED",
+ "variants": {
+ "10sec": 10000,
+ "5sec": 5000,
+ "off": 0
+ }
+ },
+ "intlShippingSlowdown": {
+ "defaultVariant": "off",
+ "description": "Delays international shipping responses to simulate overseas shipping delay",
+ "state": "ENABLED",
+ "variants": {
+ "10sec": 10,
+ "5sec": 5,
+ "off": 0
+ }
+ },
+ "kafkaQueueProblems": {
+ "defaultVariant": "off",
+ "description": "Overloads Kafka queue while simultaneously introducing a consumer side delay leading to a lag spike",
+ "state": "ENABLED",
+ "variants": {
+ "off": 0,
+ "on": 100
+ }
+ },
+ "loadGeneratorFloodHomepage": {
+ "defaultVariant": "off",
+ "description": "Flood the frontend with a large amount of requests.",
+ "state": "ENABLED",
+ "variants": {
+ "off": 0,
+ "on": 100
+ }
+ },
+ "paymentFailure": {
+ "defaultVariant": "off",
+ "description": "Fail payment service charge requests n%",
+ "state": "ENABLED",
+ "variants": {
+ "10%": 0.1,
+ "100%": 1,
+ "25%": 0.25,
+ "50%": 0.5,
+ "75%": 0.75,
+ "90%": 0.95,
+ "off": 0
+ }
+ },
+ "paymentUnreachable": {
+ "defaultVariant": "off",
+ "description": "Payment service is unavailable",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "productCatalogFailure": {
+ "defaultVariant": "off",
+ "description": "Fail product catalog service on a specific product",
+ "state": "ENABLED",
+ "targeting": {
+ "if": [
+ {
+ "==": [
+ {
+ "var": "product_id"
+ },
+ "OLJCESPC7Z"
+ ]
+ },
+ "off",
+ "off"
+ ]
+ },
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "productCatalogLockContention": {
+ "defaultVariant": "off",
+ "description": "Trigger lock contention on the product catalog database",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ },
+ "recommendationCacheFailure": {
+ "defaultVariant": "off",
+ "description": "Fail recommendation service cache",
+ "state": "ENABLED",
+ "variants": {
+ "off": false,
+ "on": true
+ }
+ }
+ }
+}
diff --git a/deploy/platform/docker/config/opentelemetry-demo/init.sql b/deploy/platform/docker/config/opentelemetry-demo/init.sql
new file mode 100644
index 0000000..b635cfe
--- /dev/null
+++ b/deploy/platform/docker/config/opentelemetry-demo/init.sql
@@ -0,0 +1,94 @@
+-- Copyright The OpenTelemetry Authors
+-- SPDX-License-Identifier: Apache-2.0
+
+-- Enable pg_stat_statements in the default postgres database
+CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
+
+-- Create application user
+CREATE USER astronomy_user WITH PASSWORD 'astronomy_password';
+
+-- Create application database
+CREATE DATABASE astronomy_db OWNER astronomy_user;
+
+-- Create monitoring user with pg_monitor role (visibility on all databases and schemas)
+CREATE USER monitoring_user WITH PASSWORD 'monitoring_password';
+GRANT pg_monitor TO monitoring_user;
+
+-- Switch to the application database
+\connect astronomy_db
+
+-- Enable pg_stat_statements in the application database
+CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
+
+-- Accounting Service: create a schema
+CREATE SCHEMA accounting;
+GRANT USAGE ON SCHEMA accounting TO astronomy_user;
+
+-- Accounting Service: create tables
+CREATE TABLE accounting."order" (
+ order_id TEXT PRIMARY KEY
+);
+
+CREATE TABLE accounting.shipping (
+ shipping_tracking_id TEXT PRIMARY KEY,
+ shipping_cost_currency_code TEXT NOT NULL,
+ shipping_cost_units BIGINT NOT NULL,
+ shipping_cost_nanos INT NOT NULL,
+ street_address TEXT,
+ city TEXT,
+ state TEXT,
+ country TEXT,
+ zip_code TEXT,
+ order_id TEXT NOT NULL,
+ FOREIGN KEY (order_id) REFERENCES accounting."order"(order_id) ON DELETE CASCADE
+);
+
+CREATE TABLE accounting.orderitem (
+ item_cost_currency_code TEXT NOT NULL,
+ item_cost_units BIGINT NOT NULL,
+ item_cost_nanos INT NOT NULL,
+ product_id TEXT NOT NULL,
+ quantity INT NOT NULL,
+ order_id TEXT NOT NULL,
+ PRIMARY KEY (order_id, product_id),
+ FOREIGN KEY (order_id) REFERENCES accounting."order"(order_id) ON DELETE CASCADE
+);
+
+-- Accounting Service: grant permission to schema
+GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA accounting TO astronomy_user;
+
+-- Product Catalog Service: create a schema
+CREATE SCHEMA catalog;
+GRANT USAGE ON SCHEMA catalog TO astronomy_user;
+
+-- Product Catalog Service: create tables
+CREATE TABLE catalog.products (
+ id TEXT PRIMARY KEY,
+ name TEXT NOT NULL,
+ description TEXT,
+ picture TEXT,
+ price_currency_code TEXT NOT NULL,
+ price_units BIGINT NOT NULL,
+ price_nanos INT NOT NULL,
+ categories TEXT
+);
+
+-- Product Catalog Service: grant permission to schema
+-- UPDATE is required to acquire the ACCESS EXCLUSIVE lock used by the
+-- productCatalogLockContention fault-injection flag; the service otherwise
+-- only reads from this schema.
+GRANT SELECT, UPDATE ON ALL TABLES IN SCHEMA catalog TO astronomy_user;
+
+-- Product Catalog Service: add product data
+INSERT INTO catalog.products (id, name, description, picture, price_currency_code, price_units, price_nanos, categories)
+VALUES
+ ('OLJCESPC7Z', 'National Park Foundation Explorascope', 'The National Park Foundation''s (NPF) Explorascope 60AZ is a manual alt-azimuth, refractor telescope perfect for celestial viewing on the go. The NPF Explorascope 60 can view the planets, moon, star clusters and brighter deep sky objects like the Orion Nebula and Andromeda Galaxy.', 'NationalParkFoundationExplorascope.jpg', 'USD', 101, 960000000, 'telescopes'),
+ ('66VCHSJNUP', 'Starsense Explorer Refractor Telescope', 'The first telescope that uses your smartphone to analyze the night sky and calculate its position in real time. StarSense Explorer is ideal for beginners thanks to the app''s user-friendly interface and detailed tutorials. It''s like having your own personal tour guide of the night sky', 'StarsenseExplorer.jpg', 'USD', 349, 950000000, 'telescopes'),
+ ('1YMWWN1N4O', 'Eclipsmart Travel Refractor Telescope', 'Dedicated white-light solar scope for the observer on the go. The 50mm refracting solar scope uses Solar Safe, ISO compliant, full-aperture glass filter material to ensure the safest view of solar events. The kit comes complete with everything you need, including the dedicated travel solar scope, a Solar Safe finderscope, tripod, a high quality 20mm (18x) Kellner eyepiece and a nylon backpack to carry everything in. This Trav [...]
+ ('L9ECAV7KIM', 'Lens Cleaning Kit', 'Wipe away dust, dirt, fingerprints and other particles on your lenses to see clearly with the Lens Cleaning Kit. This cleaning kit works on all glass and optical surfaces, including telescopes, binoculars, spotting scopes, monoculars, microscopes, and even your camera lenses, computer screens, and mobile devices. The kit comes complete with a retractable lens brush to remove dust particles and dirt and two options to clean smudges and fingerprint [...]
+ ('2ZYFJ3GM2N', 'Roof Binoculars', 'This versatile, all-around binocular is a great choice for the trail, the stadium, the arena, or just about anywhere you want a close-up view of the action without sacrificing brightness or detail. It''s an especially great companion for nature observation and bird watching, with ED glass that helps you spot the subtlest field markings and a close focus of just 6.5 feet.', 'RoofBinoculars.jpg', 'USD', 209, 950000000, 'binoculars'),
+ ('0PUK6V6EV0', 'Solar System Color Imager', 'You have your new telescope and have observed Saturn and Jupiter. Now you''re ready to take the next step and start imaging them. But where do you begin? The NexImage 10 Solar System Imager is the perfect solution.', 'SolarSystemColorImager.jpg', 'USD', 175, 0, 'accessories,telescopes'),
+ ('LS4PSXUNUM', 'Red Flashlight', 'This 3-in-1 device features a 3-mode red flashlight, a hand warmer, and a portable power bank for recharging your personal electronics on the go. Whether you use it to light the way at an astronomy star party, a night walk, or wildlife research, ThermoTorch 3 Astro Red''s rugged, IPX4-rated design will withstand your everyday activities.', 'RedFlashlight.jpg', 'USD', 57, 80000000, 'accessories,flashlights'),
+ ('9SIQT8TOJO', 'Optical Tube Assembly', 'Capturing impressive deep-sky astroimages is easier than ever with Rowe-Ackermann Schmidt Astrograph (RASA) V2, the perfect companion to today''s top DSLR or astronomical CCD cameras. This fast, wide-field f/2.2 system allows for shorter exposure times compared to traditional f/10 astroimaging, without sacrificing resolution. Because shorter sub-exposure times are possible, your equatorial mount won''t need to accurately track over extended pe [...]
+ ('6E92ZMYYFZ', 'Solar Filter', 'Enhance your viewing experience with EclipSmart Solar Filter for 8" telescopes. With two Velcro straps and four self-adhesive Velcro pads for added safety, you can be assured that the solar filter cannot be accidentally knocked off and will provide Solar Safe, ISO compliant viewing.', 'SolarFilter.jpg', 'USD', 69, 950000000, 'accessories,telescopes'),
+ ('HQTGWGPNH4', 'The Comet Book', 'A 16th-century treatise on comets, created anonymously in Flanders (now northern France) and now held at the Universitätsbibliothek Kassel. Commonly known as The Comet Book (or Kometenbuch in German), its full title translates as "Comets and their General and Particular Meanings, According to Ptolomeé, Albumasar, Haly, Aliquind and other Astrologers". The image is from https://publicdomainreview.org/collection/the-comet-book, made available by the Un [...]
\ No newline at end of file
diff --git a/deploy/platform/docker/config/opentelemetry-demo/otel-collector-config.yaml b/deploy/platform/docker/config/opentelemetry-demo/otel-collector-config.yaml
new file mode 100644
index 0000000..d743224
--- /dev/null
+++ b/deploy/platform/docker/config/opentelemetry-demo/otel-collector-config.yaml
@@ -0,0 +1,54 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# The Astronomy Shop's collector, in place of the demo's own: every span goes to the OAP over OTLP/gRPC. The demo's
+# services also export metrics and logs here; they are accepted and dropped, so no sender logs export errors.
+receivers:
+ otlp:
+ protocols:
+ grpc:
+ endpoint: 0.0.0.0:4317
+ http:
+ endpoint: 0.0.0.0:4318
+ # The storefront page sends its browser spans through frontend-proxy's /otlp-http route.
+ cors:
+ allowed_origins:
+ - "http://*"
+ - "https://*"
+
+processors:
+ batch:
+
+exporters:
+ otlp/oap:
+ endpoint: oap:11800
+ tls:
+ insecure: true
+ nop:
+
+service:
+ pipelines:
+ traces:
+ receivers: [ otlp ]
+ processors: [ batch ]
+ exporters: [ otlp/oap ]
+ metrics:
+ receivers: [ otlp ]
+ exporters: [ nop ]
+ logs:
+ receivers: [ otlp ]
+ exporters: [ nop ]
diff --git a/deploy/platform/docker/config/opentelemetry-demo/otel-config.yml b/deploy/platform/docker/config/opentelemetry-demo/otel-config.yml
new file mode 100644
index 0000000..2526521
--- /dev/null
+++ b/deploy/platform/docker/config/opentelemetry-demo/otel-config.yml
@@ -0,0 +1,37 @@
+# Copyright The OpenTelemetry Authors
+# SPDX-License-Identifier: Apache-2.0
+
+file_format: "1.0"
+disabled: false
+log_level: info
+logger_provider:
+ processors:
+ - batch:
+ exporter:
+ otlp_grpc:
+ endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}
+meter_provider:
+ readers:
+ - periodic:
+ exporter:
+ otlp_grpc:
+ endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}
+ temporality_preference: ${OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE:-cumulative}
+tracer_provider:
+ processors:
+ - batch:
+ exporter:
+ otlp_grpc:
+ endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}
+propagator:
+ composite:
+ - tracecontext:
+ - baggage:
+resource:
+ attributes_list: ${OTEL_RESOURCE_ATTRIBUTES}
+ detection/development:
+ detectors:
+ - container:
+ - host:
+ - process:
+ - service:
diff --git a/deploy/platform/docker/docker-compose.agent.yaml b/deploy/platform/docker/docker-compose.agent.yaml
index c069c11..bbee7ac 100644
--- a/deploy/platform/docker/docker-compose.agent.yaml
+++ b/deploy/platform/docker/docker-compose.agent.yaml
@@ -24,7 +24,7 @@ services:
networks: [ sw ]
privileged: true
environment:
- SW_AGENT_NAME: gateway
+ SW_AGENT_NAME: agent::gateway
SW_AGENT_COLLECTOR_BACKEND_SERVICES: ${BACKEND_SERVICE}:11800
healthcheck:
test: [ "CMD-SHELL", "curl http://localhost/actuator/health" ]
@@ -43,7 +43,7 @@ services:
privileged: true
networks: [ sw ]
environment:
- SW_AGENT_NAME: songs
+ SW_AGENT_NAME: agent::songs
SW_AGENT_COLLECTOR_BACKEND_SERVICES: ${BACKEND_SERVICE}:11800
ACTIVE_MQ_URL: tcp://activemq:61616
ACTIVE_MQ_QUEUE: queue-songs-ping
@@ -63,7 +63,7 @@ services:
image: ${HUB}/recommendation-service:${TAG}
networks: [ sw ]
environment:
- SW_AGENT_NAME: recommendation
+ SW_AGENT_NAME: agent::recommendation
SW_AGENT_COLLECTOR_BACKEND_SERVICES: ${BACKEND_SERVICE}:11800
healthcheck:
test: [ "CMD-SHELL", "curl http://localhost/health" ]
@@ -81,8 +81,8 @@ services:
ports:
- "9090:80"
environment:
- SW_AGENT_NAME_SERVER: app
- REACT_APP_SW_AGENT_NAME_UI: ui
+ SW_AGENT_NAME_SERVER: agent::app
+ REACT_APP_SW_AGENT_NAME_UI: agent::ui
SW_AGENT_COLLECTOR_BACKEND_SERVICES: ${BACKEND_SERVICE}:11800
healthcheck:
test: [ "CMD-SHELL", "curl http://localhost/health" ]
@@ -115,7 +115,7 @@ services:
ACTIVEMQ_SUNJMX_START: "-Dcom.sun.management.jmxremote.port=1616 -Dcom.sun.management.jmxremote.rmi.port=1616 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
ACTIVEMQ_BROKER_NAME: activemq-broker
expose:
- - 1616:1616
+ - "1616"
volumes:
- ./config/activemq/activemq.xml:/opt/activemq/conf/activemq.xml
networks: [ sw ]
@@ -130,7 +130,7 @@ services:
image: ${HUB}/rating-service:${TAG}
networks: [ sw ]
environment:
- SW_AGENT_NAME: rating
+ SW_AGENT_NAME: agent::rating
SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE: ${BACKEND_SERVICE}:11800
healthcheck:
test: [ "CMD-SHELL", "curl http://localhost/rating" ]
diff --git a/deploy/platform/docker/docker-compose.otlp-trace.yaml b/deploy/platform/docker/docker-compose.otlp-trace.yaml
index 7d85fcb..a132065 100644
--- a/deploy/platform/docker/docker-compose.otlp-trace.yaml
+++ b/deploy/platform/docker/docker-compose.otlp-trace.yaml
@@ -15,209 +15,703 @@
# specific language governing permissions and limitations
# under the License.
#
-# @feature: otlp-trace; a second copy of the music application from the agentless images, instrumented at start by the
-# OpenTelemetry auto-instrumentation (copied out of the operator's images into shared volumes) and exporting every span
-# straight to the OAP, which stores it natively and serves it at the TraceQL /otlp datasource. The copy lives on its own
-# network, where the aliases give the services the fixed hostnames they address each other by: frontend, gateway, songs,
-# rcmd, rating, app, activemq. The Go rating service has no runtime instrumentation and appears only as
-# recommendation's callee.
+# @feature: otlp-trace; the OpenTelemetry Astronomy Shop (https://github.com/open-telemetry/opentelemetry-demo), whose
+# services are instrumented by the OpenTelemetry SDKs and send every span through a collector to the OAP, which stores
+# it natively and serves it at the TraceQL /otlp datasource. Its Postgres, Valkey and Kafka calls feed the OTLP virtual
+# database, cache and MQ layers.
+#
+# Transcribed from the demo's compose.yaml and compose.full.yaml at the tag OTEL_DEMO_IMAGE_TAG names, without the
+# demo's own Jaeger, Grafana, Prometheus and OpenSearch, its feature-flag UI and its docs site. The files under
+# config/opentelemetry-demo are the demo's, unchanged, except the collector config. The services live on their own
+# network, where the aliases give them the hostnames the demo addresses them by.
version: '2.1'
-# Every span goes straight to the OAP; no collector sits in the trace path. The OAP serves OTLP on both of its
-# own ports, gRPC on 11800 and OTLP/HTTP on 12800, so each sender uses the transport its instrumentation has.
-x-otel-export: &otel-export
- OTEL_TRACES_EXPORTER: otlp
- OTEL_METRICS_EXPORTER: none
- OTEL_LOGS_EXPORTER: none
- OTEL_RESOURCE_ATTRIBUTES: service.namespace=otel-services
-x-otel-grpc: &otel-grpc
- OTEL_EXPORTER_OTLP_PROTOCOL: grpc
- OTEL_EXPORTER_OTLP_ENDPOINT: http://oap:11800
-# The Python auto-instrumentation image carries no gRPC exporter, so it goes over OTLP/HTTP.
-x-otel-http: &otel-http
- OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
- OTEL_EXPORTER_OTLP_ENDPOINT: http://oap:12800
+x-otel-demo-env: &otel-demo-env
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: cumulative
+ OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION: explicit_bucket_histogram
+ FLAGD_HOST: flagd
+ FLAGD_PORT: 8013
+# Each SDK uses the transport the demo configures it with: gRPC on 4317, or OTLP/HTTP on 4318.
+x-otel-demo-grpc: &otel-demo-grpc
+ OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
+x-otel-demo-http: &otel-demo-http
+ OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4318
services:
- # The OAP joins this copy's network so the services can reach it by name. Only the OAP crosses over: the copy
- # keeps its own network because its services answer to the same hostnames as the agent copy on `sw`.
+ # The OAP joins the demo's network so its collector can reach it by name.
oap:
- networks: [ sw, otel ]
+ networks: [ sw, otel-demo ]
- otel-instrumentation-java:
- image: ${OTEL_INSTRUMENTATION_JAVA_IMAGE}
- command: [ "cp", "/javaagent.jar", "/otel/javaagent.jar" ]
- volumes:
- - otel-java:/otel
- otel-instrumentation-nodejs:
- image: ${OTEL_INSTRUMENTATION_NODEJS_IMAGE}
- command: [ "cp", "-r", "/autoinstrumentation/.", "/otel" ]
+ otel-demo-collector:
+ image: ${OTEL_COLLECTOR_IMAGE}:${OTEL_COLLECTOR_IMAGE_TAG}
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ otel-collector ]
+ command: [ "--config=/etc/otel-collector-config.yaml" ]
volumes:
- - otel-nodejs:/otel
- otel-instrumentation-python:
- image: ${OTEL_INSTRUMENTATION_PYTHON_IMAGE}
- command: [ "cp", "-r", "/autoinstrumentation/.", "/otel" ]
+ - ./config/opentelemetry-demo/otel-collector-config.yaml:/etc/otel-collector-config.yaml
+ deploy:
+ resources:
+ limits:
+ memory: 200M
+ depends_on:
+ oap:
+ condition: service_healthy
+
+ otel-demo-flagd:
+ image: ghcr.io/open-feature/flagd:v0.16.0
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ flagd ]
+ command: [ "start", "--uri", "file:./etc/flagd/demo.flagd.json" ]
+ environment:
+ <<: *otel-demo-http
+ OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
+ GOMEMLIMIT: 60MiB
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: flagd
volumes:
- - otel-python:/otel
+ - ./config/opentelemetry-demo/demo.flagd.json:/etc/flagd/demo.flagd.json
+ deploy:
+ resources:
+ limits:
+ memory: 75M
- otel-gateway:
+ otel-demo-astronomy-db:
+ image: postgres:18.4
restart: unless-stopped
- image: ${HUB}/gateway-service:${TAG}-agentless
networks:
- otel:
- aliases: [ gateway ]
+ otel-demo:
+ aliases: [ astronomy-db ]
+ command: postgres -c shared_preload_libraries=pg_stat_statements
environment:
- <<: [ *otel-export, *otel-grpc ]
- OTEL_SERVICE_NAME: gateway
- JAVA_TOOL_OPTIONS: -javaagent:/otel/javaagent.jar
+ POSTGRES_PASSWORD: changeit
volumes:
- - otel-java:/otel:ro
+ - ./config/opentelemetry-demo/init.sql:/docker-entrypoint-initdb.d/init.sql
+ healthcheck:
+ test: [ "CMD-SHELL", "pg_isready" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 10
+ deploy:
+ resources:
+ limits:
+ memory: 80M
+
+ otel-demo-valkey-cart:
+ image: ghcr.io/valkey-io/valkey:9.0.4-alpine3.23
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ valkey-cart ]
+ user: valkey
+ healthcheck:
+ test: [ "CMD-SHELL", "valkey-cli ping" ]
+ start_period: 5s
+ interval: 5s
+ timeout: 3s
+ retries: 10
+ deploy:
+ resources:
+ limits:
+ memory: 20M
+
+ otel-demo-kafka:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-kafka
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ kafka ]
+ environment:
+ <<: *otel-demo-http
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
+ KAFKA_LISTENERS: PLAINTEXT://kafka:9092,CONTROLLER://kafka:9093
+ KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
+ KAFKA_HEAP_OPTS: -Xmx400m -Xms400m
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: cumulative
+ OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION: explicit_bucket_histogram
+ OTEL_EXPERIMENTAL_SDK_TELEMETRY_VERSION: latest
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: kafka
+ healthcheck:
+ test: nc -z kafka 9092
+ start_period: 10s
+ interval: 5s
+ timeout: 10s
+ retries: 10
deploy:
resources:
limits:
- memory: 768M
+ memory: 620M
depends_on:
- otel-instrumentation-java:
- condition: service_completed_successfully
- oap:
+ otel-demo-collector:
+ condition: service_started
+
+ otel-demo-ad:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-ad
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ ad ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-http ]
+ AD_PORT: 9555
+ AD_PROMETHEUS_PORT: 9465
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=medium
+ OTEL_LOGS_EXPORTER: otlp
+ OTEL_SERVICE_NAME: ad
+ OTEL_EXPERIMENTAL_SDK_TELEMETRY_VERSION: latest
+ healthcheck:
+ test: [ "CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/9555'" ]
+ start_period: 20s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ deploy:
+ resources:
+ limits:
+ memory: 300M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
+ condition: service_started
+
+ otel-demo-cart:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-cart
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ cart ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ CART_PORT: 7070
+ VALKEY_ADDR: valkey-cart:6379
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=high
+ OTEL_SERVICE_NAME: cart
+ ASPNETCORE_URLS: http://*:7070
+ deploy:
+ resources:
+ limits:
+ memory: 160M
+ depends_on:
+ otel-demo-valkey-cart:
condition: service_healthy
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
+ condition: service_started
- otel-songs:
+ otel-demo-checkout:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-checkout
restart: unless-stopped
- image: ${HUB}/songs-service:${TAG}-agentless
networks:
- otel:
- aliases: [ songs ]
+ otel-demo:
+ aliases: [ checkout ]
environment:
- <<: [ *otel-export, *otel-grpc ]
- OTEL_SERVICE_NAME: songs
- JAVA_TOOL_OPTIONS: -javaagent:/otel/javaagent.jar
- ACTIVE_MQ_URL: tcp://activemq:61616
- ACTIVE_MQ_QUEUE: queue-songs-ping
- volumes:
- - otel-java:/otel:ro
+ <<: [ *otel-demo-env, *otel-demo-http ]
+ CHECKOUT_PORT: 5050
+ CART_ADDR: cart:7070
+ CURRENCY_ADDR: currency:7001
+ EMAIL_ADDR: http://email:6060
+ PAYMENT_ADDR: payment:50051
+ PRODUCT_CATALOG_ADDR: product-catalog:3550
+ SHIPPING_ADDR: http://shipping:50050
+ KAFKA_ADDR: kafka:9092
+ KAFKA_TOPIC: orders
+ GOMEMLIMIT: 16MiB
+ OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
+ OTEL_GO_X_OBSERVABILITY: "true"
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=critical
+ OTEL_SERVICE_NAME: checkout
+ healthcheck:
+ test: [ "CMD", "/bin/grpc_health_probe", "-addr=:5050" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ read_only: true
+ tmpfs:
+ - /tmp
deploy:
resources:
limits:
- memory: 768M
+ memory: 20M
depends_on:
- otel-instrumentation-java:
- condition: service_completed_successfully
- oap:
+ otel-demo-cart:
+ condition: service_started
+ otel-demo-currency:
+ condition: service_healthy
+ otel-demo-email:
+ condition: service_healthy
+ otel-demo-payment:
+ condition: service_healthy
+ otel-demo-product-catalog:
+ condition: service_started
+ otel-demo-shipping:
+ condition: service_started
+ otel-demo-kafka:
condition: service_healthy
- otel-activemq:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
condition: service_started
- otel-rcmd:
+ otel-demo-currency:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-currency
restart: unless-stopped
- image: ${HUB}/recommendation-service:${TAG}-agentless
networks:
- otel:
- aliases: [ rcmd ]
+ otel-demo:
+ aliases: [ currency ]
environment:
- <<: [ *otel-export, *otel-http ]
- OTEL_SERVICE_NAME: recommendation
- PYTHONPATH: /otel/opentelemetry/instrumentation/auto_instrumentation:/otel
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ CURRENCY_PORT: 7001
+ IPV6_ENABLED: "false"
+ VERSION: ${OTEL_DEMO_IMAGE_TAG}
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=high
+ OTEL_SERVICE_NAME: currency
+ healthcheck:
+ test: [ "CMD-SHELL", "nc -z localhost 7001" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ deploy:
+ resources:
+ limits:
+ memory: 20M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+
+ otel-demo-email:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-email
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ email ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-http ]
+ APP_ENV: production
+ EMAIL_PORT: 6060
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=medium
+ OTEL_SERVICE_NAME: email
+ healthcheck:
+ test: [ "CMD", "ruby", "-e", "require 'socket'; TCPSocket.new('localhost', 6060).close" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ deploy:
+ resources:
+ limits:
+ memory: 100M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+
+ otel-demo-payment:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-payment
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ payment ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ IPV6_ENABLED: "false"
+ PAYMENT_PORT: 50051
+ OTEL_EXPORTER_OTLP_PROTOCOL: grpc
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=critical
+ OTEL_SERVICE_NAME: payment
+ healthcheck:
+ test:
+ - "CMD"
+ - "/nodejs/bin/node"
+ - "-e"
+ - >-
+ const net=require('net');const c=new net.Socket();
+ c.setTimeout(2000);
+ c.connect(50051,'127.0.0.1',()=>{c.destroy();process.exit(0)});
+ c.on('error',()=>process.exit(1));
+ c.on('timeout',()=>process.exit(1))
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ deploy:
+ resources:
+ limits:
+ memory: 140M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
+ condition: service_started
+
+ otel-demo-product-catalog:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-product-catalog
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ product-catalog ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ PRODUCT_CATALOG_PORT: 3550
+ GOMEMLIMIT: 16MiB
+ OTEL_GO_X_OBSERVABILITY: "true"
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=high
+ OTEL_SERVICE_NAME: product-catalog
+ # The Go SDK is built from this file (otelconf); without it the service sends no spans.
+ OTEL_CONFIG_FILE: /otel-config.yml
+ OTEL_SEMCONV_STABILITY_OPT_IN: database
+ DB_CONNECTION_STRING: postgres://astronomy_user:astronomy_password@astronomy-db/astronomy_db?sslmode=disable
volumes:
- - otel-python:/otel:ro
+ - ./config/opentelemetry-demo/otel-config.yml:/otel-config.yml
+ healthcheck:
+ test: [ "CMD", "/bin/grpc_health_probe", "-addr=:3550" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ read_only: true
+ tmpfs:
+ - /tmp
deploy:
resources:
limits:
- memory: 512M
+ memory: 20M
depends_on:
- otel-instrumentation-python:
- condition: service_completed_successfully
- oap:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
+ condition: service_started
+ otel-demo-astronomy-db:
condition: service_healthy
- otel-app:
+ otel-demo-quote:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-quote
restart: unless-stopped
- image: ${HUB}/app:${TAG}-agentless
networks:
- otel:
- aliases: [ app ]
+ otel-demo:
+ aliases: [ quote ]
environment:
- <<: [ *otel-export, *otel-grpc ]
- OTEL_SERVICE_NAME: app
- NODE_OPTIONS: --require /otel/autoinstrumentation.js
- OTEL_NODE_RESOURCE_DETECTORS: env,host,os,process,serviceinstance
- volumes:
- - otel-nodejs:/otel:ro
+ <<: [ *otel-demo-env, *otel-demo-http ]
+ IPV6_ENABLED: "false"
+ OTEL_PHP_AUTOLOAD_ENABLED: "true"
+ QUOTE_PORT: 8090
+ OTEL_PHP_INTERNAL_METRICS_ENABLED: "true"
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: quote
+ healthcheck:
+ test: [ "CMD", "php", "-r", "fsockopen('localhost', 8090) or die('fail');" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
deploy:
resources:
limits:
- memory: 512M
+ memory: 40M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+
+ otel-demo-recommendation:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-recommendation
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ recommendation ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ RECOMMENDATION_PORT: 9001
+ PRODUCT_CATALOG_ADDR: product-catalog:3550
+ OTEL_PYTHON_LOG_CORRELATION: "true"
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=medium
+ OTEL_SERVICE_NAME: recommendation
+ OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED: "true"
+ PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python
healthcheck:
- test: [ "CMD-SHELL", "curl -sf http://localhost/health" ]
- interval: 10s
+ test: [ "CMD-SHELL", "nc -z localhost 9001" ]
+ start_period: 10s
+ interval: 5s
timeout: 5s
- retries: 30
+ retries: 20
+ deploy:
+ resources:
+ limits:
+ memory: 500M
depends_on:
- otel-instrumentation-nodejs:
- condition: service_completed_successfully
- oap:
+ otel-demo-product-catalog:
+ condition: service_started
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
+ condition: service_started
+
+ otel-demo-shipping:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-shipping
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ shipping ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-http ]
+ IPV6_ENABLED: "false"
+ SHIPPING_PORT: 50050
+ QUOTE_ADDR: http://quote:8090
+ OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=high
+ OTEL_SERVICE_NAME: shipping
+ healthcheck:
+ test: [ "CMD", "/app/healthcheck" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ read_only: true
+ tmpfs:
+ - /tmp
+ deploy:
+ resources:
+ limits:
+ memory: 20M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-flagd:
+ condition: service_started
+
+ otel-demo-accounting:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-accounting
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ accounting ]
+ environment:
+ <<: *otel-demo-http
+ KAFKA_ADDR: kafka:9092
+ KAFKA_TOPIC: orders
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE: cumulative
+ OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION: explicit_bucket_histogram
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: accounting
+ DB_CONNECTION_STRING: Host=astronomy-db;Username=astronomy_user;Password=astronomy_password;Database=astronomy_db
+ OTEL_DOTNET_AUTO_TRACES_ENTITYFRAMEWORKCORE_INSTRUMENTATION_ENABLED: "false"
+ deploy:
+ resources:
+ limits:
+ memory: 160M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-kafka:
+ condition: service_healthy
+ otel-demo-astronomy-db:
condition: service_healthy
- otel-rating:
+ otel-demo-fraud-detection:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-fraud-detection
restart: unless-stopped
- image: ${HUB}/rating-service:${TAG}-agentless
networks:
- otel:
- aliases: [ rating ]
+ otel-demo:
+ aliases: [ fraud-detection ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-http ]
+ KAFKA_ADDR: kafka:9092
+ KAFKA_TOPIC: orders
+ OTEL_INSTRUMENTATION_KAFKA_EXPERIMENTAL_SPAN_ATTRIBUTES: "true"
+ OTEL_INSTRUMENTATION_MESSAGING_EXPERIMENTAL_RECEIVE_TELEMETRY_ENABLED: "true"
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: fraud-detection
+ OTEL_EXPERIMENTAL_SDK_TELEMETRY_VERSION: latest
deploy:
resources:
limits:
- memory: 1G
+ memory: 300M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-kafka:
+ condition: service_healthy
- otel-activemq:
- image: rmohr/activemq:5.15.9
+ otel-demo-image-provider:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-image-provider
+ restart: unless-stopped
networks:
- otel:
- aliases: [ activemq ]
+ otel-demo:
+ aliases: [ image-provider ]
environment:
- ACTIVEMQ_OPTS: "-Xmx128m -Xms128m"
+ IMAGE_PROVIDER_PORT: 8081
+ OTEL_COLLECTOR_HOST: otel-collector
+ OTEL_COLLECTOR_PORT_GRPC: 4317
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: image-provider
+ healthcheck:
+ test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8081/status" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
deploy:
resources:
limits:
- memory: 512M
+ memory: 120M
+ depends_on:
+ otel-demo-collector:
+ condition: service_started
- # Drives the copy: one home page every two seconds, app -> gateway -> songs, rcmd -> songs, rating.
- # The APISIX frontend of the copy, traced by APISIX's own opentelemetry plugin (config/apisix-otlp-trace); the page it
- # serves carries no browser agent, so the traces start here.
- otel-frontend:
+ otel-demo-frontend:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-frontend
restart: unless-stopped
- image: ${HUB}/frontend:${TAG}-agentless
networks:
- otel:
+ otel-demo:
aliases: [ frontend ]
- volumes:
- - ./config/apisix-otlp-trace/apisix.yaml:/usr/local/apisix/conf/apisix.yaml
- - ./config/apisix-otlp-trace/config.yaml:/usr/local/apisix/conf/config.yaml
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ PORT: 8080
+ FRONTEND_ADDR: frontend:8080
+ AD_ADDR: ad:9555
+ CART_ADDR: cart:7070
+ CHECKOUT_ADDR: checkout:5050
+ CURRENCY_ADDR: currency:7001
+ PRODUCT_CATALOG_ADDR: product-catalog:3550
+ RECOMMENDATION_ADDR: recommendation:9001
+ SHIPPING_ADDR: http://shipping:50050
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=critical
+ ENV_PLATFORM: local
+ OTEL_SERVICE_NAME: frontend
+ # The page's own spans, which the browser sends to the storefront's /otlp-http route.
+ PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: http://localhost:8088/otlp-http/v1/traces
+ WEB_OTEL_SERVICE_NAME: frontend-web
+ OTEL_COLLECTOR_HOST: otel-collector
+ healthcheck:
+ test: [ "CMD", "/nodejs/bin/node", "-e", "require('net').connect(8080,require('os').hostname(),function(){process.exit(0)}).on('error',function(){process.exit(1)})" ]
+ start_period: 60s
+ interval: 10s
+ timeout: 10s
+ retries: 5
deploy:
resources:
limits:
- memory: 256M
+ memory: 250M
depends_on:
- otel-app:
+ otel-demo-ad:
condition: service_healthy
- oap:
+ otel-demo-cart:
+ condition: service_started
+ otel-demo-checkout:
+ condition: service_started
+ otel-demo-currency:
+ condition: service_healthy
+ otel-demo-product-catalog:
+ condition: service_started
+ otel-demo-quote:
+ condition: service_healthy
+ otel-demo-recommendation:
condition: service_healthy
- # The same Selenium load generator as the agent copy, driving the frontend page.
- otel-loadgen:
+ otel-demo-shipping:
+ condition: service_started
+ otel-demo-collector:
+ condition: service_started
+ otel-demo-image-provider:
+ condition: service_healthy
+ otel-demo-flagd:
+ condition: service_started
+
+ # The storefront, at http://localhost:8088. The proxy's routes to the demo's Jaeger, Grafana, feature-flag UI and
+ # docs site remain in its built-in config, but those services are not deployed here.
+ otel-demo-frontend-proxy:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-frontend-proxy
restart: unless-stopped
- image: ${HUB}/load-gen:${TAG}
- networks: [ otel ]
+ networks:
+ otel-demo:
+ aliases: [ frontend-proxy ]
+ ports:
+ - "8088:8080"
environment:
- URL: http://frontend/index.html
+ FRONTEND_PORT: 8080
+ FRONTEND_HOST: frontend
+ LOCUST_WEB_HOST: load-generator
+ LOCUST_WEB_PORT: 8089
+ GRAFANA_PORT: 3000
+ GRAFANA_HOST: grafana
+ JAEGER_UI_PORT: 16686
+ JAEGER_HOST: jaeger
+ OPAMP_SERVER_HOST: opamp-server
+ OPAMP_SERVER_UI_PORT: 4321
+ OTEL_COLLECTOR_HOST: otel-collector
+ IMAGE_PROVIDER_HOST: image-provider
+ IMAGE_PROVIDER_PORT: 8081
+ OTEL_COLLECTOR_PORT_GRPC: 4317
+ OTEL_COLLECTOR_PORT_HTTP: 4318
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=critical
+ OTEL_SERVICE_NAME: frontend-proxy
+ OTEL_SERVICE_NAMESPACE: opentelemetry-demo
+ ENVOY_PORT: 8080
+ ENVOY_ADDR: 0.0.0.0
+ ENVOY_ADMIN_PORT: 10000
+ FIREPIT_HOST: firepit
+ FIREPIT_PORT: 8080
+ FLAGD_HOST: flagd
+ FLAGD_PORT: 8013
+ FLAGD_UI_HOST: flagd-ui
+ FLAGD_UI_PORT: 4000
+ TELEMETRY_DOCS_HOST: telemetry-docs
+ TELEMETRY_DOCS_PORT: 8000
+ CHATBOT_HOST: chatbot
+ CHATBOT_PORT: 7860
+ healthcheck:
+ test: [ "CMD", "bash", "-c", "echo > /dev/tcp/localhost/8080" ]
+ start_period: 10s
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ deploy:
+ resources:
+ limits:
+ memory: 90M
depends_on:
- otel-frontend:
+ otel-demo-frontend:
+ condition: service_healthy
+
+ # Locust: HTTP users, plus a share of headless-browser users whose page loads produce the frontend-web spans.
+ otel-demo-load-generator:
+ image: ${OTEL_DEMO_IMAGE}:${OTEL_DEMO_IMAGE_TAG}-load-generator
+ restart: unless-stopped
+ networks:
+ otel-demo:
+ aliases: [ load-generator ]
+ environment:
+ <<: [ *otel-demo-env, *otel-demo-grpc ]
+ LOCUST_WEB_PORT: 8089
+ LOCUST_USERS: 5
+ LOCUST_HOST: http://frontend-proxy:8080
+ LOCUST_HEADLESS: "false"
+ LOCUST_AUTOSTART: "true"
+ LOCUST_BROWSER_TRAFFIC_ENABLED: "true"
+ LOCUST_HTTP_USER_WEIGHT: 9
+ LOCUST_BROWSER_USER_WEIGHT: 1
+ OTEL_RESOURCE_ATTRIBUTES: service.namespace=opentelemetry-demo,service.version=${OTEL_DEMO_IMAGE_TAG},service.criticality=low
+ OTEL_SERVICE_NAME: load-generator
+ OTEL_PYTHON_SDK_INTERNAL_METRICS_ENABLED: "true"
+ PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python
+ LOCUST_WEB_HOST: 0.0.0.0
+ FLAGD_OFREP_PORT: 8016
+ deploy:
+ resources:
+ limits:
+ memory: 1500M
+ depends_on:
+ otel-demo-frontend-proxy:
+ condition: service_healthy
+ otel-demo-flagd:
condition: service_started
+
networks:
sw:
- otel:
-
-volumes:
- otel-java:
- otel-nodejs:
- otel-python:
+ otel-demo:
diff --git a/deploy/platform/kubernetes/Chart.yaml b/deploy/platform/kubernetes/Chart.yaml
index 826da20..9e8ad7e 100644
--- a/deploy/platform/kubernetes/Chart.yaml
+++ b/deploy/platform/kubernetes/Chart.yaml
@@ -24,7 +24,7 @@ sources:
dependencies:
- name: skywalking-helm
alias: skywalking
- version: 0.0.0-62c64a80707290ea4380894c983918c04d2724bc
+ version: 0.0.0-d6d0344b2ebd620ef314d02f0754f89afff0104c
repository: oci://ghcr.io/apache/skywalking-helm
# @feature: java-agent-injector; the java agent injector is a component of the swck operator, so we need to deploy the swck operator firstly
diff --git a/deploy/platform/kubernetes/Makefile b/deploy/platform/kubernetes/Makefile
index 2cf4d82..7654908 100644
--- a/deploy/platform/kubernetes/Makefile
+++ b/deploy/platform/kubernetes/Makefile
@@ -264,15 +264,14 @@ feature-grafana:
@mkdir -p ./generated/dashboard-configs/
@cp ../config/grafana/dashboards/*.json ./generated/dashboard-configs/
-# A second copy of the music application, from the agentless images, instrumented at start by the OpenTelemetry
-# auto-instrumentation and exporting OTLP to the OpenTelemetry Collector, which delivers every span to the OAP twice:
-# as OTLP on the gRPC port, stored natively, and converted to Zipkin on 9411.
+# @feature: otlp-trace; the OpenTelemetry Astronomy Shop, installed by `deploy` as its own release in its own namespace,
+# since its services take fixed names (frontend, kafka, otel-collector, ...). Its collector sends every span to the OAP.
.PHONY: feature-otlp-trace
feature-otlp-trace:
- $(eval HELM_OPTIONS := $(HELM_OPTIONS) --set features.otlpTrace.enabled=true)
- $(eval HELM_OPTIONS := $(HELM_OPTIONS) --set features.otlpTrace.instrumentation.java=$(OTEL_INSTRUMENTATION_JAVA_IMAGE))
- $(eval HELM_OPTIONS := $(HELM_OPTIONS) --set features.otlpTrace.instrumentation.nodejs=$(OTEL_INSTRUMENTATION_NODEJS_IMAGE))
- $(eval HELM_OPTIONS := $(HELM_OPTIONS) --set features.otlpTrace.instrumentation.python=$(OTEL_INSTRUMENTATION_PYTHON_IMAGE))
+ $(eval OTEL_DEMO_HELM_OPTIONS := --version $(OTEL_DEMO_CHART_VERSION) -f ../config/opentelemetry-demo/values.yaml)
+ $(eval OTEL_DEMO_HELM_OPTIONS := $(OTEL_DEMO_HELM_OPTIONS) --set default.image.repository=$(OTEL_DEMO_IMAGE) --set default.image.tag=$(OTEL_DEMO_IMAGE_TAG))
+ $(eval OTEL_DEMO_HELM_OPTIONS := $(OTEL_DEMO_HELM_OPTIONS) --set opentelemetry-collector.alternateConfig.exporters.otlp_grpc/oap.endpoint=$(RELEASE)-oap.$(NAMESPACE).svc:11800)
+ $(eval OTEL_DEMO_HELM_OPTIONS := $(OTEL_DEMO_HELM_OPTIONS) $(if $(filter true,$(DEBUG)),--dry-run --debug))
# @feature: asz; deploy the SkyWalking AI Sessionizer. No real Claude Code runs in the showcase, so
# asz's scenario feed generates the conversations, and asz collects them and pushes them to the OAP
@@ -350,6 +349,9 @@ deploy: clean-generated $(features)
@rm -rf ./charts/ ./tmpcharts/ ./tmpcharts-*/ ./Chart.lock
helm dep up .
helm -n $(NAMESPACE) upgrade --install $(RELEASE) . --create-namespace --timeout=20m $(HELM_OPTIONS)
+ifneq ($(findstring otlp-trace,$(FEATURE_FLAGS)),)
+ helm -n $(OTEL_DEMO_NAMESPACE) upgrade --install $(OTEL_DEMO_RELEASE) $(OTEL_DEMO_CHART) --create-namespace --timeout=20m $(OTEL_DEMO_HELM_OPTIONS)
+endif
ifneq ($(DEBUG),true)
$(info rollout restart to allow the new sidecar to be injected.)
kubectl -n $(SAMPLE_SERVICES_NAMESPACE) get deployments -o name | xargs kubectl -n $(SAMPLE_SERVICES_NAMESPACE) rollout restart
@@ -358,6 +360,9 @@ endif
.PHONY: undeploy
undeploy:
helm -n $(NAMESPACE) delete $(RELEASE) --wait || true
+ifneq ($(findstring otlp-trace,$(FEATURE_FLAGS)),)
+ helm -n $(OTEL_DEMO_NAMESPACE) delete $(OTEL_DEMO_RELEASE) --wait || true
+endif
ifneq ($(findstring cilium,$(FEATURE_FLAGS)),)
cilium uninstall
endif
diff --git a/deploy/platform/kubernetes/Makefile.in b/deploy/platform/kubernetes/Makefile.in
index 19086fc..2ae2815 100644
--- a/deploy/platform/kubernetes/Makefile.in
+++ b/deploy/platform/kubernetes/Makefile.in
@@ -21,6 +21,10 @@
NAMESPACE ?= skywalking-showcase
SAMPLE_SERVICES_NAMESPACE ?= sample-services
CILIUM_SERVICES_NAMESPACE ?= cilium-services
+# @feature: otlp-trace; where the OpenTelemetry Astronomy Shop is installed, as its own release
+OTEL_DEMO_NAMESPACE ?= otel-demo
+OTEL_DEMO_RELEASE ?= otel-demo
+OTEL_DEMO_CHART ?= oci://ghcr.io/open-telemetry/opentelemetry-helm-charts/opentelemetry-demo
RELEASE ?= demo
AGENTLESS ?= false
SCALLER_ENABLE ?= false
diff --git a/deploy/platform/kubernetes/templates/feature-ciilum/policy.yaml b/deploy/platform/kubernetes/templates/feature-ciilum/policy.yaml
index 4c128a7..dcd39e9 100644
--- a/deploy/platform/kubernetes/templates/feature-ciilum/policy.yaml
+++ b/deploy/platform/kubernetes/templates/feature-ciilum/policy.yaml
@@ -16,6 +16,9 @@
# under the License.
#
{{- if .Values.features.cilium.enabled }}
+{{- /* The OAP and Satellite pods are matched twice: by the chart's legacy labels (app, component), which a release
+installed before skywalking-helm 5.1.0 keeps across upgrades, and by the Kubernetes recommended labels
+(app.kubernetes.io/instance, app.kubernetes.io/component), the only ones a release installed since then carries. */}}
---
@@ -39,6 +42,9 @@ spec:
- matchLabels:
"k8s:app": demo
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": satellite
egress:
- toEndpoints:
- matchLabels:
@@ -60,6 +66,8 @@ spec:
"k8s:app": gateway
- matchLabels:
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/component": satellite
toPorts:
- ports:
- port: "80"
@@ -91,6 +99,9 @@ spec:
- matchLabels:
"k8s:app": demo
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": satellite
egress:
- toEndpoints:
- matchLabels:
@@ -112,6 +123,8 @@ spec:
"k8s:app": app
- matchLabels:
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/component": satellite
toPorts:
- ports:
- port: "80"
@@ -141,9 +154,15 @@ spec:
- matchLabels:
"k8s:app": demo
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": satellite
- matchLabels:
"k8s:app": demo
"k8s:component": oap
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": oap
egress:
- toEndpoints:
- matchLabels:
@@ -163,9 +182,14 @@ spec:
"k8s:app": gateway
- matchLabels:
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/component": satellite
- matchLabels:
"k8s:app": demo
"k8s:component": oap
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": oap
toPorts:
- ports:
- port: "80"
@@ -196,9 +220,15 @@ spec:
- matchLabels:
"k8s:app": demo
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": satellite
- matchLabels:
"k8s:app": demo
"k8s:component": oap
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": oap
egress:
- toEndpoints:
- matchLabels:
@@ -216,8 +246,12 @@ spec:
"k8s:app": frontend
- matchLabels:
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/component": satellite
- matchLabels:
"k8s:component": oap
+ - matchLabels:
+ "k8s:app.kubernetes.io/component": oap
toPorts:
- ports:
- port: "80"
@@ -257,9 +291,15 @@ spec:
- matchLabels:
"k8s:app": demo
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": satellite
- matchLabels:
"k8s:app": demo
"k8s:component": oap
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": oap
- matchLabels:
"k8s:app.kubernetes.io/name": opentelemetry-collector
"k8s:component": standalone-collector
@@ -283,9 +323,15 @@ spec:
- matchLabels:
"k8s:app": demo
"k8s:component": satellite
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": satellite
- matchLabels:
"k8s:app": demo
"k8s:component": oap
+ - matchLabels:
+ "k8s:app.kubernetes.io/instance": demo
+ "k8s:app.kubernetes.io/component": oap
- matchLabels:
"k8s:app.kubernetes.io/name": opentelemetry-collector
"k8s:component": standalone-collector
diff --git a/deploy/platform/kubernetes/templates/feature-otlp-trace/resources.yaml b/deploy/platform/kubernetes/templates/feature-otlp-trace/resources.yaml
deleted file mode 100644
index 6c78c3e..0000000
--- a/deploy/platform/kubernetes/templates/feature-otlp-trace/resources.yaml
+++ /dev/null
@@ -1,492 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-{{- if .Values.features.otlpTrace.enabled }}
-{{- $ns := .Values.features.otlpTrace.namespace }}
-{{- $hub := .Values.sampleServices.hub }}
-{{- $tag := .Values.sampleServices.tag }}
-{{- /* The spans go straight to the OAP: gRPC on 11800 where the instrumentation speaks it, OTLP/HTTP on 12800
- for the Python agent and the APISIX plugin, which are HTTP-only. */}}
-{{- $oapGrpc := include "skywalking.oap.address.grpc" . }}
-{{- $oapHttp := include "skywalking.oap.address.http" . }}
-{{- $oapHost := include "skywalking.oap.address.host" . }}
-{{- /*
-A second copy of the music application: the agentless images, the OpenTelemetry auto-instrumentation copied in by an
-init container and switched on through the runtime's own hook (JAVA_TOOL_OPTIONS, NODE_OPTIONS, PYTHONPATH), the APISIX
-frontend traced by its built-in opentelemetry plugin, and every span exported straight to the OAP, which stores it
-natively for the TraceQL /otlp datasource. No collector sits in the trace path. The Zipkin store stays the mesh's:
-Istio's sidecars send it their own spans, so /zipkin shows the mesh and /otlp this copy.
-The same Selenium load generator drives the frontend page, so the traces start at frontend. It has its own namespace
-because the services address each other by fixed hostnames, frontend, gateway, songs, rcmd, rating, app and activemq.
-The page carries no browser agent, and the Go rating service has no runtime instrumentation and appears only as the
-callee of recommendation's spans.
-*/}}
----
-apiVersion: v1
-kind: Namespace
-metadata:
- name: {{ $ns }}
-{{- range $svc := list "frontend" "gateway" "songs" "rcmd" "app" "rating" }}
----
-apiVersion: v1
-kind: Service
-metadata:
- name: {{ $svc }}
- namespace: {{ $ns }}
-spec:
- selector:
- app: {{ $svc }}
- ports:
- - protocol: TCP
- port: 80
- targetPort: 80
-{{- end }}
----
-apiVersion: v1
-kind: Service
-metadata:
- name: activemq
- namespace: {{ $ns }}
-spec:
- selector:
- app: activemq
- ports:
- - name: openwire
- protocol: TCP
- port: 61616
- targetPort: 61616
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: activemq
- namespace: {{ $ns }}
- labels:
- app: activemq
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: activemq
- template:
- metadata:
- labels:
- app: activemq
- spec:
- containers:
- - name: activemq
- image: rmohr/activemq:5.15.9
- imagePullPolicy: IfNotPresent
- ports:
- - containerPort: 61616
- env:
- - name: ACTIVEMQ_OPTS
- value: "-Xmx128m -Xms128m"
- resources:
- requests:
- cpu: 50m
- memory: 256Mi
- limits:
- # The broker's JVM needs more than its 128m heap; 256Mi got it OOM-killed.
- memory: 512Mi
-{{- range $svc := list "gateway" "songs" }}
----
-# Java: the OpenTelemetry Java agent, attached through JAVA_TOOL_OPTIONS, which the agentless image's java picks up.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: {{ $svc }}
- namespace: {{ $ns }}
- labels:
- app: {{ $svc }}
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: {{ $svc }}
- template:
- metadata:
- labels:
- app: {{ $svc }}
- annotations:
- sidecar.istio.io/inject: "false"
- spec:
- initContainers:
- - name: otel-instrumentation
- image: {{ $.Values.features.otlpTrace.instrumentation.java }}
- command: ["cp", "/javaagent.jar", "/otel-auto-instrumentation/javaagent.jar"]
- volumeMounts:
- - name: otel-auto-instrumentation
- mountPath: /otel-auto-instrumentation
- containers:
- - name: {{ $svc }}
- image: "{{ $hub }}/{{ if eq $svc "gateway" }}gateway-service{{ else }}songs-service{{ end }}:{{ $tag }}-agentless"
- imagePullPolicy: IfNotPresent
- ports:
- - containerPort: 80
- env:
- - name: JAVA_TOOL_OPTIONS
- value: -javaagent:/otel-auto-instrumentation/javaagent.jar
- - name: OTEL_SERVICE_NAME
- value: {{ $svc }}
- - name: OTEL_RESOURCE_ATTRIBUTES
- value: service.namespace={{ $ns }}
- - name: OTEL_EXPORTER_OTLP_PROTOCOL
- value: grpc
- - name: OTEL_EXPORTER_OTLP_ENDPOINT
- value: http://{{ $oapGrpc }}
- - name: OTEL_TRACES_EXPORTER
- value: otlp
- - name: OTEL_METRICS_EXPORTER
- value: none
- - name: OTEL_LOGS_EXPORTER
- value: none
- {{- if eq $svc "songs" }}
- - name: ACTIVE_MQ_URL
- value: tcp://activemq:61616
- - name: ACTIVE_MQ_QUEUE
- value: queue-songs-ping
- {{- end }}
- readinessProbe:
- tcpSocket:
- port: 80
- initialDelaySeconds: 20
- periodSeconds: 10
- resources:
- requests:
- cpu: 100m
- memory: 384Mi
- limits:
- memory: 768Mi
- volumeMounts:
- - name: otel-auto-instrumentation
- mountPath: /otel-auto-instrumentation
- readOnly: true
- volumes:
- - name: otel-auto-instrumentation
- emptyDir: {}
-{{- end }}
----
-# Python: the auto-instrumentation's sitecustomize is put first on PYTHONPATH.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: recommendation
- namespace: {{ $ns }}
- labels:
- app: rcmd
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: rcmd
- template:
- metadata:
- labels:
- app: rcmd
- annotations:
- sidecar.istio.io/inject: "false"
- spec:
- initContainers:
- - name: otel-instrumentation
- image: {{ .Values.features.otlpTrace.instrumentation.python }}
- command: ["cp", "-r", "/autoinstrumentation/.", "/otel-auto-instrumentation"]
- volumeMounts:
- - name: otel-auto-instrumentation
- mountPath: /otel-auto-instrumentation
- containers:
- - name: recommendation
- image: "{{ $hub }}/recommendation-service:{{ $tag }}-agentless"
- imagePullPolicy: IfNotPresent
- ports:
- - containerPort: 80
- env:
- - name: PYTHONPATH
- value: /otel-auto-instrumentation/opentelemetry/instrumentation/auto_instrumentation:/otel-auto-instrumentation
- - name: OTEL_SERVICE_NAME
- value: recommendation
- - name: OTEL_RESOURCE_ATTRIBUTES
- value: service.namespace={{ $ns }}
- # The Python auto-instrumentation image carries no gRPC exporter, so this one goes over OTLP/HTTP.
- - name: OTEL_EXPORTER_OTLP_PROTOCOL
- value: http/protobuf
- - name: OTEL_EXPORTER_OTLP_ENDPOINT
- value: {{ $oapHttp }}
- - name: OTEL_TRACES_EXPORTER
- value: otlp
- - name: OTEL_METRICS_EXPORTER
- value: none
- - name: OTEL_LOGS_EXPORTER
- value: none
- readinessProbe:
- tcpSocket:
- port: 80
- periodSeconds: 10
- resources:
- requests:
- cpu: 50m
- memory: 128Mi
- limits:
- memory: 512Mi
- volumeMounts:
- - name: otel-auto-instrumentation
- mountPath: /otel-auto-instrumentation
- readOnly: true
- volumes:
- - name: otel-auto-instrumentation
- emptyDir: {}
----
-# Node.js: the auto-instrumentation is required through NODE_OPTIONS before the app's own code.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: app
- namespace: {{ $ns }}
- labels:
- app: app
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: app
- template:
- metadata:
- labels:
- app: app
- annotations:
- sidecar.istio.io/inject: "false"
- spec:
- initContainers:
- - name: otel-instrumentation
- image: {{ .Values.features.otlpTrace.instrumentation.nodejs }}
- command: ["cp", "-r", "/autoinstrumentation/.", "/otel-auto-instrumentation"]
- volumeMounts:
- - name: otel-auto-instrumentation
- mountPath: /otel-auto-instrumentation
- containers:
- - name: app
- image: "{{ $hub }}/app:{{ $tag }}-agentless"
- imagePullPolicy: IfNotPresent
- ports:
- - containerPort: 80
- env:
- - name: NODE_OPTIONS
- value: --require /otel-auto-instrumentation/autoinstrumentation.js
- - name: OTEL_NODE_RESOURCE_DETECTORS
- value: env,host,os,process,serviceinstance
- - name: OTEL_SERVICE_NAME
- value: app
- - name: OTEL_RESOURCE_ATTRIBUTES
- value: service.namespace={{ $ns }}
- - name: OTEL_EXPORTER_OTLP_PROTOCOL
- value: grpc
- - name: OTEL_EXPORTER_OTLP_ENDPOINT
- value: http://{{ $oapGrpc }}
- - name: OTEL_TRACES_EXPORTER
- value: otlp
- - name: OTEL_METRICS_EXPORTER
- value: none
- - name: OTEL_LOGS_EXPORTER
- value: none
- readinessProbe:
- httpGet:
- path: /health
- port: 80
- periodSeconds: 10
- resources:
- requests:
- cpu: 50m
- memory: 128Mi
- limits:
- memory: 512Mi
- volumeMounts:
- - name: otel-auto-instrumentation
- mountPath: /otel-auto-instrumentation
- readOnly: true
- volumes:
- - name: otel-auto-instrumentation
- emptyDir: {}
----
-# Go: no runtime instrumentation; the agentless image builds the binary at start, so its probe waits.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: rating
- namespace: {{ $ns }}
- labels:
- app: rating
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: rating
- template:
- metadata:
- labels:
- app: rating
- annotations:
- sidecar.istio.io/inject: "false"
- spec:
- containers:
- - name: rating
- image: "{{ $hub }}/rating-service:{{ $tag }}-agentless"
- imagePullPolicy: IfNotPresent
- ports:
- - containerPort: 80
- readinessProbe:
- tcpSocket:
- port: 80
- initialDelaySeconds: 30
- periodSeconds: 10
- failureThreshold: 30
- resources:
- requests:
- cpu: 100m
- memory: 256Mi
- limits:
- memory: 1Gi
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: apisix-config
- namespace: {{ $ns }}
-data:
- config: |
- apisix:
- node_listen: 80
- enable_ipv6: false
- enable_admin: false
- config_center: yaml
- plugin_attr:
- opentelemetry:
- resource:
- service.name: frontend
- service.namespace: {{ $ns }}
- collector:
- address: {{ $oapHost }}:12800
- request_timeout: 3
- plugins:
- - opentelemetry
- nginx_config:
- # Two workers rather than one per CPU: the frontend proxies two routes and serves a static page, and APISIX's
- # default sizes the workers by the node, not by the container's memory limit.
- worker_processes: 2
- http_server_configuration_snippet: |
- location ~ \.(gif|jpg|png|js|css|html)$ {
- root /app/build;
- index index.html;
- }
- # The two routes the page calls, traced by the opentelemetry plugin; its default sampler is always_off, so each route
- # turns it on. The static page is served by the nginx location above and is not traced.
- apisix: |
- routes:
- - uri: /homepage
- service_id: 1
- plugins:
- opentelemetry:
- sampler:
- name: always_on
- - uri: /test
- service_id: 1
- plugins:
- opentelemetry:
- sampler:
- name: always_on
- services:
- - id: 1
- upstream_id: 1
- upstreams:
- - id: 1
- nodes:
- "app:80": 1
- type: roundrobin
- #END
----
-# The APISIX frontend of the copy; the page it serves carries no browser agent, so the traces start here.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: frontend
- namespace: {{ $ns }}
- labels:
- app: frontend
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: frontend
- template:
- metadata:
- labels:
- app: frontend
- annotations:
- sidecar.istio.io/inject: "false"
- spec:
- containers:
- - name: frontend
- image: "{{ $hub }}/frontend:{{ $tag }}-agentless"
- imagePullPolicy: IfNotPresent
- resources:
- requests:
- cpu: 100m
- memory: 128Mi
- limits:
- memory: 256Mi
- ports:
- - containerPort: 80
- name: http
- volumeMounts:
- - name: apisix-config
- mountPath: /usr/local/apisix/conf/config.yaml
- subPath: config
- - name: apisix-config
- mountPath: /usr/local/apisix/conf/apisix.yaml
- subPath: apisix
- volumes:
- - name: apisix-config
- configMap:
- name: apisix-config
----
-# Drives the copy: the same Selenium load generator as the agent copy, clicking through the frontend page.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: loadgen
- namespace: {{ $ns }}
- labels:
- app: loadgen
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: loadgen
- template:
- metadata:
- labels:
- app: loadgen
- annotations:
- sidecar.istio.io/inject: "false"
- spec:
- containers:
- - name: loadgen
- image: "{{ $hub }}/load-gen:{{ $tag }}"
- imagePullPolicy: IfNotPresent
- env:
- - name: URL
- value: http://frontend/index.html
-{{- end }}
diff --git a/deploy/platform/kubernetes/values.yaml b/deploy/platform/kubernetes/values.yaml
index 83fb626..52d8bb3 100644
--- a/deploy/platform/kubernetes/values.yaml
+++ b/deploy/platform/kubernetes/values.yaml
@@ -928,18 +928,6 @@ features:
grafana:
enabled: false
image: ~
- # @feature: otlp-trace; a second copy of the music application, from the agentless images, instrumented at start by the
- # OpenTelemetry auto-instrumentation (the APISIX frontend by its own opentelemetry plugin) and exporting every span
- # straight to the OAP, gRPC on 11800 or OTLP/HTTP on 12800, stored natively for Grafana's /otlp. No collector sits in
- # the trace path; the Zipkin store stays the mesh's.
- otlpTrace:
- enabled: false
- # Its own namespace: the services address each other by the same fixed hostnames as the agent copy.
- namespace: otel-services
- instrumentation:
- java: ~
- nodejs: ~
- python: ~
# @feature: asz; the SkyWalking AI Sessionizer and its scenario feed
asz:
diff --git a/docs/readme.md b/docs/readme.md
index ebd1b5b..a694f71 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -115,7 +115,7 @@ Currently, the features supported are:
| `apisix-monitor` | Deploy OpenTelemetry and export APISIX metrics to SkyWalking for analysis and display on UI | |
| `mesh-with-agent` | Deploy services with java agent in the service mesh environment. | Only support deployment in the Kubernetes environment, docker is not supported. |
| `grafana` | Deploy a Grafana to show SkyWalking metrics and logs on the Grafana UI. | Feel free to modify the Grafana config when deploy your own environment. |
-| `otlp-trace` | Deploy a second copy of the music application from its agentless images: the Java, Node.js and Python services instrumented at start by the OpenTelemetry auto-instrumentation, the APISIX frontend by its built-in `opentelemetry` plugin, every span exported straight to the OAP and stored natively, so Grafana Tempo serves this copy at `/otlp`. | Runs beside the SkyWalking-agent copy, in its own namespace on Kubernetes and its own network on Docker Compose, so bot [...]
+| `otlp-trace` | Deploy the [OpenTelemetry Astronomy Shop](https://github.com/open-telemetry/opentelemetry-demo), whose services are instrumented by the OpenTelemetry SDKs, with its collector sending every span to the OAP, stored natively, so the OTLP layers and Grafana Tempo's `/otlp` datasource show it. Its Postgres, Valkey and Kafka calls feed the OTLP virtual database, cache and MQ layers. | Runs apart from the SkyWalking-agent music application, so neither changes the oth [...]
| `r3` | Deploy [R3](https://github.com/SkyAPM/R3) as RESTful URL recognition service. | |
| `rocketmq-monitor` | Deploy OpenTelemetry and export RocketMQ monitoring metrics to SkyWalking for analysis and display on UI. | |
| `pulsar-monitor` | Deploy OpenTelemetry and export Pulsar monitoring metrics to SkyWalking for analysis and display on UI. | |
diff --git a/services/recommendation-service/Dockerfile b/services/recommendation-service/Dockerfile
index ba69280..9af98b7 100644
--- a/services/recommendation-service/Dockerfile
+++ b/services/recommendation-service/Dockerfile
@@ -18,6 +18,9 @@
FROM apache/skywalking-python:1.2.0-grpc-py3.10-slim
WORKDIR /workspace
+# The base image's agent wheel lacks the generated skywalking.protocol package, so the agent fails to start
+# ("No module named 'skywalking.protocol'"); the same release from PyPI carries it.
+RUN pip install --no-deps --force-reinstall apache-skywalking==1.2.0
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src .