Deploy ASP.NET Core app to Google Kubernetes Engine with Istio (Part 2)

1. Overview

In the first part of the lab, you created an ASP.NET Core application, containerized, and deployed it to Google Kubernetes Engine (GKE) and configured its traffic to be managed by Istio.

This second part of the lab assumes that you already have your Kubernetes cluster and the application from the first lab running. You will see how Istio can help to manage, monitor, and secure your services with minimal code changes. Specifically, you explore features of Istio such as metrics, tracing, service visualization, dynamic traffic management, fault injection, and more.

What you'll learn

  • How to query metrics with Prometheus.
  • How to visualize metrics with Grafana.
  • How to create a new version of your service.
  • How to pin a service to a specific version.
  • How to split traffic between different versions.
  • How to inject faults in service calls.

What you'll need

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would rate your experience with Google Cloud Platform?

Novice Intermediate Proficient

2. Setup and Requirements

Self-paced environment setup

  1. Sign in to Cloud Console and create a new project or reuse an existing one. (If you don't already have a Gmail or G Suite account, you must create one.)

H_hgylo4zxOllHaAbPKJ7VyqCKPDUnDhkr-BsBIFBsrB6TYSisg6LX-uqmMhh4sXUy_hoa2Qv87C2nFmkg-QAcCiZZp0qtpf6VPaNEEfP_iqt29KVLD-gklBWugQVeOWsFnJmNjHDw

dcCPqfBIwNO4R-0fNQLUC4aYXOOZhKhjUnakFLZJGeziw2ikOxGjGkCHDwN5x5kCbPFB8fiOzZnX-GfuzQ8Ox-UU15BwHirkVPR_0RJwl0oXrhqZmMIvZMa_uwHugBJIdx5-bZ6Z8Q

jgLzVCxk93d6E2bbonzATKA4jFZReoQ-fORxZZLEi5C3D-ubnv6nL-eP-iyh7qAsWyq_nyzzuEoPFD1wFOFZOe4FWhPBJjUDncnTxTImT3Ts9TM54f4nPpsAp52O0y3Cb19IceAEgQ

Remember the project ID, a unique name across all Google Cloud projects (the name above has already been taken and will not work for you, sorry!). It will be referred to later in this codelab as PROJECT_ID.

  1. Next, you'll need to enable billing in Cloud Console in order to use Google Cloud resources.

Running through this codelab shouldn't cost much, if anything at all. Be sure to to follow any instructions in the "Cleaning up" section which advises you how to shut down resources so you don't incur billing beyond this tutorial. New users of Google Cloud are eligible for the $300USD Free Trial program.

Start Cloud Shell

While Google Cloud can be operated remotely from your laptop, in this codelab you use Google Cloud Shell, a command line environment running in Google Cloud.

Activate Cloud Shell

  1. From the Cloud Console, click Activate Cloud Shell dnDTxS9j60RcXdTjea12HLB9paS9Gzf7PfFLE9RW8g0Qx1bz7nmCzyCu4rjluX3bOEwavOpDwioXEkzOf6xtZp6-ZbJa08jwJqtmeeW8jZ1tYfi2lyXqvW3WFHP0eAxDkQDfpO9Ljw.

yzBQBp2RC1EFvSSLYVkMA2m6LHqGsp22O81rUS5tGb9Y1FqlVhoRj_ka8V_uEjtpcirZRULMy1IjNr848uYvb9mC9RcGGqeayaLcXFfRwUGeXWChZPtWkHzUshTcqx_wJHis0X8viA

If you've never started Cloud Shell before, you'll be presented with an intermediate screen (below the fold) describing what it is. If that's the case, click Continue (and you won't ever see it again). Here's what that one-time screen looks like:

VgsaqGbKPRiqK24CqAKjSXjepuJT96PmiDqQMcySmWKx8QyW5F3G2D8JH2d08ek-YM77wWKxPvggpOFER8Hbq3aaZipTDU2o0il7A0kS3FXY_NzuujjEqDF1nsbDKkNMThrqcdMGtQ

It should only take a few moments to provision and connect to Cloud Shell.

7RuYr-LCKzdiE1veTFmL_lYrVxsMZ6-xDoxAnfwPPc5uFA0utmFGejvu81jGmTdbqnqxrytW3KcHT6xrMIRc3bskctnDZC5nJdpqw-LRxu3r35hL4A0BSBTtbtirfh3PKv-eOKt8Rg

This virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory and runs in Google Cloud, greatly enhancing network performance and authentication. Much, if not all, of your work in this codelab can be done with simply a browser or your Chromebook.

Once connected to Cloud Shell, you should see that you are already authenticated and that the project is already set to your project ID.

  1. Run the following command in Cloud Shell to confirm that you are authenticated:
gcloud auth list

Command output

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

Command output

[core]
project = <PROJECT_ID>

If it is not, you can set it with this command:

gcloud config set project <PROJECT_ID>

Command output

Updated property [core/project].

3. Test the application

Before you start the lab, make sure the application is still working from the previous lab. As a reminder, this is how you see the external IP and port of the gateway, which are listed under EXTERNAL-IP:

kubectl get svc istio-ingressgateway -n istio-system

To view the application, you can open your browser and navigate to http://<gatewayurl>:

f579a9baedc108a9.png

If you don't see the application, go back to the previous lab to make sure you followed all the steps and both the application and Istio are installed and running properly.

At this point, you might be wondering "What's the benefit of Istio?". By letting Istio manage your application's traffic, you get features like metrics, tracing, dynamic traffic management, service visualization, fault injection, and more for free.

You'll start with exploring metrics in the next step.

4. Metrics with Grafana and Prometheus

By default, Istio generates some metrics. You can use add-ons to query and visualize these default metrics.

Prometheus

Prometheus is an open-source monitoring solution. You can use Prometheus to query metrics generated by Istio but you need to first install Prometheus add-on.

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/prometheus.yaml

Verify that Prometheus is running:

kubectl get svc prometheus -n istio-system

NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
prometheus   ClusterIP   10.31.243.62   <none>        9090/TCP   1d

Send some traffic to the application by visiting http://<gatewayurl> a few times or running the curl command.

Setup port forwarding for the Prometheus UI:

kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=prometheus -o jsonpath='{.items[0].metadata.name}') 8080:9090

You can now execute a query by clicking on the Web Preview button in the top-right corner of Cloud Shell and click Preview on port 8080:

772a5248aa493025.png

You'll see the Prometheus UI in a new tab:

272ee63c1fe0be16.png

To learn more about Prometheus, see Querying Metrics with Prometheus.

Grafana

Grafana is another add-on for visualizing metrics.

Install Grafana. Replace istio-version with your current Istio version,for example, 1.0.3-gke.3:

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/grafana.yaml

Verify that Grafana is running:

kubectl get svc grafana -n istio-system

NAME      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
grafana   ClusterIP   10.31.248.230   <none>        3000/TCP   1d

Send some traffic to the application by visiting http://<gatewayurl> a few times or running the curl command.

Setup port forwarding for the Grafana UI:

kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 8080:3000

You can view Grafana dashboards by visiting Web Preview:

806d696d85267a37.png

524cb9f6d66f8655.png

To learn more about Granfana, see Visualizing Metrics with Grafana.

5. Create a new version of the application

At some point, the application that you've deployed to production will require bug fixes or additional features. Let's see how that process looks like.

First, let's modify the application. Open the code editor from Cloud Shell.

mxrggIJ2Zz8E47ULCEo4NywjM-EpSkZF5c3TQgfGx4nODwP2obiQXrwQjEEaXuBhJDA2jJ5evR7TuHIy1gsqqDRFm0Wh3xhZUu9tn_xb1ygFlBm1HKJqLdfz_aK7WJS33u2IBDO2oQ

Navigate to Index.cshtml under HelloWorldAspNetCore > Views > Home and update one of the carousel messages.

Find the following line:

Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core 

And change it to this:

Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core on Google Cloud

Save the changes and then go back to Cloud Shell. Inside HelloWorldAspNetCore,build the docker image:

docker build -t gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-dotnet:v2 . 

And push to the Container Registry:

docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-dotnet:v2 

After you push the container image, you can deploy the new version in the next step.

6. Create the new deployment

To deploy the new version, you first need to create a new deployment for it in Kubernetes. Add the following at the end of the aspnetcore.yaml file:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aspnetcore-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aspnetcore
      version: v2
  template:
    metadata:
      labels:
        app: aspnetcore
        version: v2
    spec:
      containers:
      - name: aspnetcore
        image: gcr.io/YOUR-PROJECT-ID/hello-dotnet:v2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

Deploy the new version to the default namespace with kubectl:

kubectl apply -f aspnetcore.yaml
service "aspnetcore" unchanged
deployment.extensions "aspnetcore-v1" unchanged
deployment.extensions "aspnetcore-v2" created

Verify that the expected pods are running:

kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
aspnetcore-v1-6cf64748-mddb   2/2       Running   0          34s
aspnetcore-v2-5d765db-l9xmg   2/2       Running   0          1m

Now, test the application again. Get the external IP of the gateway:

kubectl get svc istio-ingressgateway -n istio-system

It's listed under EXTERNAL-IP. Open up an incognito browser and visit http://<replace-with-external-ip>

When you refresh, sometimes, you'll see the message "Learn about building Web apps with ASP.NET Core":

11d528132dbb6cee.png

Other times, you'll see the message "Learn about building Web apps with ASP.NET Core on Google Cloud":

3eb0d5be1b4cb40b.png

This is because both v1 and v2 deployments are exposed behind the same Kubernetes service (aspnetcore-service) and the VirtualService you created in the previous lab (aspnetcore-virtualservice) uses that service as a host.

In the next step, you pin the service to the v2 deployment using a DestinationRule.

7. Pin your service to the new version

In this step, you pin your service to use the v2 deployment and you can do that with a DestinationRule. A DestinationRule configures the set of policies to be applied to a request after a VirtualService routing operation has occurred.

A DestinationRule also defines addressable subsets, meaning named versions, of the corresponding destination host. These subsets are used in VirtualService route specifications when sending traffic to specific versions of the service.

Create a new file called aspnetcore-destinationrule.yaml:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: aspnetcore-destinationrule
spec:
  host: aspnetcore-service
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

Next, create the DestinationRule. This creates two subsets (v1 and v2) that you can use from the VirtualService:

kubectl apply -f aspnetcore-destinationrule.yaml
destinationrule.networking.istio.io "aspnetcore-destionationrule" created

Now, go back to aspnetcore-virtualservice.yaml file to update the VirtualService to use the v2 subset:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aspnetcore-virtualservice
spec:
  hosts:
  - "*"
  gateways:
  - aspnetcore-gateway
  http:
  - route:
    - destination:
        host: aspnetcore-service
        subset: v2

Update the VirtualService:

kubectl apply -f aspnetcore-virtualservice.yaml

Open up your browser and visit http://<replace-with-external-ip>. Even after multiple refreshes, you should see the message "Learn about building Web apps with ASP.NET Core on Google Cloud":

3eb0d5be1b4cb40b.png

8. Split traffic between versions

Sometimes, you might want to split traffic between versions for testing. For example, you might want to send 75% of the traffic to the v1 and 25% of the traffic to the v2 version of the service. You can easily achieve this with Istio. Create a new aspnetcore-virtualservice-weights.yaml file to refer to the two subsets with different weights:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aspnetcore-virtualservice
spec:
  hosts:
  - "*"
  gateways:
  - aspnetcore-gateway
  http:
  - route:
    - destination:
        host: aspnetcore-service
        subset: v1
      weight: 75
    - destination:
        host: aspnetcore-service
        subset: v2
      weight: 25

Update the VirtualService:

kubectl apply -f aspnetcore-virtualservice-weights.yaml

Now, when you refresh the browser, you should see the v1 vs. v2 versions served with roughly a 3:1 ratio.

To learn more, see traffic splitting in Istio.

9. Inject faults

Another useful development task to do for testing is to inject faults or delays into the traffic and see how services behave in response.

For example, you might want to return a bad request (HTTP 400) response for 50% of the traffic to the v1 version. Create aspnetcore-virtualservice-fault-abort.yaml file to match the following:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aspnetcore-virtualservice
spec:
  hosts:
  - "*"
  gateways:
  - aspnetcore-gateway
  http:
  - fault:
      abort:
        percentage:
          value: 50
        httpStatus: 400
    route:
    - destination:
        host: aspnetcore-service
        subset: v1

Update the VirtualService:

kubectl apply -f aspnetcore-virtualservice-fault-abort.yaml

Now, when you refresh the browser, you should see that half of the time, the v1 service returns a HTTP 400s response code.

Or maybe you want to add 5 seconds delay to the requests. Create aspnetcore-virtualservice-fault-delay.yaml file to match the following:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: aspnetcore-virtualservice
spec:
  hosts:
  - "*"
  gateways:
  - aspnetcore-gateway
  http:
  - fault:
      delay:
        fixedDelay: 5s
        percentage:
          value: 100
    route:
    - destination:
        host: aspnetcore-service
        subset: v1

Update the VirtualService:

kubectl apply -f aspnetcore-virtualservice-fault-delay.yaml

Now, when you refresh the browser, you should see that requests are delayed by 5 seconds.

To learn more about Istio features such as timeouts, retries, conditional rules, circuit breakers and more, see traffic management features.

10. Congratulations!

Hopefully, this lab gave you an overview of what Istio can do for your services out of the box. To learn more about Istio and GKE.

Next Steps

License

This work is licensed under a Creative Commons Attribution 2.0 Generic License.

11. Cleanup

You can delete the app and uninstall Istio or you can simply delete the Kubernetes cluster.

Delete the application

To delete the application:

kubectl delete -f aspnetcore-gateway.yaml
kubectl delete -f aspnetcore-virtualservice.yaml
kubectl delete -f aspnetcore-destinationrule.yaml
kubectl delete -f aspnetcore.yaml

To confirm that the application is gone:

kubectl get gateway 
kubectl get virtualservices
kubectl get destinationrule
kubectl get pods

Uninstall Istio

To delete Istio:

kubectl delete -f install/kubernetes/istio-demo-auth.yaml

To confirm that Istio is gone:

kubectl get pods -n istio-system

Delete Kubernetes cluster

gcloud container clusters delete hello-dotnet-cluster