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:19 UTC

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

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