> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Virtual Services

> Demonstrates an Istio VirtualService demo using httpbin to show how Envoy sidecars enforce routing, how misconfiguring ports breaks traffic, and how URL rewrites work.

This lesson walks through a concise Istio VirtualService demo using the httpbin sample and a test pod. It shows how VirtualService routes influence traffic only when Envoy sidecars are present, and demonstrates URL rewriting. Follow the steps to reproduce the examples and understand the behavior.

## TL;DR

* Deploy the httpbin sample in the `default` namespace.
* Create a `test` namespace and a simple pod to curl httpbin.
* Create a VirtualService that initially mirrors routing, then change it to a non-listening port to observe broken traffic.
* Enable Istio sidecar injection in the `test` namespace so Envoy enforces the VirtualService routing.
* Demonstrate URL rewrites and review common VirtualService capabilities.

## Prerequisites

* Kubernetes cluster with Istio installed.
* `kubectl` configured to talk to your cluster.
* `istioctl` installed (used for analysis).

## 1) Check namespace injection label

Confirm whether automatic Istio sidecar injection is enabled in the `default` namespace:

```bash theme={null}
# kubectl get ns --show-labels
NAME                STATUS   AGE   LABELS
default             Active   15m   istio-injection=enabled,kubernetes.io/metadata.name=default
istio-system        Active   12m   kubernetes.io/metadata.name=istio-system
kube-node-lease     Active   15m   kubernetes.io/metadata.name=kube-node-lease
kube-public         Active   15m   kubernetes.io/metadata.name=kube-public
kube-system         Active   15m   kubernetes.io/metadata.name=kube-system
```

## 2) Deploy the httpbin sample

Apply the official httpbin sample to the `default` namespace:

```bash theme={null}
kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/httpbin/httpbin.yaml

# Expected output
# serviceaccount/httpbin created
# service/httpbin created
# deployment.apps/httpbin created
```

Verify the httpbin pod is running with the Envoy sidecar (READY should show 2/2):

```bash theme={null}
kubectl get pods
# NAME                          READY   STATUS    RESTARTS   AGE
# httpbin-787cdcc9df-hs5q2      2/2     Running   0          7s
```

## 3) Create a test namespace and pod (no sidecar initially)

Create a namespace `test` (not injection-enabled by default) and run a simple nginx pod there:

```bash theme={null}
kubectl create ns test
kubectl run test --image=nginx -n test
kubectl get pods -n test
# NAME   READY   STATUS    RESTARTS   AGE
# test   1/1     Running   0          5s
```

Exec into the `test` pod and verify you can reach httpbin in the `default` namespace (httpbin listens on port 8000):

```bash theme={null}
kubectl exec -ti -n test test -- /bin/bash
# root@test:/# curl httpbin.default.svc:8000/ip
# {
#   "origin": "127.0.0.6:49657"
# }
# root@test:/# curl httpbin.default.svc:8000/user-agent
# {
#   "user-agent": "curl/7.88.1"
# }
# root@test:/# exit
```

Note: Istio is permissive by default for cross-namespace communication unless you enable strict policies (e.g., mTLS strict mode). This helps avoid accidental service disruption after installing Istio.

## 4) Create a VirtualService that mirrors default routing

Save the following manifest as `vs.yaml` — this first version routes HTTP traffic to port 8000 (same as the Kubernetes Service):

```yaml theme={null}
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: httpbin
  namespace: default
spec:
  hosts:
  - httpbin
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: httpbin.default.svc.cluster.local
        port:
          number: 8000
```

Apply the VirtualService:

```bash theme={null}
kubectl apply -f vs.yaml
# virtualservice.networking.istio.io/httpbin configured
```

Confirm it exists:

```bash theme={null}
kubectl get virtualservice
# NAME      GATEWAYS   HOSTS      AGE
# httpbin   <none>     httpbin    10m
```

At this point, you won't see any change in behavior because the VirtualService matches the service’s default routing.

## 5) Modify the VirtualService to break traffic (demonstrate effect)

Edit `vs.yaml` to route to port `9000`, where httpbin is not listening:

```yaml theme={null}
# vs.yaml (modified to break traffic)
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: httpbin
  namespace: default
spec:
  hosts:
  - httpbin
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: httpbin.default.svc.cluster.local
        port:
          number: 9000
```

Apply the broken VirtualService:

```bash theme={null}
kubectl apply -f vs.yaml
# virtualservice.networking.istio.io/httpbin configured
```

You might still be able to curl httpbin from the `test` pod even after applying the broken VirtualService. Why? Because the `test` pod currently runs without an Envoy sidecar (its namespace was not injection-enabled) so its outbound traffic bypasses Istio and is unaffected by the VirtualService.

Check the namespace labels and run analysis:

```bash theme={null}
kubectl get ns --show-labels
istioctl analyze -n test
# Info [IST0102] (Namespace test) The namespace is not enabled for Istio injection. Run 'kubectl label namespace test istio-injection=enabled' to enable it, or 'kubectl label namespace test istio-injection=disabled' to explicitly mark it as not needing injection.
```

## 6) Enable injection and recreate the pod so Envoy gets injected

Enable automatic sidecar injection for `test`, then delete and recreate the pod so it receives an Envoy sidecar:

```bash theme={null}
kubectl label namespace test istio-injection=enabled
kubectl delete pod test -n test
kubectl run test --image=nginx -n test
kubectl get pods -n test
# NAME   READY   STATUS    RESTARTS   AGE
# test   2/2     Running   0          10s
```

Now the `test` pod’s outbound traffic goes through Envoy and is governed by the VirtualService. Exec into the pod and try to reach httpbin:

```bash theme={null}
kubectl exec -ti -n test test -- /bin/bash
# root@test:/# curl -I httpbin.default.svc:8000/ip
# HTTP/1.1 503 Service Unavailable
# ...
# root@test:/# exit
```

The 503 Service Unavailable is expected because the VirtualService routes to port 9000 (where nothing listens). Fix the VirtualService to route back to port 8000 and re-apply:

```yaml theme={null}
# vs.yaml (fixed)
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: httpbin
  namespace: default
spec:
  hosts:
  - httpbin
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: httpbin.default.svc.cluster.local
        port:
          number: 8000
```

```bash theme={null}
kubectl apply -f vs.yaml
# virtualservice.networking.istio.io/httpbin configured
```

Now curl from the `test` pod should work again.

<Callout icon="lightbulb" color="#1CB2FE">
  You must enable Istio sidecar injection in a namespace for Envoy to enforce VirtualService routing from pods in that namespace. Pods without a sidecar send traffic directly and are not affected by VirtualService rules.
</Callout>

## URL rewrites

VirtualServices can rewrite request URIs before forwarding. Add a second HTTP match that rewrites `/hello` to `/`:

```yaml theme={null}
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: httpbin
  namespace: default
spec:
  hosts:
  - httpbin
  http:
  - match:
    - uri:
        prefix: /hello
    rewrite:
      uri: /
    route:
    - destination:
        host: httpbin.default.svc.cluster.local
        port:
          number: 8000
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: httpbin.default.svc.cluster.local
        port:
          number: 8000
```

Before applying the rewrite, requesting `/hello` returns `404` because httpbin has no `/hello` endpoint. After applying the VirtualService with the rewrite, requests to `/hello` are rewritten to `/` and succeed:

```bash theme={null}
kubectl apply -f vs.yaml
kubectl exec -ti -n test test -- /bin/bash
# root@test:/# curl httpbin.default.svc:8000/ip
# {
#   "origin": "127.0.0.6:36879"
# }
# root@test:/# curl httpbin.default.svc:8000/hello
# 404 page not found   # (before apply)
#
# # After apply:
# root@test:/# curl httpbin.default.svc:8000/hello
# { ... httpbin response for / ... }
# root@test:/# exit
```

The httpbin sample exposes many useful endpoints — for example, `/ip`, `/user-agent`, `/status/<code>`, and `/dump/request`. The following is an example HTML snippet from the httpbin project to illustrate a typical response:

```html theme={null}
<h3 id="-curl-http-httpbin-org-dump-request">$ curl https://httpbingo.org/dump/request?foo=bar</h3>

<pre><code>GET /dump/request?foo=bar HTTP/1.1
Host: httpbingo.org
Accept: */*
User-Agent: curl/7.64.1
</code></pre>

<h3 id="-curl-I-http-httpbin-org-status-418">$ curl -I https://httpbingo.org/status/418</h3>

<pre><code>HTTP/1.1 418 I'm a teapot
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
X-More-Info: http://tools.ietf.org/html/rfc2324
Date: Tue, 13 Jul 2021 13:12:37 GMT
Content-Length: 0
</code></pre>

<h2 id="AUTHOR">AUTHOR</h2>

<p>Ported to Go by <a href="https://github.com/mccutchen">Will McCutchen</a>.</p>
<p>From <a href="https://httpbin.org/">the original</a> <a href="https://kennethreitz.org/">Kenneth Reitz</a> project.</p>
```

## VirtualService capabilities (quick reference)

Here’s a short reference of common VirtualService features and what they’re used for.

|           Capability | Purpose                                                                          |
| -------------------: | -------------------------------------------------------------------------------- |
|             Timeouts | Set per-route request timeouts (e.g., `timeout: 5s`)                             |
| Header-based matches | Match traffic by request headers and URI (e.g., `headers.end-user.exact: jason`) |
|   Rewrite / Redirect | Rewrite the request URI or issue redirects to different path/authority           |
|              Retries | Configure retry attempts, per-try timeout, and conditions (e.g., `attempts: 3`)  |

Examples of these capabilities are shown below for easy copy/paste during exams or troubleshooting.

* Timeouts example:

```yaml theme={null}
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: my-productpage-rule
  namespace: istio-system
spec:
  hosts:
  - productpage.prod.svc.cluster.local
  http:
  - timeout: 5s
    route:
    - destination:
        host: productpage.prod.svc.cluster.local
```

* Header-based matches example:

```yaml theme={null}
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: ratings-route
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - match:
    - headers:
        end-user:
          exact: jason
      uri:
        prefix: "/ratings/v2/"
    route:
    - destination:
        host: ratings.prod.svc.cluster.local
```

* Rewrite and redirect examples:

```yaml theme={null}
# Rewrite example:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: ratings-rewrite
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - match:
    - uri:
        prefix: /ratings
    rewrite:
      uri: /v1/bookRatings
    route:
    - destination:
        host: ratings.prod.svc.cluster.local
        subset: v1

# Redirect example:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: ratings-redirect
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - match:
    - uri:
        exact: /v1/getProductRatings
    redirect:
      uri: /v1/bookRatings
      authority: newratings.default.svc.cluster.local
```

* Retries example:

```yaml theme={null}
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: ratings-retries
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - route:
    - destination:
        host: ratings.prod.svc.cluster.local
        subset: v1
    retries:
      attempts: 3
      perTryTimeout: 2s
      retryOn: gateway-error,connect-failure,refused-stream
```

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/zDpSzOByf0QVxNkX/images/Prep-Course-Istio-Certified-Associate-ICA-Certification/Traffic-Management/Demo-Virtual-Services/istio-virtual-service-docs-screenshot.jpg?fit=max&auto=format&n=zDpSzOByf0QVxNkX&q=85&s=cbccce76d3bbee9969c0ef552d113805" alt="A screenshot of the Istio website documentation showing the &#x22;Virtual Service&#x22; page, with the article text in the center, a left navigation menu, and a right-side table of contents. The browser tabs and URL bar are visible at the top." width="1920" height="1080" data-path="images/Prep-Course-Istio-Certified-Associate-ICA-Certification/Traffic-Management/Demo-Virtual-Services/istio-virtual-service-docs-screenshot.jpg" />
</Frame>

## Closing notes

This minimal demo demonstrates how VirtualService routing rules can change or break traffic when Envoy sidecars are present. In real deployments, VirtualServices are used widely together with DestinationRules, Gateways, and policies for traffic shaping, retries, timeouts, redirects, and header manipulation.

Keep the official Istio docs handy for reference and canonical examples:

* Istio Documentation: [https://istio.io/latest/docs/](https://istio.io/latest/docs/)
* httpbin / httpbingo: [https://httpbin.org/](https://httpbin.org/) and [https://httpbingo.org/](https://httpbingo.org/)
* kubectl reference: [https://kubernetes.io/docs/reference/kubectl/](https://kubernetes.io/docs/reference/kubectl/)
* istioctl analyze docs: [https://istio.io/latest/docs/ops/diagnostic-tools/istioctl-analyze/](https://istio.io/latest/docs/ops/diagnostic-tools/istioctl-analyze/)

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/istio-certified-associate/module/f3f5ca4b-b8d6-4788-9553-9ed765709933/lesson/4deeb1cf-af2a-40f0-98f1-0f03b8dd2b87" />

  <Card title="Practice Lab" icon="flask-conical" cta="Learn more" href="https://learn.kodekloud.com/user/courses/istio-certified-associate/module/f3f5ca4b-b8d6-4788-9553-9ed765709933/lesson/f9527147-d6e9-4b09-bf7b-86cf274b6cd5" />
</CardGroup>
