TCP Traffic Shifting
This task shows you how to shift TCP traffic from one version of a microservice to another.
A common use case is to migrate TCP traffic gradually from an older version of a microservice to a new one. In Istio, you accomplish this goal by configuring a sequence of routing rules that redirect a percentage of TCP traffic from one destination to another.
In this task, you will send 100% of the TCP traffic to tcp-echo:v1. Then, you will route 20% of the TCP traffic to tcp-echo:v2 using Istio’s weighted routing feature.
Before you begin
Setup Istio by following the instructions in the Installation guide.
Review the Traffic Management concepts doc.
Set up the test environment
To get started, create a namespace for testing TCP traffic shifting.
$ kubectl create namespace istio-io-tcp-traffic-shiftingDeploy the curl sample app to use as a test source for sending requests.
$ kubectl apply -f @samples/curl/curl.yaml@ -n istio-io-tcp-traffic-shiftingDeploy the
v1andv2versions of thetcp-echomicroservice.$ kubectl apply -f @samples/tcp-echo/tcp-echo-services.yaml@ -n istio-io-tcp-traffic-shifting
Apply weight-based TCP routing
- Route all TCP traffic to the
v1version of thetcp-echomicroservice.
$ kubectl apply -f @samples/tcp-echo/tcp-echo-all-v1.yaml@ -n istio-io-tcp-traffic-shifting$ kubectl apply -f @samples/tcp-echo/gateway-api/tcp-echo-all-v1.yaml@ -n istio-io-tcp-traffic-shifting- Determine the ingress IP and port:
TCP_INGRESS_PORT and INGRESS_HOST environment variables.Use the following commands to set the SECURE_INGRESS_PORT and INGRESS_HOST environment variables:
$ kubectl wait --for=condition=programmed gtw tcp-echo-gateway -n istio-io-tcp-traffic-shifting $ export INGRESS_HOST=$(kubectl get gtw tcp-echo-gateway -n istio-io-tcp-traffic-shifting -o jsonpath='{.status.addresses[0].value}') $ export TCP_INGRESS_PORT=$(kubectl get gtw tcp-echo-gateway -n istio-io-tcp-traffic-shifting -o jsonpath='{.spec.listeners[?(@.name=="tcp-31400")].port}')Confirm that the
tcp-echoservice is up and running by sending some TCP traffic.$ export CURL=$(kubectl get pod -l app=curl -n istio-io-tcp-traffic-shifting -o jsonpath={.items..metadata.name}) $ for i in {1..20}; do \ kubectl exec "$CURL" -c curl -n istio-io-tcp-traffic-shifting -- sh -c "(date; sleep 1) | nc $INGRESS_HOST $TCP_INGRESS_PORT"; \ done one Mon Nov 12 23:24:57 UTC 2022 one Mon Nov 12 23:25:00 UTC 2022 one Mon Nov 12 23:25:02 UTC 2022 one Mon Nov 12 23:25:05 UTC 2022 one Mon Nov 12 23:25:07 UTC 2022 one Mon Nov 12 23:25:10 UTC 2022 one Mon Nov 12 23:25:12 UTC 2022 one Mon Nov 12 23:25:15 UTC 2022 one Mon Nov 12 23:25:17 UTC 2022 one Mon Nov 12 23:25:19 UTC 2022 ...You should notice that all the timestamps have a prefix of one, which means that all traffic was routed to the
v1version of thetcp-echoservice.Transfer 20% of the traffic from
tcp-echo:v1totcp-echo:v2with the following command:
$ kubectl apply -f @samples/tcp-echo/tcp-echo-20-v2.yaml@ -n istio-io-tcp-traffic-shifting$ kubectl apply -f @samples/tcp-echo/gateway-api/tcp-echo-20-v2.yaml@ -n istio-io-tcp-traffic-shifting- Wait a few seconds for the new rules to propagate and then confirm that the rule was replaced:
$ kubectl get virtualservice tcp-echo -o yaml -n istio-io-tcp-traffic-shifting apiVersion: networking.istio.io/v1 kind: VirtualService ... spec: ... tcp: - match: - port: 31400 route: - destination: host: tcp-echo port: number: 9000 subset: v1 weight: 80 - destination: host: tcp-echo port: number: 9000 subset: v2 weight: 20$ kubectl get tcproute tcp-echo -o yaml -n istio-io-tcp-traffic-shifting apiVersion: gateway.networking.k8s.io/v1alpha2 kind: TCPRoute ... spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: tcp-echo-gateway sectionName: tcp-31400 rules: - backendRefs: - group: "" kind: Service name: tcp-echo-v1 port: 9000 weight: 80 - group: "" kind: Service name: tcp-echo-v2 port: 9000 weight: 20 ...Send some more TCP traffic to the
tcp-echomicroservice.$ export CURL=$(kubectl get pod -l app=curl -n istio-io-tcp-traffic-shifting -o jsonpath={.items..metadata.name}) $ for i in {1..20}; do \ kubectl exec "$CURL" -c curl -n istio-io-tcp-traffic-shifting -- sh -c "(date; sleep 1) | nc $INGRESS_HOST $TCP_INGRESS_PORT"; \ done one Mon Nov 12 23:38:45 UTC 2022 two Mon Nov 12 23:38:47 UTC 2022 one Mon Nov 12 23:38:50 UTC 2022 one Mon Nov 12 23:38:52 UTC 2022 one Mon Nov 12 23:38:55 UTC 2022 two Mon Nov 12 23:38:57 UTC 2022 one Mon Nov 12 23:39:00 UTC 2022 one Mon Nov 12 23:39:02 UTC 2022 one Mon Nov 12 23:39:05 UTC 2022 one Mon Nov 12 23:39:07 UTC 2022 ...You should now notice that about 20% of the timestamps have a prefix of two, which means that 80% of the TCP traffic was routed to the
v1version of thetcp-echoservice, while 20% was routed tov2.
Understanding what happened
In this task you partially migrated TCP traffic from an old to new version of the tcp-echo service using Istio’s weighted routing feature. Note that this is very different than doing version migration using the deployment features of container orchestration platforms, which use instance scaling to manage the traffic.
With Istio, you can allow the two versions of the tcp-echo service to scale up and down independently, without affecting the traffic distribution between them.
For more information about version routing with autoscaling, check out the blog article Canary Deployments using Istio.
Cleanup
- Remove the routing rules:
$ kubectl delete -f @samples/tcp-echo/tcp-echo-all-v1.yaml@ -n istio-io-tcp-traffic-shifting$ kubectl delete -f @samples/tcp-echo/gateway-api/tcp-echo-all-v1.yaml@ -n istio-io-tcp-traffic-shiftingRemove the
curlsample,tcp-echoapplication and test namespace:$ kubectl delete -f @samples/curl/curl.yaml@ -n istio-io-tcp-traffic-shifting $ kubectl delete -f @samples/tcp-echo/tcp-echo-services.yaml@ -n istio-io-tcp-traffic-shifting $ kubectl delete namespace istio-io-tcp-traffic-shifting