Service Mesh (ASM) allows you to use the Intra-zone Provider First feature (also called intra-zone routing) without the need to modify the application code. This topic describes how to use this feature by using the ingress gateway to access an httpbin application as an example.
Prerequisites
- An ASM instance is created. For more information, see Create an ASM instance.
- An ACK managed cluster is created. For more information, see Create an ACK managed cluster.
- The cluster is added to the ASM instance. For more information, see Add a cluster to an ASM instance.
Nodes in an Alibaba Cloud Container Service for Kubernetes (ACK) cluster reside in at least two zones. In this topic, the cn-hongkong-b and cn-hongkong-c zones are used. You can view the region and zone where the Elastic Compute Service (ECS) instance that corresponds to a cluster node resides in the Container Service for Kubernetes (ACK) console. For more information, see Regions and zones.
In this example, sleep and helloworld-v1 applications are deployed in cn-hongkong-b, and the helloworld-v2 application is deployed in cn-hongkong-c. Use the zones where your applications reside.
Background information
When a client initiates an access request to a service, the request is routed to the service provider on the node or in the zone of the client. This is how the Intra-zone Provider First feature works. Intra-zone Provider First is a load balancing feature. It makes traffic flow in the same zones to reduce service latency.
Step 1: Deploy applications
Create a sleep.yaml file that contains the following content:
NoteIn the following example, the sleep application is deployed in cn-hongkong-b. You can deploy your application to a zone based on your business requirements.
# Copyright Istio Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################################## # Sleep service ################################################################################################## apiVersion: v1 kind: ServiceAccount metadata: name: sleep --- apiVersion: v1 kind: Service metadata: name: sleep labels: app: sleep service: sleep spec: ports: - port: 80 name: http selector: app: sleep --- apiVersion: apps/v1 kind: Deployment metadata: name: sleep spec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: failure-domain.beta.kubernetes.io/zone operator: In values: - 'cn-hongkong-b' terminationGracePeriodSeconds: 0 serviceAccountName: sleep containers: - name: sleep image: curlimages/curl command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /etc/sleep/tls name: secret-volume volumes: - name: secret-volume secret: secretName: sleep-secret optional: true
Run the following command to deploy the sleep application in the ACK cluster:
kubectl apply -f sleep.yaml
Create a helloworld.yaml file that contains the following content:
NoteIn the following example, the helloworld-v1 application is deployed in cn-hongkong-b and the helloworld-v2 application in cn-hongkong-c. Use the zones where your applications reside.
apiVersion: v1 kind: Service metadata: name: helloworld labels: app: helloworld service: helloworld spec: ports: - port: 5000 name: http selector: app: helloworld --- apiVersion: apps/v1 kind: Deployment metadata: name: helloworld-v1 labels: app: helloworld version: v1 spec: replicas: 1 selector: matchLabels: app: helloworld version: v1 template: metadata: labels: app: helloworld version: v1 spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: failure-domain.beta.kubernetes.io/zone operator: In values: - 'cn-hongkong-b' containers: - name: helloworld image: docker.io/istio/examples-helloworld-v1 resources: requests: cpu: "100m" imagePullPolicy: IfNotPresent #Always ports: - containerPort: 5000 --- apiVersion: apps/v1 kind: Deployment metadata: name: helloworld-v2 labels: app: helloworld version: v2 spec: replicas: 1 selector: matchLabels: app: helloworld version: v2 template: metadata: labels: app: helloworld version: v2 spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: failure-domain.beta.kubernetes.io/zone operator: In values: - 'cn-hongkong-c' containers: - name: helloworld image: docker.io/istio/examples-helloworld-v2 resources: requests: cpu: "100m" imagePullPolicy: IfNotPresent #Always ports: - containerPort: 5000
Run the following command to deploy the helloworld applications in the ACK cluster:
kubectl apply -f helloworld.yaml
Run the following command to query the registration information of the service to be accessed:
kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')" -c sleep -- curl localhost:15000/clusters | grep helloworld
Expected output:
outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::region::cn-hongkong outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::zone::cn-hongkong-b outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::sub_zone:: outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::canary::false outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::priority::0 ....... outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::region::cn-hongkong outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::zone::cn-hongkong-c outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::sub_zone:: outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::canary::false outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::priority::0
The output shows that the two helloworld applications have the same priority
priority::0
. Therefore, when the sleep client calls the helloworld service, the two helloworld applications have the same routing policies.
Step 2: Enable the Intra-zone Provider First feature
Use the destination rule to prioritize the helloworld application in the zone of the client. Enable the Intra-zone Provider First feature for the helloworld.default.svc.cluster.local
service.
You can enable this feature by configuring the following parameters: consecutive5xxErrors
, interval
, and baseEjectionTime
. In this example, a failover is triggered when the first request fails.
Create a helloworld-failover.yaml file that contains the following content:
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld-failover namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: connectionPool: http: maxRequestsPerConnection: 1 loadBalancer: localityLbSetting: enabled: true simple: ROUND_ROBIN outlierDetection: baseEjectionTime: 1m consecutive5xxErrors: 1 interval: 1s
Run the following command to view the pod priorities:
kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')" -c sleep -- curl localhost:15000/clusters | grep helloworld
Expected output:
outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::region::cn-hongkong outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::zone::cn-hongkong-b outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::sub_zone:: outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::canary::false outbound|5000||helloworld.default.svc.cluster.local::172.28.32.49:5000::priority::0 ....... outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::region::cn-hongkong outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::zone::cn-hongkong-c outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::sub_zone:: outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::canary::false outbound|5000||helloworld.default.svc.cluster.local::172.28.33.155:5000::priority::1
In the output, the priorities of the two helloworld applications are different, which are
priority::0
andpriority::1
. The output shows that the Intra-zone Provider First feature can take effect when the sleep client calls the helloworld service.
Step 3: Verify the Intra-zone Provider First feature
Send a request to call the helloworld service from the sleep application on the client located in the cn-hongkong-b zone. After the Intra-zone Provider First feature is enabled, all traffic flows to the helloworld-v1 application in the same zone with the client. The sleep and helloworld-v1 applications are deployed in cn-hongkong-b, and the helloworld-v2 application in cn-hongkong-c.
Run the following command multiple times to access the helloworld service:
kubectl exec -c sleep "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')" -- curl -sSL helloworld:5000/hello
Expected output:
Hello version: v1, instance: helloworld-v1-6f88967849-sq2h2
The output shows that the returned result is always the helloworld-v1 application.
Scale in the helloworld-v1 application.
Run the following command to scale in the helloworld-v1 application to zero pods and make the application unavailable:
kubectl scale deploy helloworld-v1 --replicas=0
Wait for a few seconds and run the following command multiple times to access the helloworld service:
kubectl exec -c sleep "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')" -- curl -sSL helloworld:5000/hello
Expected output:
Hello version: v2, instance: helloworld-v2-75db5f978d-s7v4k
When the helloworld-v1 application in the same zone as the client becomes unavailable, the request is switched to the helloworld-v2 application in the cn-hongkong-c zone.
Scale out the helloworld-v1 application.
Run the following command to scale out the helloworld-v1 application to one pod and restore the helloworld-v1 application:
kubectl scale deploy helloworld-v1 --replicas=1
Wait for a few seconds and run the following command multiple times to access the helloworld service:
kubectl exec -c sleep "$(kubectl get pod -l app=sleep -o jsonpath='{.items[0].metadata.name}')" -- curl -sSL helloworld:5000/hello
Expected output:
Hello version: v1, instance: helloworld-v1-6f88967849-sq2h2
The output shows that the returned result is always the helloworld-v1 application.