---
title: "Istio Routing Basics: A Step-by-Step Tutorial"
source: "https://www.tigera.io/blog/istio-routing-basics/"
---

[Technical Blog](https://www.tigera.io/category/technical-blog/)

# Istio Routing Basics: A Step-by-Step Tutorial

By [Mete Atamel](https://www.tigera.io/blog/author/mete-atamel/) on Sep 13, 2019 • 6 min read

When learning a new technology like [Istio](http://istio.io/), it’s always a good idea to take a look at sample apps. Istio repo has a few [sample](http://github.com/istio/istio/tree/master/samples) apps but they fall short in various ways. [BookInfo](http://github.com/istio/istio/tree/master/samples/bookinfo) is covered in the docs and it is a good first step. However, it is too verbose with too many services for me and the docs seem to focus on managing the BookInfo app, rather than building it from ground up. There’s a smaller [helloworld](http://github.com/istio/istio/tree/master/samples/helloworld) sample but it’s more about autoscaling than anything else.

In this post, I’d like to get to the basics and show you what it takes to build an Istio enabled ‘HelloWorld’ app from ground up. One thing to keep in mind is that Istio only manages the traffic of your app. The app lifecycle is managed by the underlying platform, Kubernetes in this case. Therefore, you need to understand containers and Kubernetes basics and you need to know about Istio Routing primitives such as Gateway, VirtualService, DestinationRuleupfront. I’m assuming that most people know containers and Kubernetes basics at this point. I will focus on Istio Routing instead in this post.

Because Istio only manages traffic, teams still need robust [Kubernetes security](https://www.tigera.io/learn/guides/kubernetes-security/) to protect workloads, enforce network policy, and control access across the cluster.

 

## Basic Steps

These are roughly the steps you need to follow to get an Istio enabled ‘HelloWorld’ app:

- Create a Kubernetes cluster and install Istio with automatic sidecar injection.

- Create a HelloWorld app in your language of choice, create a Docker image out of it and push it to a public image repository.

- Create Kubernetes Deployment and Service for your container.

- Create a [Gateway](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#Gateway) to enable HTTP(S) traffic to your cluster.

- Create a [VirtualService](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#VirtualService) to expose Kubernetes Service via Gateway.

- (Optional) If you want to create multiple versions of your app, create a [DestinationRule](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationRule) to define subsets that you can refer from the VirtualService.

- (Optional) If you want to call external services outside your service mesh, create a [ServiceEntry](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#ServiceEntry).

I won’t cover steps 1 and 2 in this post because they are not Istio specific. If you need help with these steps, you can take a look at the codelabs I mention at the end of this post. Step 3 is not Istio specific either but it’s kind of prerequisite to everything else, so let’s start with that.

## Deployment and Service

As I mentioned, the app lifecycle is managed by Kubernetes. Therefore, you need to start with creating a Kubernetes Deployment and Service. In my case, I have a containerized ASP.NET Core app whose image I already pushed to Google Container Registry. Let’s start with creating an `aspnetcore.yaml` file:

Create the deployment and service:

```
`$ kubectl apply -f aspnetcore.yaml service "aspnetcore-service" created deployment.extensions "aspnetcore-v1" created`
```

Nothing Istio specific so far.

## Gateway

We can now start looking into Istio Routing. First, we need to enable HTTP/HTTPS traffic to our service mesh. To do that, we need to create a [Gateway](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#Gateway). Gateway describes a load balancer operating at the edge of the mesh receiving incoming or outgoing HTTP/TCP connections. Let’s create an `aspnetcore-gateway.yaml` file:

Create the Gateway:

```
`$ kubectl apply -f aspnetcore-gateway.yaml gateway.networking.istio.io "aspnetcore-gateway" created`
```

At this point, we have HTTP traffic enabled for our cluster. We need to map the Kubernetes Service we created earlier to the Gateway. We’ll do that with a VirtualService.

## VirtualService

A [VirtualService](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#VirtualService) essentially connects a Kubernetes Service to Istio Gateway. It can also do more such as defining a set of traffic routing rules to apply when a host is addressed but we won’t get into those details.

Let’s create an `aspnetcore-virtualservice.yaml` file:

Notice that a VirtualService is tied to a specific Gateway and it defines a host that refers to the Kubernetes Service. Create the VirtualService:

```
`$ kubectl apply -f aspnetcore-virtualservice.yaml virtualservice.networking.istio.io "aspnetcore-virtualservice" created`
```

 

## Test the v1 of app

We’re ready to test our app. We need to get the IP address of the Istio Ingress Gateway:

```
`$ kubectl get svc istio-ingressgateway -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP istio-ingressgateway LoadBalancer 10.31.247.41 35.240.XX.XXX`
```

When we browser to the `EXTERNAL-IP`, we should see the HelloWorld ASP.NET Core app:

![Screenshot of the HelloWorld ASP.NET Core app, confirming successful deployment](/app/uploads/2019/06/1_WksXRI3XV54SegfmFd0_bg.png)

 

## DestinationRule

At some point, you want to update your app to a new version. Maybe you want to split the traffic between two versions. You need to create a [DestinationRule](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationRule) to define those versions, called subsets in Istio. First, update `aspnetcore.yaml` file to define the Deployment for `v2` with `v2`version of the container:

Create the new deployment:

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

If you refresh the browser with the `EXTERNAL-IP` , you’ll see that VirtualService rotates through `v1` and `v2` versions of the app:

v1 of the app

![HelloWorldAspNetCore site showcasing ASP.NET Core running on Windows, Linux, and OSX](/app/uploads/2019/06/1_vqfpTeJtV1aP8v0mV8Ff2g.png)

v2 of the app

This is expected because both versions are exposed behind the same Kubernetes service:`aspnetcore-service`.

What if you want to pin your service to only `v2`? This can be done by specifying a subset in the VirtualService but we need to define those subsets first in a DestinationRules. A DestinationRule essentially maps labels to Istio subsets.

Create a `aspnetcore-destinationrule.yaml` file:

Create the DestinationRule:

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

Now, you can refer to `v2` subset from VirtualService:

Update the VirtualService:

```
`$ kubectl apply -f aspnetcore-virtualservice.yaml virtualservice.networking.istio.io "aspnetcore-virtualservice" configured`
```

If you browse back to the`EXTERNAL-IP` , you should now only see the `v2` of the app.

## ServiceEntry

The last thing I want to mention in Istio Routing is [ServiceEntry](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#ServiceEntry). By default, all the external traffic in Istio is blocked. If you want to enable external traffic, you need to create a ServiceEntry to list what protocols and hosts are enabled for external traffic. I won’t show an example in this post but you can read more about it [here](http://istio.io/docs/reference/config/istio.networking.v1alpha3/#ServiceEntry).

This article originated from [http://medium.com/google-cloud/istio-routing-basics-14feab3c040e](http://medium.com/google-cloud/istio-routing-basics-14feab3c040e)

[Mete Atamel](http://uk.linkedin.com/in/meteatamel) is a Tigera guest blogger. He is a Developer Advocate at Google, helping developers to be successful on Google Cloud Platform, and a regular speaker at tech conferences/meetups across the globe. His focus areas are Windows/.NET apps on Google Cloud, Kubernetes, Istio and Knative. Previously, he was a Software Engineer/Architect/Tech Lead at Nokia, EMC, Adobe, Skype and Microsoft, building apps and services on various web, mobile and cloud platforms.

————————————————-

[**Free Online Training**](https://www.tigera.io/events/)

Access Live and On-Demand Kubernetes Tutorials

[**Calico Enterprise – Free Trial**](https://www.calicocloud.io/home)

Solve Common Kubernetes Roadblocks and Advance Your Enterprise Adoption

[How-To](https://www.tigera.io/tags/how-to/)[Service Mesh](https://www.tigera.io/tags/service-mesh/)

## Related posts

[![Save the Address, Save the Cloud: A Hands-on KubeVirt Live Migration Workshop](https://www.tigera.io/app/uploads/2026/07/Save-the-Address-Save-the-Cloud-A-Hands-on-KubeVirt-Live-Migration-Workshop.png)](https://www.tigera.io/blog/save-the-address-save-the-cloud-a-hands-on-kubevirt-live-migration-workshop/)

#### [Save the Address, Save the Cloud: A Hands-on KubeVirt Live Migration Workshop](https://www.tigera.io/blog/save-the-address-save-the-cloud-a-hands-on-kubevirt-live-migration-workshop/)

By [Reza Ramezanpour](https://www.tigera.io/blog/author/rezar/)
on Jul 9, 2026

In the previous post in this series, we covered why Virtual Machine (VM) Live Migration in Kubernetes is difficult: a VM’s IP is its identity, and the “new” VM on the destination node has to...

[Read more](https://www.tigera.io/blog/save-the-address-save-the-cloud-a-hands-on-kubevirt-live-migration-workshop/)

[![KubeVirt Networking: How to Preserve VM IP Addresses During Migration](https://www.tigera.io/app/uploads/2026/04/KubeVirt-Networking-How-to-Preserve-VM-IP-Addresses-During-Migration-1-1.png)](https://www.tigera.io/blog/kubevirt-networking-how-to-preserve-vm-ip-addresses-during-migration/)

#### [KubeVirt Networking: How to Preserve VM IP Addresses During Migration](https://www.tigera.io/blog/kubevirt-networking-how-to-preserve-vm-ip-addresses-during-migration/)

By [Dillon Barry](https://www.tigera.io/blog/author/dillon-barry/)
on Apr 21, 2026

Organisations are re-evaluating their VM infrastructure. The economics have shifted, the tooling has matured, and the case for running two separate platforms, one for containers, one for VMs, is getting harder to justify. Platform teams...

[Read more](https://www.tigera.io/blog/kubevirt-networking-how-to-preserve-vm-ip-addresses-during-migration/)

[![How to Stub LLMs for AI Agent Security Testing and Governance](https://www.tigera.io/app/uploads/2026/04/How-to-Stub-LLMs-for-AI-Agent-Security-Testing-and-Governance.png)](https://www.tigera.io/blog/how-to-stub-llms-for-ai-agent-security-testing-and-governance/)

[Featured Blog](https://www.tigera.io/category/featured-blog/)

#### [How to Stub LLMs for AI Agent Security Testing and Governance](https://www.tigera.io/blog/how-to-stub-llms-for-ai-agent-security-testing-and-governance/)

By [Alister Baroi](https://www.tigera.io/blog/author/alister-baroi/)
on Apr 2, 2026

Note: The core architecture for this pattern was introduced by Isaac Hawley from Tigera. If you are building an AI agent that relies on tool calling, complex routing, or the Model Context Protocol (MCP), you’re...

[Read more](https://www.tigera.io/blog/how-to-stub-llms-for-ai-agent-security-testing-and-governance/)

<!-- plugin=object-cache-pro client=phpredis metric#hits=3186 metric#misses=33 metric#hit-ratio=99.0 metric#bytes=1568831 metric#prefetches=0 metric#store-reads=176 metric#store-writes=8 metric#store-hits=171 metric#store-misses=22 metric#sql-queries=25 metric#ms-total=549.69 metric#ms-cache=40.69 metric#ms-cache-avg=0.2223 metric#ms-cache-ratio=7.4 -->
