Module 2: Exercises

This exercise section provides hands-on practice with Istio traffic management. You will learn how to configure Gateways, create VirtualServices with various routing patterns, implement path-based routing, perform weighted traffic splitting, and combine these components for complete traffic control.

Prerequisites

Before starting these exercises, ensure you have:

  • Access to an OpenShift cluster with Service Mesh 3 (Istio >= 1.23) installed

  • Your namespace ($NAMESPACE) configured with sidecar injection enabled (from Module 1)

  • The oc CLI tool installed and configured

  • Basic understanding of Kubernetes Services and Deployments

Exercise 1: Create and Configure a Gateway

In this exercise, you will create a Gateway resource to allow external traffic into your service mesh.

Step 1: Set Your Namespace

Ensure your namespace variable is set:

export NAMESPACE={USER}-sandbox

Verify the namespace exists and has sidecar injection enabled:

oc get namespace $NAMESPACE --show-labels | grep istio.io/rev

Step 2: Verify Istio Ingress Gateway

Check that the Istio ingress gateway is running:

oc get pods -n istio-system -l app=istio-ingressgateway

Note the service name and external access method:

oc get svc -n istio-system istio-ingressgateway

Step 3: Create a Basic Gateway

Create a Gateway that accepts HTTP traffic on port 80:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: my-gateway
  namespace: ${NAMESPACE}
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
EOF

Step 4: Verify Gateway Creation

Verify the Gateway was created successfully:

oc get gateway -n $NAMESPACE

View the Gateway configuration:

oc get gateway my-gateway -n $NAMESPACE -o yaml

Step 5: Create a Gateway with HTTPS

Create an additional Gateway that accepts HTTPS traffic on port 443:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: my-https-gateway
  namespace: ${NAMESPACE}
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: my-tls-secret
    hosts:
    - "myapp.example.com"
EOF
In a production environment, you would need to create the TLS secret referenced in the Gateway configuration.

Exercise 2: Create VirtualServices with Basic Routing

In this exercise, you will create VirtualServices to route traffic to your services.

Step 1: Deploy Sample Applications

Deploy two sample applications to use for routing:

oc apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: ${NAMESPACE}
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
      version: v1
  template:
    metadata:
      labels:
        app: frontend
        version: v1
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: ${NAMESPACE}
spec:
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80
    name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  namespace: ${NAMESPACE}
spec:
  replicas: 2
  selector:
    matchLabels:
      app: backend
      version: v1
  template:
    metadata:
      labels:
        app: backend
        version: v1
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: backend
  namespace: ${NAMESPACE}
spec:
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 80
    name: http
EOF

Wait for the pods to be ready:

oc get pods -n $NAMESPACE -l app=frontend
oc get pods -n $NAMESPACE -l app=backend

Step 2: Create a Basic VirtualService

Create a VirtualService that routes all traffic to the frontend service:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: frontend
  namespace: ${NAMESPACE}
spec:
  hosts:
  - frontend
  http:
  - route:
    - destination:
        host: frontend
      weight: 100
EOF

Step 3: Verify VirtualService

Check that the VirtualService was created:

oc get virtualservice -n $NAMESPACE

View the VirtualService configuration:

oc get virtualservice frontend -n $NAMESPACE -o yaml

Step 4: Test Internal Routing

Test that the VirtualService routes traffic correctly by sending a request from within the cluster:

oc run curl-test --image=curlimages/curl:latest --rm -i --restart=Never -n $NAMESPACE -- curl -v http://frontend

Exercise 3: Implement Path-Based Routing

In this exercise, you will create a VirtualService that routes traffic based on URI paths.

Step 1: Create a Path-Based VirtualService

Create a VirtualService that routes different paths to different services:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp
  namespace: ${NAMESPACE}
spec:
  hosts:
  - myapp.example.com
  gateways:
  - my-gateway
  http:
  - match:
    - uri:
        prefix: "/api"
    route:
    - destination:
        host: backend
      weight: 100
  - match:
    - uri:
        prefix: "/"
    route:
    - destination:
        host: frontend
      weight: 100
EOF

This VirtualService:
* Routes requests to /api/* to the backend service
* Routes all other requests to the frontend service

Step 2: Verify Path-Based Routing

Check the VirtualService configuration:

oc get virtualservice myapp -n $NAMESPACE -o yaml

Step 3: Test Path-Based Routing

Get the ingress gateway external address:

INGRESS_HOST=$(oc get svc -n istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo $INGRESS_HOST

If no external address is available, you can use port-forwarding:

oc port-forward -n istio-system svc/istio-ingressgateway 8080:80 &

Test the frontend route:

curl -H "Host: myapp.example.com" http://localhost:8080/

Test the backend API route:

curl -H "Host: myapp.example.com" http://localhost:8080/api

Step 4: Create More Complex Path Matching

Create a VirtualService with multiple path patterns:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: complex-routing
  namespace: ${NAMESPACE}
spec:
  hosts:
  - complex.example.com
  gateways:
  - my-gateway
  http:
  - match:
    - uri:
        exact: "/api/v1/users"
    route:
    - destination:
        host: backend
      weight: 100
  - match:
    - uri:
        prefix: "/api/v2"
    route:
    - destination:
        host: backend
      weight: 100
  - match:
    - uri:
        regex: "^/static/.*\\.(jpg|png|gif)$"
    route:
    - destination:
        host: frontend
      weight: 100
  - route:
    - destination:
        host: frontend
      weight: 100
EOF

This example demonstrates:
* Exact path matching (/api/v1/users)
* Prefix matching (/api/v2/*)
* Regex matching (static image files)
* Default route (catch-all)

Exercise 4: Implement Weighted Traffic Splitting

In this exercise, you will implement weighted traffic splitting for canary deployments.

Step 1: Deploy Multiple Versions

Deploy a second version of the frontend application:

oc apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v2
  namespace: ${NAMESPACE}
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
      version: v2
  template:
    metadata:
      labels:
        app: frontend
        version: v2
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
EOF

Wait for the new pods to be ready:

oc get pods -n $NAMESPACE -l app=frontend

Step 2: Create DestinationRule with Subsets

Create a DestinationRule to define service subsets (versions):

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: frontend
  namespace: ${NAMESPACE}
spec:
  host: frontend
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
EOF

Verify the DestinationRule:

oc get destinationrule -n $NAMESPACE
oc get destinationrule frontend -n $NAMESPACE -o yaml

Step 3: Create VirtualService with Weighted Splitting

Create a VirtualService that splits traffic 90% to v1 and 10% to v2:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: frontend-canary
  namespace: ${NAMESPACE}
spec:
  hosts:
  - frontend
  http:
  - route:
    - destination:
        host: frontend
        subset: v1
      weight: 90
    - destination:
        host: frontend
        subset: v2
      weight: 10
EOF

Step 4: Test Weighted Traffic Splitting

Send multiple requests and observe the traffic distribution. You can check the Envoy access logs to see which version receives each request:

for i in {1..20}; do
  oc run curl-test-$i --image=curlimages/curl:latest --rm -i --restart=Never -n $NAMESPACE -- curl -s http://frontend > /dev/null
done

Check the logs to see traffic distribution:

oc logs -n $NAMESPACE -l app=frontend,version=v1 -c istio-proxy --tail=10
oc logs -n $NAMESPACE -l app=frontend,version=v2 -c istio-proxy --tail=10

Step 5: Adjust Traffic Weights

Update the VirtualService to increase traffic to v2 (50/50 split):

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: frontend-canary
  namespace: ${NAMESPACE}
spec:
  hosts:
  - frontend
  http:
  - route:
    - destination:
        host: frontend
        subset: v1
      weight: 50
    - destination:
        host: frontend
        subset: v2
      weight: 50
EOF

Step 6: Complete Canary Deployment

Finally, route 100% of traffic to v2:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: frontend-canary
  namespace: ${NAMESPACE}
spec:
  hosts:
  - frontend
  http:
  - route:
    - destination:
        host: frontend
        subset: v2
      weight: 100
EOF

Exercise 5: Combine Gateway and VirtualService

In this exercise, you will combine a Gateway and VirtualService to provide complete external access to your services.

Step 1: Create a Complete Gateway Configuration

Ensure you have a Gateway that accepts traffic for your application:

oc get gateway my-gateway -n $NAMESPACE

If it doesn’t exist, create it:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: my-gateway
  namespace: ${NAMESPACE}
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "myapp.example.com"
EOF

Step 2: Create VirtualService for Gateway

Create a VirtualService that works with the Gateway to route external traffic:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-external
  namespace: ${NAMESPACE}
spec:
  hosts:
  - myapp.example.com
  gateways:
  - my-gateway
  http:
  - match:
    - uri:
        prefix: "/api"
    route:
    - destination:
        host: backend
        port:
          number: 80
      weight: 100
  - route:
    - destination:
        host: frontend
        port:
          number: 80
      weight: 100
EOF

Step 3: Verify Gateway and VirtualService Integration

Check both resources:

oc get gateway,virtualservice -n $NAMESPACE

View the complete configuration:

oc get gateway my-gateway -n $NAMESPACE -o yaml
oc get virtualservice myapp-external -n $NAMESPACE -o yaml

Step 4: Test External Access

Get the ingress gateway address:

INGRESS_HOST=$(oc get svc -n istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
INGRESS_PORT=$(oc get svc -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')

If using port-forwarding:

oc port-forward -n istio-system svc/istio-ingressgateway 8080:80 &

Test the frontend:

curl -H "Host: myapp.example.com" http://localhost:8080/

Test the API:

curl -H "Host: myapp.example.com" http://localhost:8080/api

Step 5: Add Header-Based Routing

Enhance the VirtualService to include header-based routing:

oc apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-external
  namespace: ${NAMESPACE}
spec:
  hosts:
  - myapp.example.com
  gateways:
  - my-gateway
  http:
  - match:
    - headers:
        x-canary:
          exact: "true"
    route:
    - destination:
        host: frontend
        subset: v2
      weight: 100
  - match:
    - uri:
        prefix: "/api"
    route:
    - destination:
        host: backend
        port:
          number: 80
      weight: 100
  - route:
    - destination:
        host: frontend
        port:
          number: 80
      weight: 100
EOF

Test with the canary header:

curl -H "Host: myapp.example.com" -H "x-canary: true" http://localhost:8080/

Summary

In these exercises, you have:

  • Created and configured Gateways to accept external traffic

  • Created VirtualServices with basic routing patterns

  • Implemented path-based routing to direct traffic based on URI paths

  • Configured weighted traffic splitting for canary deployments

  • Combined Gateways and VirtualServices for complete external traffic management

  • Used DestinationRules to define service subsets for version-based routing

These skills form the foundation of Istio traffic management and are essential for implementing advanced deployment strategies in production environments.

Troubleshooting

If you encounter issues:

  • Gateway not accepting traffic: Verify the Gateway selector matches your ingress gateway pods and check that the gateway pods are running

  • VirtualService not routing: Ensure the VirtualService hosts match the Gateway hosts, and verify the destination services exist

  • Traffic not splitting correctly: Check that DestinationRule subsets match the pod labels, and verify the weight percentages sum to 100

  • External access not working: Verify the ingress gateway service has an external IP or use port-forwarding for testing

  • Path matching not working: Check the match conditions are correct and that routes are ordered properly (most specific first)