Attach multiple VirtualServices to Istio Gateway
Tags: istio, kubernetes, devops
Published: 2020-12-01 22:23:14

---
title: Attach multiple VirtualServices to Istio Gateway
published: true
date: 2020-11-23 20:43:25 UTC
tags: istio, kubernetes, devops
canonical_url: https://learncloudnative.com/blog/2020-11-23-multiple-vs-gateway/
---

## What will I learn?

In this post, you'll learn how to expose multiple Kubernetes services running inside your cluster using Istio' Gateway and VirtualService resources.

The idea for this post came from a comment on the [Istio Gateway video](https://www.youtube.com/watch?v=ssqDgcEvdZ0) I recorded last year.

[![YouTube Comment](https://learncloudnative.com/static/9d2ba36e97e25aca97361b7eae28e10a/ade6e/yt-comment.png "YouTube comment")](/static/9d2ba36e97e25aca97361b7eae28e10a/ade6e/yt-comment.png)

The question was: "Is it possible to route multiple VirtualServices using the same Gateway resource?".

The answer is **YES**. You can use the Gateway resource and bind multiple VirtualServices to it, exposing them outside of the cluster.

## How does it work?

The key to understanding how to do that is in the `hosts` fields in the Gateway and VirtualService resources.

When you attach a VirtualService to a Gateway (using the `gateway` field), only the hosts defined in the Gateway resource will be allowed to make it to the VirtualService.

Let's look at the Gateway resource example, that defines two hosts: `red.example.com` and `green.example.com`:

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - 'red.example.com'
        - 'green.example.com'
```

With the `hosts` field, you can define one or more hosts you want to expose with the gateway. In this example, we are specifying the host with an FQDN name (e.g., `red.example.com`). We could optionally include a wildcard character (e.g. `my-namespace/*`) to select all VirtualService hosts from `my-namespace`. You can think of the list of hosts in the Gateway resource as a filter. For example, with the above definition, you are filtering the hosts down to `red.example.com` and `green.example.com`.

In addition to the Gateway, we also have two VirtualServices:

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: red
spec:
  hosts:
    - 'red.example.com'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: red.default.svc.cluster.local
            port:
              number: 80
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: green
spec:
  hosts:
    - 'green.example.com'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: green.default.svc.cluster.local
            port:
              number: 80
```

Notice that both VirtualServices are attached to the Gateway, allowing us to 'expose' the services (destinations) through the Gateway.

However, attaching the Gateway is not enough. We also need to specify the `hosts` in the VirtualService. Gateway uses the values in the `hosts` field to do the matching when the traffic comes in.

Let's take the `red.example.com` as an example. We make the following request:

```bash
$ curl -H "Host: red.example.com" http://$GATEWAY_URL
```

The request hits the ingress gateway (because we defined the host is in the `hosts` field in the Gateway resource), then, because we have a VirtualService with a matching host attached to the gateway, the traffic makes it to the destination (`red.default.svc.cluster.local`).

If we send a request to `blue.example.com`, we get back a 404. That's because we didn't specify that host name in the Gateways' hosts field. Even if we deployed a VirtualService that is attached to the gateway and has `blue.example.com` defined in its host field, we'd still get back a 404.

## Try it out

To try this out on your cluster, following these steps:

1. Install [Istio](https://istio.io).
2. Label the `default` namespace for sidecar injection.
3. Deploy the Green and Red applications:

   ```bash
   kubectl apply -f https://raw.githubusercontent.com/peterj/color-app/main/examples/green.yaml

   kubectl apply -f https://raw.githubusercontent.com/peterj/color- app/main/examples/red.yaml
   ```
4. Create the Gateway, and VirtualServices:

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - 'red.example.com'
        - 'green.example.com'
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: red
spec:
  hosts:
    - 'red.example.com'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: red.default.svc.cluster.local
            port:
              number: 80
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: green
spec:
  hosts:
    - 'green.example.com'
  gateways:
    - gateway
  http:
    - route:
        - destination:
            host: green.default.svc.cluster.local
            port:
              number: 80
```

With everything deployed, we can try to make a request to the GATEWAY_URL.

You can use `kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'` to get the GATEWAY_URL.

If you want to try this out in a browser, make sure you install an extension that allows you to modify the Host header. Alternatively, if you have access to an actual domain name, you can set the GATEWAY_URL as an A name record in your domain registrars' settings and use it directly.

> You can refer to [Expose a Kubernetes service on your own custom domain](/blog/2018-09-28-expose_kubernetes_service_on_your_own_custom_domain/) article to learn how to do that.

Let's make a request with Host set to `green.example.com`:

```bash
$ curl -H "Host: green.example.com" http://$GATEWAY_URL
<link href="/css/style.css" rel="stylesheet" type="text/css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap" rel="stylesheet">

<div class="main" style="background-color:#10b981; color:#FFFFFF">
    <h1>GREEN</h1>
</div>
```

You get a similar response if you use `red.example.com` as your host.