You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2021/11/05 05:08:18 UTC

[skywalking-showcase] branch main updated (2b2f473 -> d81a041)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-showcase.git.


 discard 2b2f473  Add highlight target to highlight important contents of a feature
     new d81a041  Add highlight target to highlight important contents of a feature

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (2b2f473)
            \
             N -- N -- N   refs/heads/main (d81a041)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

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.


Summary of changes:
 deploy/platform/docker/docker-compose.cluster.yaml |  2 +-
 services/app/Dockerfile                            | 11 +++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)

[skywalking-showcase] 01/01: Add highlight target to highlight important contents of a feature

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-showcase.git

commit d81a04169583071ee5231f773f31c1efe55693ef
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Fri Nov 5 11:01:21 2021 +0800

    Add highlight target to highlight important contents of a feature
---
 Makefile                                           |  10 +-
 Makefile.in                                        |   7 +-
 deploy/platform/docker/Makefile                    |   6 +-
 .../docker/config/otel-collector-config.yaml       |   1 +
 deploy/platform/docker/docker-compose.cluster.yaml |  88 ++++++++++
 ...ompose.yaml => docker-compose.single-node.yaml} |  10 +-
 deploy/platform/docker/docker-compose.vm.yaml      |   3 +
 deploy/platform/kubernetes/Makefile                |  30 +++-
 .../kubernetes/feature-agent/resources.yaml        | 181 +++++++++++++++++++++
 .../kubernetes/feature-single-node/resources.yaml  | 156 ++++++++++++++++++
 .../platform/kubernetes/feature-vm/resources.yaml  | 121 ++++++++++++++
 scripts/make/help.mk                               |  14 +-
 services/app/Dockerfile                            |  11 +-
 services/app/server/index.js                       |   1 +
 services/app/ui/src/index.js                       |   1 +
 services/gateway-service/Dockerfile                |   1 +
 services/recommendation-service/Dockerfile         |   2 +
 services/songs-service/Dockerfile                  |   1 +
 18 files changed, 623 insertions(+), 21 deletions(-)

diff --git a/Makefile b/Makefile
index 7edc1f6..1278364 100644
--- a/Makefile
+++ b/Makefile
@@ -46,17 +46,23 @@ $(services_push): %.docker.push: %
 ##@ Deploy targets
 
 .PHONY: deploy.docker
-deploy.docker: undeploy.docker ## Deploy the showcase with Docker Compose
+deploy.docker: ## Deploy the showcase with Docker Compose
 	$(MAKE) -C deploy/platform/docker deploy
 
 .PHONY: undeploy.docker
 undeploy.docker: ## Undeploy the showcase from Docker Compose
 	$(MAKE) -C deploy/platform/docker undeploy
 
+.PHONY: redeploy.docker
+redeploy.docker: undeploy.docker deploy.docker
+
 .PHONY: deploy.kubernetes
-deploy.kubernetes: undeploy.kubernetes ## Deploy the showcase to Kubernetes
+deploy.kubernetes: ## Deploy the showcase to Kubernetes
 	$(MAKE) -C deploy/platform/kubernetes deploy
 
 .PHONY: undeploy.kubernetes
 undeploy.kubernetes: ## Undeploy the showcase from Kubernetes
 	$(MAKE) -C deploy/platform/kubernetes undeploy
+
+.PHONY: redeploy.kubernetes
+redeploy.kubernetes: undeploy.kubernetes deploy.kubernetes
diff --git a/Makefile.in b/Makefile.in
index b1fc2b7..1ce08e0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -16,6 +16,8 @@
 # under the License.
 #
 
+comma := ,
+
 .EXPORT_ALL_VARIABLES:
 
 HUB ?= ghcr.io/apache/skywalking-showcase
@@ -29,4 +31,7 @@ SW_ROCKET_BOT_IMAGE ?= ghcr.io/apache/skywalking/ui:c9bd79e8bb974e404766e3490c00
 SW_AGENT_NODEJS_BACKEND_VERSION ?= e755659c7f308d3b5589619778c8360308cb14f8
 SW_AGENT_NODEJS_FRONTEND_VERSION ?= af0565a67d382b683c1dbd94c379b7080db61449
 
-FEATURE_FLAGS ?= all
+# ALL variables should be listed above ^^
+EXPORTED_VARS := $(filter-out <%,$(.VARIABLES))
+
+features ?= all
diff --git a/deploy/platform/docker/Makefile b/deploy/platform/docker/Makefile
index d9e69c5..af5c48c 100644
--- a/deploy/platform/docker/Makefile
+++ b/deploy/platform/docker/Makefile
@@ -18,8 +18,6 @@
 
 include ../../../Makefile.in
 
-comma := ,
-
 ifeq ($(FEATURE_FLAGS),all)
   features := $(wildcard docker-compose.*.yaml)
   features := $(foreach f,$(features),-f $(f))
@@ -30,8 +28,8 @@ endif
 
 .PHONY: deploy
 deploy:
-	docker-compose -f docker-compose.yaml $(features) up -d
+	docker-compose $(features) up -d
 
 .PHONY: undeploy
 undeploy:
-	docker-compose -f docker-compose.yaml $(features) --log-level ERROR down
+	docker-compose $(features) --log-level ERROR down
diff --git a/deploy/platform/docker/config/otel-collector-config.yaml b/deploy/platform/docker/config/otel-collector-config.yaml
index 743a47a..eca75f5 100644
--- a/deploy/platform/docker/config/otel-collector-config.yaml
+++ b/deploy/platform/docker/config/otel-collector-config.yaml
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# @feature: vm; OpenTelemetry collector configurations to scrape VM node metrics
 receivers:
   prometheus:
     config:
diff --git a/deploy/platform/docker/docker-compose.cluster.yaml b/deploy/platform/docker/docker-compose.cluster.yaml
new file mode 100644
index 0000000..5accf20
--- /dev/null
+++ b/deploy/platform/docker/docker-compose.cluster.yaml
@@ -0,0 +1,88 @@
+# 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.
+#
+version: '2.1'
+
+services:
+  elasticsearch:
+    extends:
+      file: docker-compose.single-node.yaml
+      service: elasticsearch
+
+  zookeeper:
+    image: zookeeper:3.5
+    expose:
+      - 2181
+    networks: [ sw ]
+    healthcheck:
+      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/2181" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  oap-init: # @feature: cluster; set up an init container to initialize the storage templates and indices
+    image: ${SW_OAP_IMAGE}
+    networks: [ sw ]
+    environment:
+      SW_STORAGE: elasticsearch
+      SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
+      JAVA_OPTS: "-Dmode=init" # @feature: cluster; set the init container to "init" mode to initialize the storage templates and indices
+    depends_on:
+      elasticsearch:
+        condition: service_healthy
+
+  oap1: &oap
+    image: ${SW_OAP_IMAGE}
+    networks: [ sw ]
+    environment:
+      SW_CLUSTER: zookeeper # @feature: cluster; set up a cluster coordinator
+      SW_CLUSTER_ZK_HOST_PORT: zookeeper:2181 # @feature: cluster; set up the cluster coordinator address
+      SW_HEALTH_CHECKER: default # @feature: health-check;
+      SW_OTEL_RECEIVER: default # @feature: vm; enable the OC receiver that receives the VM metrics
+      SW_OTEL_RECEIVER_ENABLED_OC_RULES: vm # @feature: vm; enable the OC rules that analyse the VM metrics
+      SW_STORAGE: elasticsearch
+      SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
+      SW_TELEMETRY: prometheus # @feature: so11y; expose the metrics of self o11y through prometheus
+      SW_PROMETHEUS_FETCHER: default # @feature: so11y; fetch the metrics of self o11y through prometheus
+      JAVA_OPTS: "-Dmode=no-init -Xms2048m -Xmx2048m" # @feature: cluster; start the cluster nodes in no-init mode
+    healthcheck:
+      test: [ "CMD-SHELL", "/skywalking/bin/swctl ch" ]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+    depends_on:
+      oap-init:
+        condition: service_completed_successfully # @feature: cluster; wait for init container to complete
+      zookeeper:
+        condition: service_healthy
+
+  oap:
+    <<: *oap
+
+  rocket-bot:
+    image: ${SW_ROCKET_BOT_IMAGE}
+    networks: [ sw ]
+    ports:
+      - "9999:8080"
+    depends_on:
+      oap:
+        condition: service_healthy
+    environment:
+      SW_OAP_ADDRESS: http://oap:12800,http://oap1:12800
+
+networks:
+  sw:
diff --git a/deploy/platform/docker/docker-compose.yaml b/deploy/platform/docker/docker-compose.single-node.yaml
similarity index 80%
rename from deploy/platform/docker/docker-compose.yaml
rename to deploy/platform/docker/docker-compose.single-node.yaml
index ee1a435..dfc0bc6 100644
--- a/deploy/platform/docker/docker-compose.yaml
+++ b/deploy/platform/docker/docker-compose.single-node.yaml
@@ -41,13 +41,13 @@ services:
     image: ${SW_OAP_IMAGE}
     networks: [ sw ]
     environment:
-      SW_HEALTH_CHECKER: default
-      SW_OTEL_RECEIVER: default
-      SW_OTEL_RECEIVER_ENABLED_OC_RULES: vm
-      SW_PROMETHEUS_FETCHER: "default"
+      SW_HEALTH_CHECKER: default # @feature: health-check;
+      SW_OTEL_RECEIVER: default # @feature: vm; enable the OC receiver that receives the VM metrics
+      SW_OTEL_RECEIVER_ENABLED_OC_RULES: vm # @feature: vm; enable the OC rules that analyse the VM metrics
       SW_STORAGE: elasticsearch
       SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
-      SW_TELEMETRY: prometheus
+      SW_TELEMETRY: prometheus # @feature: so11y; expose the metrics of self o11y through prometheus
+      SW_PROMETHEUS_FETCHER: default # @feature: so11y; fetch the metrics of self o11y through prometheus
       JAVA_OPTS: "-Xms2048m -Xmx2048m"
     healthcheck:
       test: [ "CMD-SHELL", "/skywalking/bin/swctl ch" ]
diff --git a/deploy/platform/docker/docker-compose.vm.yaml b/deploy/platform/docker/docker-compose.vm.yaml
index ac868f1..fcc5026 100644
--- a/deploy/platform/docker/docker-compose.vm.yaml
+++ b/deploy/platform/docker/docker-compose.vm.yaml
@@ -15,6 +15,9 @@
 # specific language governing permissions and limitations
 # under the License.
 #
+
+# @feature: vm; set up VM node exporter and OpenTelemetry collector
+
 version: '2.1'
 
 services:
diff --git a/deploy/platform/kubernetes/Makefile b/deploy/platform/kubernetes/Makefile
index 02e539f..2e161b6 100644
--- a/deploy/platform/kubernetes/Makefile
+++ b/deploy/platform/kubernetes/Makefile
@@ -18,10 +18,32 @@
 
 include ../../../Makefile.in
 
+ifeq ($(FEATURE_FLAGS),all)
+  features := $(wildcard feature-*)
+else
+  features := $(subst $(comma), ,$(FEATURE_FLAGS))
+  features := $(foreach f,$(features),feature-$(f))
+endif
+
+resources := $(foreach dir,$(features),$(wildcard $(dir)/*))
+resources := $(resources) resources.yaml # Basic resources are always applied
+
+resources_deploy := $(foreach r,$(resources),$(r).deploy)
+.PHONY: $(resources_deploy)
+$(resources_deploy): %.deploy: %
+	@docker run --rm -v "$(shell pwd)/$<":/input \
+		$(foreach v,$(EXPORTED_VARS),-e $(v)) \
+		bhgedigital/envsubst sh -c "envsubst < /input" | kubectl apply -f -
+
 .PHONY: deploy
-deploy:
-	echo 'TODO'
+deploy: $(resources_deploy)
+
+resources_undeploy := $(foreach r,$(resources),$(r).undeploy)
+.PHONY: $(resources_undeploy)
+$(resources_undeploy): %.undeploy: %
+	@docker run --rm -v "$(shell pwd)/$<":/input \
+		$(foreach v,$(EXPORTED_VARS),-e $(v)) \
+		bhgedigital/envsubst sh -c "envsubst < /input" | kubectl delete --ignore-not-found -f -
 
 .PHONY: undeploy
-undeploy:
-	echo 'TODO'
+undeploy: $(resources_undeploy)
diff --git a/deploy/platform/kubernetes/feature-agent/resources.yaml b/deploy/platform/kubernetes/feature-agent/resources.yaml
new file mode 100644
index 0000000..c12e3d1
--- /dev/null
+++ b/deploy/platform/kubernetes/feature-agent/resources.yaml
@@ -0,0 +1,181 @@
+# 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.
+#
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: gateway
+spec:
+  selector:
+    app: gateway
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 80
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: gateway-deployment
+  labels:
+    app: gateway
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: gateway
+  template:
+    metadata:
+      labels:
+        app: gateway
+    spec:
+      containers:
+        - name: gateway
+          image: ${HUB}/gateway-service:${TAG}
+          ports:
+            - containerPort: 80
+          env:
+            - name: SW_AGENT_NAME
+              value: gateway
+            - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
+              value: oap:11800
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: songs
+spec:
+  selector:
+    app: songs
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 80
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: songs-deployment
+  labels:
+    app: songs
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: songs
+  template:
+    metadata:
+      labels:
+        app: songs
+    spec:
+      containers:
+        - name: songs
+          image: ${HUB}/songs-service:${TAG}
+          ports:
+            - containerPort: 80
+          env:
+            - name: SW_AGENT_NAME
+              value: songs
+            - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
+              value: oap:11800
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: rcmd
+spec:
+  selector:
+    app: recommendation
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 80
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: recommendation-deployment
+  labels:
+    app: recommendation
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: recommendation
+  template:
+    metadata:
+      labels:
+        app: recommendation
+    spec:
+      containers:
+        - name: recommendation
+          image: ${HUB}/recommendation-service:${TAG}
+          ports:
+            - containerPort: 80
+          env:
+            - name: SW_AGENT_NAME
+              value: recommendation
+            - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
+              value: oap:11800
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: app
+spec:
+  selector:
+    app: app
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 80
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: app-deployment
+  labels:
+    app: app
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: app
+  template:
+    metadata:
+      labels:
+        app: app
+    spec:
+      containers:
+        - name: app
+          image: ${HUB}/app:${TAG}
+          ports:
+            - containerPort: 80
+          env:
+            - name: SW_AGENT_NAME
+              value: app
+            - name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
+              value: oap:11800
diff --git a/deploy/platform/kubernetes/feature-single-node/resources.yaml b/deploy/platform/kubernetes/feature-single-node/resources.yaml
new file mode 100644
index 0000000..29d3583
--- /dev/null
+++ b/deploy/platform/kubernetes/feature-single-node/resources.yaml
@@ -0,0 +1,156 @@
+# 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.
+#
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: elasticsearch
+spec:
+  selector:
+    app: elasticsearch
+  ports:
+    - protocol: TCP
+      port: 9200
+      targetPort: 9200
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: es-deployment
+  labels:
+    app: elasticsearch
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: elasticsearch
+  template:
+    metadata:
+      labels:
+        app: elasticsearch
+    spec:
+      containers:
+        - name: elasticsearch
+          image: docker.elastic.co/elasticsearch/elasticsearch-oss:${ES_VERSION}
+          ports:
+            - containerPort: 9200
+          env:
+            - name: 'discovery.type'
+              value: 'single-node'
+            - name: 'bootstrap.memory_lock'
+              value: 'true'
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: oap
+spec:
+  selector:
+    app: oap
+  ports:
+    - name: grpc
+      protocol: TCP
+      port: 11800
+      targetPort: 11800
+    - name: http
+      protocol: TCP
+      port: 12800
+      targetPort: 12800
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: oap-deployment
+  labels:
+    app: oap
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: oap
+  template:
+    metadata:
+      labels:
+        app: oap
+    spec:
+      containers:
+        - name: oap
+          image: ${SW_OAP_IMAGE}
+          resources:
+            limits:
+              cpu: 2000m
+              memory: "2048Mi"
+            requests:
+              cpu: 1000m
+              memory: "1024Mi"
+          ports:
+            - containerPort: 11800
+            - containerPort: 12800
+          env:
+            - name: SW_HEALTH_CHECKER
+              value: default
+            - name: SW_OTEL_RECEIVER
+              value: default
+            - name: SW_OTEL_RECEIVER_ENABLED_OC_RULES
+              value: vm
+            - name: SW_STORAGE
+              value: elasticsearch
+            - name: SW_STORAGE_ES_CLUSTER_NODES
+              value: elasticsearch:9200
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: rocket-bot
+spec:
+  selector:
+    app: rocket-bot
+  ports:
+    - protocol: TCP
+      port: 8080
+      targetPort: 8080
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: rocket-bot-deployment
+  labels:
+    app: rocket-bot
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: rocket-bot
+  template:
+    metadata:
+      labels:
+        app: rocket-bot
+    spec:
+      containers:
+        - name: rocket-bot
+          image: ${SW_ROCKET_BOT_IMAGE}
+          ports:
+            - containerPort: 8080
+          env:
+            - name: SW_OAP_ADDRESS
+              value: oap:12800
diff --git a/deploy/platform/kubernetes/feature-vm/resources.yaml b/deploy/platform/kubernetes/feature-vm/resources.yaml
new file mode 100644
index 0000000..1cf6bae
--- /dev/null
+++ b/deploy/platform/kubernetes/feature-vm/resources.yaml
@@ -0,0 +1,121 @@
+# 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.
+#
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: vm
+spec:
+  selector:
+    app: vm
+  ports:
+    - protocol: TCP
+      port: 9100
+      targetPort: 9100
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: vm-deployment
+  labels:
+    app: vm
+spec:
+  replicas: 2
+  selector:
+    matchLabels:
+      app: vm
+  template:
+    metadata:
+      labels:
+        app: vm
+    spec:
+      containers:
+        - name: vm
+          image: quay.io/prometheus/node-exporter:v1.2.2
+          ports:
+            - containerPort: 9100
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: otel-collector-conf
+  labels:
+    app: opentelemetry
+    component: otel-collector-conf
+data:
+  otel-collector-config: |
+    receivers:
+      prometheus:
+        config:
+          scrape_configs:
+            - job_name: 'otel-collector'
+              scrape_interval: 10s
+              static_configs:
+                - targets: [ 'vm:9100' ]
+
+    processors:
+      batch:
+
+    exporters:
+      opencensus:
+        endpoint: "oap:11800"
+        insecure: true
+      logging:
+        logLevel: debug
+
+    service:
+      pipelines:
+        metrics:
+          receivers: [ prometheus ]
+          processors: [ batch ]
+          exporters: [ opencensus,logging ]
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: otel-deployment
+  labels:
+    app: otel
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: otel
+  template:
+    metadata:
+      labels:
+        app: otel
+    spec:
+      containers:
+        - name: otel
+          image: otel/opentelemetry-collector:0.29.0
+          command:
+            - "/otelcol"
+            - "--config=/conf/otel-collector-config.yaml"
+          volumeMounts:
+            - name: otel-collector-config-vol
+              mountPath: /conf
+      volumes:
+        - name: otel-collector-config-vol
+          configMap:
+            name: otel-collector-conf
+            items:
+              - key: otel-collector-config
+                path: otel-collector-config.yaml
diff --git a/scripts/make/help.mk b/scripts/make/help.mk
index 2e9cc27..0ca065d 100644
--- a/scripts/make/help.mk
+++ b/scripts/make/help.mk
@@ -8,7 +8,8 @@ define usage
 
   or via environment variable:
 
-  $$ export FEATURE_FLAGS=agent,vm && make deploy.docker
+  $$ export FEATURE_FLAGS=single-node,agent,vm && make deploy.docker
+  $$ export FEATURE_FLAGS=cluster,agent,vm && make deploy.docker
 endef
 
 export usage
@@ -21,3 +22,14 @@ help:  ## Display this help
 	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} \
 			/^[.a-zA-Z0-9_-]+:.*?##/ { printf "  \033[36m%-15s\033[0m \t%s\n", $$1, $$2 } \
 			/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
+
+features := $(subst $(comma), ,$(FEATURE_FLAGS))
+features := $(foreach f,$(features),@feature: *$(f)*)
+
+.PHONY: highlight
+highlight:  ## Highlight the important points of a feature
+	@if [ "$(FEATURE_FLAGS)" = "" ]; then \
+	  echo 'FEATURE_FLAGS must be set in highlight target'; \
+  	  exit 1; \
+  	fi
+	@grep --color -rnw . -e "$(features)"
diff --git a/services/app/Dockerfile b/services/app/Dockerfile
index 9900a4d..72747ea 100644
--- a/services/app/Dockerfile
+++ b/services/app/Dockerfile
@@ -20,7 +20,7 @@ FROM node:10
 ARG SW_AGENT_NODEJS_BACKEND_VERSION
 ARG SW_AGENT_NODEJS_FRONTEND_VERSION
 
-WORKDIR /skywalking-nodejs-backend
+WORKDIR /skywalking-backend-js
 
 RUN git clone --recurse-submodules https://github.com/apache/skywalking-nodejs.git . ; \
     git reset --hard ${SW_AGENT_NODEJS_BACKEND_VERSION} ; \
@@ -29,7 +29,7 @@ RUN git clone --recurse-submodules https://github.com/apache/skywalking-nodejs.g
     npm install ; \
     npm run build
 
-WORKDIR /skywalking-nodejs-frontend
+WORKDIR /skywalking-client-js
 
 RUN git clone --recurse-submodules https://github.com/apache/skywalking-client-js.git . ; \
     git reset --hard ${SW_AGENT_NODEJS_FRONTEND_VERSION} ; \
@@ -42,8 +42,11 @@ WORKDIR /app
 
 COPY . .
 
-RUN npm install /skywalking-nodejs-backend ; \
-    npm install /skywalking-nodejs-frontend ; \
+RUN \
+    # @feature: nodejs-agent-backend; install skywalking-backend-js
+    npm install /skywalking-backend-js ; \
+    # @feature: nodejs-agent-frontend; install skywalking-client-js
+    npm install /skywalking-client-js ; \
     npm run build
 
 CMD npm start
diff --git a/services/app/server/index.js b/services/app/server/index.js
index 5662982..5a10413 100644
--- a/services/app/server/index.js
+++ b/services/app/server/index.js
@@ -22,6 +22,7 @@ const express = require('express');
 const axios = require('axios');
 const {default: agent} = require('skywalking-backend-js');
 
+// @feature: nodejs-agent-backend;
 agent.start({
     serviceName: 'app',
     maxBufferSize: 1000,
diff --git a/services/app/ui/src/index.js b/services/app/ui/src/index.js
index 0609cb1..b222d48 100644
--- a/services/app/ui/src/index.js
+++ b/services/app/ui/src/index.js
@@ -26,6 +26,7 @@ import ClientMonitor from 'skywalking-client-js';
 
 const OAP = process.env.OAP || 'oap';
 
+// @feature: nodejs-agent-frontend;
 ClientMonitor.register({
     collector: `http://${OAP}:12800`,
     service: 'ui',
diff --git a/services/gateway-service/Dockerfile b/services/gateway-service/Dockerfile
index f0e4c97..9164054 100644
--- a/services/gateway-service/Dockerfile
+++ b/services/gateway-service/Dockerfile
@@ -16,6 +16,7 @@
 # under the License.
 #
 
+# @feature: java-agent;
 FROM ghcr.io/apache/skywalking-java/jdk-11:latest
 
 COPY build/libs/gateway-service-0.0.1-SNAPSHOT.jar /app.jar
diff --git a/services/recommendation-service/Dockerfile b/services/recommendation-service/Dockerfile
index 2755a0a..40f36fa 100644
--- a/services/recommendation-service/Dockerfile
+++ b/services/recommendation-service/Dockerfile
@@ -15,6 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 #
+
+# @feature: python-agent;
 FROM apache/skywalking-python:0.7.0-grpc-py3.9
 
 WORKDIR /workspace
diff --git a/services/songs-service/Dockerfile b/services/songs-service/Dockerfile
index 28c4938..d7cde50 100644
--- a/services/songs-service/Dockerfile
+++ b/services/songs-service/Dockerfile
@@ -16,6 +16,7 @@
 # under the License.
 #
 
+# @feature: java-agent;
 FROM ghcr.io/apache/skywalking-java/jdk-11:latest
 
 COPY build/libs/songs-service-0.0.1-SNAPSHOT.jar /app.jar