Cloud Service Mesh by example: canary deployments

Note: This guide only supports Cloud Service Mesh with Istio APIs and doesnot support Google Cloud APIs. For more information see,Cloud Service Mesh overview.

In this tutorial, you walk through a common use case: rolling out acanary deployment with Cloud Service Mesh using Istio APIs.

What is a canary deployment?

A canary deployment routes a small percentage of traffic to a new version of amicroservice, then gradually increases that percentage while phasing out andretiring the old version. If something goes wrong during this process, trafficcan be switched back to the earlier version. With Cloud Service Mesh, you canroute traffic to ensure that new services are introduced safely.

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use thepricing calculator.

New Google Cloud users might be eligible for afree trial.

When you finish this tutorial, you can avoid ongoing costs by deleting theresources you created. For more information, seeClean up.

Before you begin

Deploy Online Boutique

  1. Set the current context forkubectl to the cluster where you plan to deploy Online Boutique. The command depends on whether you provisioned Cloud Service Mesh on a GKE cluster or a Kubernetes cluster outside GKE:

    GKE on Google Cloud

    gcloud container clusters get-credentialsCLUSTER_NAME  \    --project=PROJECT_ID \    --zone=CLUSTER_LOCATION

    GKE outside Google Cloud

    kubectl config use-contextCLUSTER_NAME
  2. Create the namespace for the sample application and the ingress gateway:

    kubectl create namespace onlineboutique
  3. Label theonlineboutique namespace to automatically inject Envoy proxies. Follow the steps onhow to enable automatic sidecar injection.

  4. Deploy the sample app. For this tutorial, you deployOnline Boutique,a microservice demo app.

    kubectl apply \-n onlineboutique \-f https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-samples/main/docs/shared/online-boutique/kubernetes-manifests.yaml
  5. Add a labelversion=v1 to theproductcatalog deployment by running the following command:

    kubectl patch deployments/productcatalogservice -p '{"spec":{"template":{"metadata":{"labels":{"version":"v1"}}}}}' \-n onlineboutique

    View the services that you deployed:

    kubectl get pods -n onlineboutique

    Expected output:

    NAME                                     READY   STATUS    RESTARTS   AGEadservice-85598d856b-m84m6               2/2     Running   0          2m7scartservice-c77f6b866-m67vd              2/2     Running   0          2m8scheckoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10scurrencyservice-59bc889674-jhk8z         2/2     Running   0          2m8semailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10sfrontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9sloadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8spaymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9sproductcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114srecommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9sredis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7sshippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s

    A2/2 in theREADY column indicates that a pod is up and running with an Envoyproxy successfully injected.

  6. Deploy yourVirtualService andDestinationRule for v1 ofproductcatalog:

     kubectl apply -f destination-vs-v1.yaml -n onlineboutique
    apiVersion:networking.istio.io/v1beta1kind:DestinationRulemetadata:name:productcatalogservicespec:host:productcatalogservicesubsets:-labels:version:v1name:v1---apiVersion:networking.istio.io/v1beta1kind:VirtualServicemetadata:name:productcatalogservicespec:hosts:-productcatalogservicehttp:-route:-destination:host:productcatalogservicesubset:v1

    Note that onlyv1 is present in the resources.

    View theDestination Rule created.

      kubectl get destinationrules -n onlineboutique

    Expected output:

      NAME                    HOST                    AGE  productcatalogservice   productcatalogservice   2m

    View theVirtualService created.

      kubectl get virtualservices -n onlineboutique

    Expected outcome:

      NAME                    GATEWAYS   HOSTS                       AGE  productcatalogservice              ["productcatalogservice"]   2m
  7. Visit the application in your browser using the external IP address of your ingress gateway:

    kubectl get services -nGATEWAY_NAMESPACE

This next section tours the Cloud Service Mesh UI and show how you can viewyour metrics.

View your services in Google Cloud console

  1. In Google Cloud console, go to theGoogle Kubernetes Engine (GKE) Enterprise edition Services page.

    Go to Google Kubernetes Engine (GKE) Enterprise edition Services

  2. By default, you view your services in theList view.

    The Table Overview lets you observe all your services, as well as important metrics at a glance.

  3. In the top right, clickTopology. Here you can view your services and their interaction with each other.

    You can expandServices and view theRequests per second for each of your services by hovering over on them with your cursor.

  4. Navigate back to theTable View.

  5. In theServices Table, selectproductcatalogservice. This takes you to an overview of your service.

  6. On the left side of the screen, clickTraffic.

  7. Ensure 100% of the incoming traffic toproductcatalogservice goes to the workload service.

The next section goes through creating a v2 of theproductcatalog service.

Deploy v2 of a service

  1. For this tutorial,productcatalogservice-v2 introduces a 3-second latency into requests with theEXTRA_LATENCY field. This simulates a regression in the new version of the service.

    apiVersion:apps/v1kind:Deploymentmetadata:name:productcatalogservice-v2spec:selector:matchLabels:app:productcatalogservicetemplate:metadata:labels:app:productcatalogserviceversion:v2spec:containers:-env:-name:PORTvalue:'3550'-name:EXTRA_LATENCYvalue:3sname:serverimage:gcr.io/google-samples/microservices-demo/productcatalogservice:v0.3.6livenessProbe:exec:command:["/bin/grpc_health_probe","-addr=:3550"]ports:-containerPort:3550readinessProbe:exec:command:["/bin/grpc_health_probe","-addr=:3550"]resources:limits:cpu:200mmemory:128Mirequests:cpu:100mmemory:64MiterminationGracePeriodSeconds:5

    Apply this resource to theonlineboutique namespace.

    kubectl apply -f productcatalog-v2.yaml -n onlineboutique
  2. Check on your application pods.

    kubectl get pods -n onlineboutique

    Expected output:

    NAME                                     READY   STATUS    RESTARTS   AGEadservice-85598d856b-8wqfd                  2/2     Running   0          25hcartservice-c77f6b866-7jwcr                 2/2     Running   0          25hcheckoutservice-654c47f4b6-n8c6x            2/2     Running   0          25hcurrencyservice-59bc889674-l5xw2            2/2     Running   0          25hemailservice-5b9fff7cb8-jjr89               2/2     Running   0          25hfrontend-77b88cc7cb-bwtk4                   2/2     Running   0          25hloadgenerator-6958f5bc8b-lqmnw              2/2     Running   0          25hpaymentservice-68dd9755bb-dckrj             2/2     Running   0          25hproductcatalogservice-84f95c95ff-ddhjv      2/2     Running   0          25hproductcatalogservice-v2-6df4cf5475-9lwjb   2/2     Running   0          8srecommendationservice-64dc9dfbc8-7s7cx      2/2     Running   0          25hredis-cart-5b569cd47-vw7lw                  2/2     Running   0          25hshippingservice-5488d5b6cb-dj5gd            2/2     Running   0          25h

    Note that there are now twoproductcatalogservices listed.

  3. UseDestinationRule to specify the subsets of a service. In this scenario, there is a subset for v1 and then a separate subset for v2 ofproductcatalogservice.

    apiVersion:networking.istio.io/v1beta1kind:DestinationRulemetadata:name:productcatalogservicespec:host:productcatalogservicesubsets:-labels:version:v1name:v1-labels:version:v2name:v2

    Note thelabels field. The versions ofproductcatalogservice are distinguished after the traffic is routed by theVirtualService.

    Apply theDestinationRule:

    kubectl apply -f destination-v1-v2.yaml -n onlineboutique

Split traffic between v1 and v2

  1. UseVirtualService to define a small percentage of the traffic to direct to v2 of theproductcatalogservice.

    apiVersion:networking.istio.io/v1beta1kind:VirtualServicemetadata:name:productcatalogservicespec:hosts:-productcatalogservicehttp:-route:-destination:host:productcatalogservicesubset:v1weight:75-destination:host:productcatalogservicesubset:v2weight:25

    The subset field indicates the version, and the weight field indicates the percentage split of traffic. 75% of traffic goes to v1 of productcatalog, and 25% goes to v2.

    Apply theVirtualService:

    kubectl apply -f vs-split-traffic.yaml -n onlineboutique

If you visit theEXTERNAL_IP of the cluster's ingress, you should notice that periodically, the frontend is slower to load.

In the next section, explore the traffic split in Google Cloud console.

Observe the traffic split in Google Cloud console

  1. Return to Google Cloud console and go to the GKE Enterprise Services page.Go to GKE Enterprise Services

  2. In the top right, clickTopology.

    Expand theproductcatalogservice workload and note theproductcatalogservice andproductcatalogservice-v2 deployments.

  3. Return to theTable View.

  4. Clickproductcatalogservice in the Services Table.

  5. Return toTraffic on the left navigation bar.

  6. Note that the incoming traffic is split between v1 and v2 by the percentage specified in theVirtualService file, and that there are 2 workloads of the productcatalog service.

    On the right side of the page, you seeRequests,Error Rate, andLatency Metrics. With Cloud Service Mesh, each service has these metrics outlined to provide you with observability metrics.

    Note: It may take some time for the actual 75-25 split to be shown, since traffic over time is redirected to thev2 service.

Roll out or roll back to a version

After observing the metrics during a canary deployment, you can complete the roll out the new service version, or roll back to the original service version by leveraging theVirtualService resource.

Roll out

After you are satisfied with the behavior of a v2 service, you can incrementallyincrease the percentage of traffic directed to the v2 service. Eventually,traffic can be 100% directed to the new service in the VirtualService resourceyou created above by removing the traffic split from that resource.

To direct all the traffic to v2 ofproductcatalogservice:

kubectl apply -f vs-v2.yaml -n onlineboutique

Roll back

If you need to roll back to the v1 service, apply thedestination-vs-v1.yaml from earlier. This directs traffic only to v1 ofproductcatalogservice.

apiVersion:networking.istio.io/v1beta1kind:VirtualServicemetadata:name:productcatalogservicespec:hosts:-productcatalogservicehttp:-route:-destination:host:productcatalogservicesubset:v1

To direct all the traffic to v1 ofproductcatalogservice:

kubectl apply -f vs-v1.yaml -n onlineboutique

Clean up

To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.

To avoid incurring continuing charges to your Google Cloud account forthe resources used in this tutorial, you can either delete the project or deletethe individual resources.

Delete the project

Caution: Deleting a project has the following effects:
  • Everything in the project is deleted. If you used an existing project for this tutorial, when you delete it, you also delete any other work you've done in the project.
  • Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as an appspot.com URL, delete selected resources inside the project instead of deleting the whole project.

In Cloud Shell, delete the project:

gcloud projects deletePROJECT_ID

Delete the resources

If you want to prevent additional charges, delete the cluster:

gcloud container clusters deleteCLUSTER_NAME  \  --project=PROJECT_ID \  --zone=CLUSTER_LOCATION

If you registered your cluster with fleet usinggcloud container fleet memberships(rather than--enable-fleet or--fleet-project during cluster creation)then remove the stale membership:

gcloud container fleet memberships deleteMEMBERSHIP  \  --project=PROJECT_ID

If you want to keep your cluster configured for Cloud Service Mesh but removethe Online Boutique sample:

  1. Delete the application namespaces:

    kubectl delete -f namespace onlineboutique

    Expected output:

    namespace "onlineboutique" deleted
  2. Delete the service entries:

    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/istio-manifests/frontend.yaml -n onlineboutiquekubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/istio-manifests/frontend-gateway.yaml -n onlineboutique

    Expected output:

    serviceentry.networking.istio.io "allow-egress-googleapis" deletedserviceentry.networking.istio.io "allow-egress-google-metadata" deleted

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.