All Products
Search
Document Center

Application Real-Time Monitoring Service:End-to-end canary release and monitoring for Go applications with ARMS and ASM

Last Updated:Mar 11, 2026

When you run Go microservices on Kubernetes, validating a new version across an entire call chain before full rollout reduces production risk. By combining Application Real-Time Monitoring Service (ARMS) with Service Mesh (ASM) traffic lanes, you can route canary traffic end-to-end through a Go service chain and monitor both baseline and canary versions in real time.

How it works

The sample architecture consists of four Go services deployed in the go-gray namespace:

requestsender (entry) > go-demo-a > go-demo-b > go-demo-c

Each service (A, B, C) runs two versions:

  • v1 (baseline): The stable production version.

  • v2 (canary): The version under validation.

In this setup, only go-demo-a and go-demo-c have canary versions. go-demo-b uses the baseline version in both lanes -- a common pattern where not every service in the call chain needs a canary release.

ASM traffic lanes route requests based on the x-asm-prefer-tag header:

  • x-asm-prefer-tag: v1 -- all requests flow through baseline versions (A:base > B:base > C:base).

  • x-asm-prefer-tag: v2 -- requests route to canary versions where available (A:gray > B:base > C:gray).

The ARMS Go agent provides application-level observability across both lanes, including topology maps, API call analysis, and database monitoring.

Architecture diagram

Prerequisites

Before you begin, make sure that you have:

  • A Kubernetes cluster (ACK or self-managed) with kubectl access

  • Familiarity with Kubernetes Deployments, Services, and Istio concepts

Sample applications

All sample applications are deployed in the go-gray namespace.

Key labels

Each pod carries labels that enable ARMS monitoring and ASM traffic routing:

LabelPurposeValues
ASM_TRAFFIC_TAGIdentifies the traffic lane for ASM routingv1 (baseline), v2 (canary)
versionVersion identifier used by Istio routingv1, v2
armsPilotCreateAppNameRegisters the application name in ARMSApplication name (e.g., go-demo-a)
armsPilotAutoEnableEnables automatic ARMS agent injectionon
aliyun.com/app-languageSpecifies the application language for agent selectiongolang

Application manifests

Note

The Kubernetes labels on each pod serve two purposes: ARMS agent injection (armsPilotAutoEnable, armsPilotCreateAppName, aliyun.com/app-language) and ASM traffic routing (ASM_TRAFFIC_TAG, version).

  • Entry application (requestsender)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: requestsender
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: requestsender
      template:
        metadata:
          labels:
            app: requestsender
            ASM_TRAFFIC_TAG: v1
            version: v1
            armsPilotCreateAppName: requestsender
            armsPilotAutoEnable: 'on'
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: requestsender
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:requestsender-demo
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: requestsender
      namespace: go-gray
    spec:
      selector:
        app: requestsender
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
      type: ClusterIP
  • Application A (go-demo-a) -- baseline and canary

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo-a-base
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-demo-a
      template:
        metadata:
          labels:
            app: go-demo-a
            armsPilotAutoEnable: "on"
            ASM_TRAFFIC_TAG: v1
            version: v1
            armsPilotCreateAppName: "go-demo-a"
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: go-demo-a
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:a-demo
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo-a-gray
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-demo-a
      template:
        metadata:
          labels:
            app: go-demo-a
            ASM_TRAFFIC_TAG: v2
            version: v2
            armsPilotCreateAppName: go-demo-a
            armsPilotAutoEnable: 'on'
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: go-demo-a-base
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:a-demo-gray
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: go-demo-a
      namespace: go-gray
    spec:
      selector:
        app: go-demo-a
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
      type: ClusterIP
  • Application B (go-demo-b) -- baseline and canary

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo-b-base
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-demo-b
      template:
        metadata:
          labels:
            app: go-demo-b
            ASM_TRAFFIC_TAG: v1
            version: v1
            armsPilotCreateAppName: go-demo-b
            armsPilotAutoEnable: 'on'
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: go-demo-b
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:b-demo
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo-b-gray
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-demo-b
      template:
        metadata:
          labels:
            app: go-demo-b
            ASM_TRAFFIC_TAG: v2
            version: v2
            armsPilotCreateAppName: go-demo-b
            armsPilotAutoEnable: 'on'
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: go-demo-b
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:b-demo-gray
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: go-demo-b
      namespace: go-gray
    spec:
      selector:
        app: go-demo-b
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
      type: ClusterIP
  • Application C (go-demo-c) -- baseline and canary

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo-c-base
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-demo-c
      template:
        metadata:
          labels:
            app: go-demo-c
            ASM_TRAFFIC_TAG: v1
            version: v1
            armsPilotCreateAppName: go-demo-c
            armsPilotAutoEnable: 'on'
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: go-demo-c
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:c-demo
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-demo-c-gray
      namespace: go-gray
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-demo-c
      template:
        metadata:
          labels:
            app: go-demo-c
            ASM_TRAFFIC_TAG: v2
            version: v2
            armsPilotCreateAppName: go-demo-c
            armsPilotAutoEnable: 'on'
            aliyun.com/app-language: golang
        spec:
          containers:
            - name: go-demo-c
              image: registry.cn-hangzhou.aliyuncs.com/private-mesh/hellob:c-demo-gray
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: go-demo-c
      namespace: go-gray
    spec:
      selector:
        app: go-demo-c
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
      type: ClusterIP

Step 1: Install the ARMS Go agent

Install the ARMS agent to integrate the sample applications into ARMS Application Monitoring. After installation, application topology, API calls, and database analysis become available in the ARMS console.

Choose the installation method based on your cluster type:

Cluster typeInstallation guide
Container Service for Kubernetes (ACK)Install an ARMS agent for a Go application deployed in ACK
Self-managed KubernetesAutomatically install an ARMS agent for Go in a Kubernetes cluster

Step 2: Set up ASM for end-to-end canary release

2.1 Create an ASM instance and add a cluster

Create an ASM instance and add your Kubernetes cluster to it.

2.2 Create an ingress gateway

Create an ingress gateway for the ASM instance.

2.3 Create an Istio gateway

Create an Istio gateway named ingressgateway in the istio-system namespace. For detailed instructions, see Manage Istio gateways.

Use the following YAML:

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: ingressgateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'

2.4 Inject sidecar proxies

Inject sidecar proxies into the sample applications and restart them. For instructions, see Install a sidecar proxy.

2.5 Enable distributed tracing

Distributed tracing propagates trace context across services, enabling end-to-end observability for canary routing.

  1. Create a namespace for the OpenTelemetry collector:

       kubectl create namespace opentelemetry-operator-system
  2. Deploy the tracing collector service:

       apiVersion: v1
       kind: Service
       metadata:
         name: default-collector
         namespace: opentelemetry-operator-system
       spec:
         ports:
           - port: 4317
             protocol: TCP
             targetPort: 4317
         selector:
           app: default-collector
         sessionAffinity: None
         type: ClusterIP
  3. In the ASM console, enable tracing with the following settings:

    ParameterValue
    OpenTelemetry FQDNdefault-collector.opentelemetry-operator-system.svc.cluster.local
    OpenTelemetry port4317

    Enable tracing in the ASM console

  4. On the Observability Settings page, go to the Tracing Analysis Settings section. Enable tracing and configure the sample rate.

    Tracing analysis settings

2.6 Configure traffic lanes

Traffic lanes define how requests route to different service versions. For background information, see Create lanes.

Create a lane group

Create a lane group named test with the following settings:

ParameterValue
Trace ID Request Headertraceparent
Routing Request Headerx-asm-prefer-tag
Swimlane Servicesrequestsender, go-demo-a, go-demo-b, go-demo-c
Lane group configuration

Create lanes

Create two lanes, v1 (baseline) and v2 (canary). Under Configure Service Tag, set the label key and value for each lane:

Parameterv1 (baseline)v2 (canary)
Swimlane Namev1v2
Label KeyASM_TRAFFIC_TAGASM_TRAFFIC_TAG
Label Valuev1v2
Add Servicerequestsender, go-demo-a, go-demo-b, go-demo-cgo-demo-a, go-demo-c
Note

The v2 lane only includes go-demo-a and go-demo-c. Requests to go-demo-b fall back to the baseline version automatically.

Configure routing rules

Set up Ingress traffic rules for the v1 and v2 lanes:

ParameterValue
Ingress servicerequestsender.go-gray.svc.cluster.local
Namev1 and v2
Domain Name*
Matching MethodExact
Content/greetinit
Routing rules configuration

Step 3: Verify the canary release

Get the ingress gateway IP

  1. In the ARMS console, go to ASM Gateway > Ingress Gateway.

  2. Copy the public IP address of the ingress gateway.

  3. Set an environment variable: Replace <ingress-gateway-ip> with the IP address from the previous step.

       export ASM_GATEWAY_IP=<ingress-gateway-ip>

Test baseline routing (v1)

Send requests with the x-asm-prefer-tag: v1 header. All services in the call chain return their baseline versions:

for i in {1..100}; do curl -H 'x-asm-prefer-tag: v1' http://${ASM_GATEWAY_IP}/greetinit; echo ''; sleep 1; done;

Expected output:

{"code":0,"data":{"greeting":"Hello ","callChain":"Init:base:172.30.208.29 - A:base:172.30.208.114 - B:base:172.30.208.116 - C:base:172.30.208.120"},"message":"success"}

Every hop in the callChain field shows base, confirming that all traffic stays in the baseline lane.

Test canary routing (v2)

Send requests with the x-asm-prefer-tag: v2 header. Services with canary versions (A and C) return their canary versions, while B returns the baseline:

for i in {1..100}; do curl -H 'x-asm-prefer-tag: v2' http://${ASM_GATEWAY_IP}/greetinit; echo ''; sleep 1; done;

Expected output:

{"code":0,"data":{"greeting":"Hello ","callChain":"Init:base:172.30.208.29 - A:gray:172.30.208.115 - B:base:172.30.208.116 - C:gray:172.30.208.122"},"message":"success"}

The callChain field shows A:gray and C:gray, while B:base confirms that go-demo-b falls back to the baseline lane as expected.

Monitor baseline and canary versions in ARMS

After you send traffic to both lanes, use ARMS to compare the performance of baseline and canary versions:

  1. Log on to the ARMS console.

  2. In the left-side navigation pane, choose Application Monitoring > Applications.

  3. On the Applications page, locate the deployed services. Each service registered through the armsPilotCreateAppName label appears as a separate application entry.

Application monitoring view

Use the application topology and API call analysis to compare error rates, latency, and throughput between the baseline and canary versions.

Related topics