You can use dynamic subset load balancing to implement fine-grained management and flexible routing of microservices workloads. In scenarios where multiple applications and versions are released, Service Mesh (ASM) automatically divides workloads into dynamic subsets based on application characteristics. O&M personnel do not need to perform manual configurations. ASM can also match specific headers of requests with subset characteristics to implement more flexible request routing.
Prerequisites
A Container Service for Kubernetes (ACK) cluster is added to an ASM instance of v1.18 or later. For more information, see Add a cluster to an ASM instance.
Feature description
ASM allows you to use destination rules to divide the workloads of a service into different subsets by using tags, use virtual services to declare routing rules, and route traffic to specific subsets. This static grouping and static routing method is relatively simple and can meet the needs in most situations. However, in some scenarios, this method may not be convenient enough. For example, in a scenario where workloads are divided into different subsets by version, the versions may be evolving. This requires O&M personnel to add or remove the corresponding subset configurations in destination rules when later versions are released or earlier versions are phased out. In a scenario where multiple applications and versions are frequently released, it is burdensome for O&M personnel to update subset configurations.
To improve user experience, ASM supports dynamic subset load balancing since v1.18. You can specify a dimension, such as version, to dynamically divide workloads with the same value in the specified dimension into the same dynamic subset. If dynamic subnets are used in the preceding scenario, O&M personnel do not need to manually configure subsets for each new version. When you deploy workloads, ASM automatically classifies workloads into dynamic subsets based on application characteristics. In addition, ASM allows you to configure specific headers in requests to match the subset characteristics and routes the requests to a specified dynamic subset based on the headers carried in the requests.
Step 1: Deploy an application
In this example, a hashicorp/http-echo application is used, and two environments, dev and prod, are deployed to simulate the development environment and production environment respectively. The v1, v2, and v3 versions are deployed in the dev environment, and only the v2 and v3 versions are deployed in the prod environment. Each helloworld application listens on port 5678 and replies with its own environment and version when it receives a request. The helloworld service is deployed to expose port 8000. In addition, the helloworld service is associated with the workloads for which the value of the app
tag is helloworld
.
Use kubectl to connect to the ACK cluster based on the information in the kubeconfig file. Then, use the following YAML code to deploy the v1, v2, and v3 versions of the helloworld application in the dev environment, the v2 and v3 versions of the helloworld application in the prod environment, the helloworld service, and the sleep application that is used to initiate testing. For more information about how to deploy an application, see Deploy an application in an ASM instance.
Step 2: Access a specified version in a specified environment
Create a destination rule and a virtual service.
Use the following content to create a destination rule for the helloworld service. For more information, see Manage destination rules.
After the helloworld application is deployed, requests that access the helloworld service are allocated to any pod of the helloworld application by the Kubernetes load balancing feature by default. In this example, two environments and multiple versions are deployed for the helloworld application: the v1, v2, and v3 versions in the dev environment and the v2 and v3 versions in the prod environment. To access the specified environment and version, you must configure a destination rule for the helloworld service.
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: subsetSelectors: - keys: - stage - version
The preceding destination rule groups the workloads of the helloworld service by the stage and version tags. In this example, the deployed workloads are divided into the following subsets by this rule.
Subset
Pod
IP address
stage = dev
version = v1
helloworld-dev-v1-67b6876778-nf7pz
192.168.0.5
stage = dev
version = v2
helloworld-dev-v2-68f65bbc99-v957l
192.168.0.1
stage = dev
version = v3
helloworld-dev-v3-7f6978bc56-hqzgg
192.168.0.252
stage = prod
version = v2
helloworld-prod-v2-b5745b949-p8rc4
192.168.0.103
stage = prod
version = v3
helloworld-prod-v3-6768bf56f8-6bd6h
192.168.0.104
helloworld-prod-v3-6768bf56f8-6bd6h
192.168.0.6
Use the following content to create a virtual service for the helloworld service and establish a mapping between requests and dynamic subnets specified by the
key
values. For more information, see Manage virtual services.The preceding virtual service specifies the following operations:
Maps the header named
x-version
in a request to the subnet key namedversion
. If a request does not carry the header namedx-version
, the default valuev3
is used.Maps the header named
x-stage
in a request to the subset key namedstage
. If a request does not carry the header namedx-stage
, the default valueprod
is used.
Use kubectl to connect to the ACK cluster based on the information in the kubeconfig file. Then, run the following command to enable the sleep application to access the v1 version of the helloworld application in the dev environment.
For more information about how to use kubectl to manage a cluster, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: dev' -H 'x-version: v1' helloworld:8000
Expected output:
Welcome to helloworld stage: dev, version: v1, ip: 192.168.0.5
The output indicates that the requests are routed to the pod whose
stage
isdev
andversion
isv1
as expected.
Step 3: Configure a fallback policy for a subnet
The v1 version is not deployed in the prod environment. If you attempt to access the v1 version in the prod environment, an error is reported because the subnet does not exist.
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
Expected output:
no healthy upstream # An error is reported because the subnet does not exist.
To avoid access failures when a subnet does not exist, you can configure a fallback policy for dynamic grouping rules. The following section describes the three fallback policies supported by ASM dynamic grouping: NO_FALLBACK, ANY_ENDPOINT, and DEFAULT_SUBSET.
NO_FALLBACK
When this fallback policy applies to dynamic grouping rules, a no healthy upstream
error is reported for a request if no subnet is matched.
Use the following destination rule to set
fallbackPolicy
toNO_FALLBACK
for the grouping rule specified bystage
andversion
. For more information, see Manage destination rules.apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: subsetSelectors: - fallbackPolicy: NO_FALLBACK keys: - stage - version
Run the following command to access the helloworld application whose
stage
isprod
andversion
isv1
:kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
Expected output:
no healthy upstream # An error is reported because the subnet does not exist.
ANY_ENDPOINT
When this fallback policy applies to dynamic grouping rules, requests will be routed to any endpoint of the service if no subnet is matched.
Use the following destination rule to set
fallbackPolicy
toANY_ENDPOINT
for the grouping rule specified bystage
andversion
. For more information, see Manage destination rules.apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: subsetSelectors: - fallbackPolicy: ANY_ENDPOINT keys: - stage - version
Run the following command to access the helloworld application whose
stage
isprod
andversion
isv1
.First access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' helloworld:8000
Expected output:
Welcome to helloworld stage: prod, version: v2, ip: 192.168.0.103 # The first access is routed to the helloworld application of the v2 version in the prod environment.
Second access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
Expected output:
Welcome to helloworld stage: dev, version: v2, ip: 192.168.0.1 # The second access is routed to the helloworld application of the v2 version in the dev environment.
The output indicates that requests are routed to random pods of the helloworld service.
DEFAULT_SUBSET
When this fallback policy applies to dynamic grouping rules, requests will be routed to the subnet that matches the values of keys
specified in the defaultSubset
field if no subnet is matched.
Use the following destination rule to set
fallbackPolicy
toDEFAULT_SUBSET
for the grouping rule specified bystage
andversion
, and configurekeys
and values in thedefaultSubset
field. For more information, see Manage destination rules.key
value
stage
prod
version
v3
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: defaultSubset: stage: prod version: v3 subsetSelectors: - fallbackPolicy: DEFAULT_SUBSET keys: - stage - version
Run the following command to access the subnet whose
stage
isprod
andversion
isv1
.First access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
Expected output:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
Second access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
Expected output:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.104
The output is as expected: No subnet is matched. Therefore, a fallback is triggered, and the requests are routed to the subnet whose
stage
isprod
andversion
isv3
.
Step 4: Access a specific pod
If you want to access a specific pod, you can divide pods into independent subnets by setting keys
of ASM dynamic grouping to %ip%
.
Use the following destination rule to create a grouping rule that groups pods by IP address. For more information, see Manage destination rules.
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: default spec: host: helloworld.default.svc.cluster.local trafficPolicy: loadBalancer: dynamicSubset: defaultSubset: stage: prod version: v3 subsetSelectors: - keys: - '%ip%'
Use the following virtual service to map the
x-ip
header of a request to the subset specified by%ip%
, so that the request can access the pod whose IP address is specified byx-ip
. For more information, see Manage virtual services.apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: helloworld namespace: default spec: hosts: - helloworld.default.svc.cluster.local http: - headerToDynamicSubsetKey: - header: x-ip key: '%ip%' name: default route: - destination: host: helloworld.default.svc.cluster.local port: number: 8000
Run the following command to access the Pod helloworld-prod-v3-6768bf56f8-6bd6h whose IP address is
192.168.0.6
. Perform the access operations for multiple times.First access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000
Expected output:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
Second access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000
Expected output:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
Third access:
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000
Expected output:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
The output indicates that the requests are routed to the pod with the specified IP address
192.168.0.6
, which is as expected.
Description of CRD fields
VirtualService
HTTPRoute
The headerToDynamicSubsetKey field is added to the HTTPRoute resource for ASM.
Field
Type
Description
headerToDynamicSubsetKey
Used to configure the mapping of request headers to dynamic subset keys. Each element in the array maps a header to a key.
HeaderToMetadataSubsetKey
HeaderToMetadataSubsetKey specifies the mapping from request headers to dynamic subset keys and the default value to be used if a request does not carry the specified header.
Field
Type
Description
header
string
The name of the request header.
key
string
The name of the dynamic subset key. The part that is enclosed by percent signs (%) defines a built-in attribute of workloads.
defaultValue
string
This default value is used if a request does not carry the header mapping to the key. If you do not specify the default value and a request does not carry the header mapping to the key, the system considers that the header is missing and does not perform matching from the perspective of header.
DestinationRule
In ASM, the dynamicSubset field is added to the trafficPolicy structure.
TrafficPolicy
Field
Type
Description
dynamicSubset
Used to configure dynamic grouping rules.
DyunamicSubsetLB
Field
Type
Description
defaultSubset
map[string]string
Used to configure the default subset. When a request does not match any dynamic subset and the fallback policy is DEFAULT_SUBSET, the subset declared by this field is selected.
subsetSelectors
Used to configure dynamic grouping rules. Each element in the array indicates a separate grouping rule.
fallbackPolicy
Specifies the fallback policy used when the dynamic subsets are not matched. If you do not specify this field, the default value is NO_FALLBACK.
SubsetSelector
Field
Type
Description
keys
string[]
The list of grouping dimensions. The values are mapped to workload tags. For example, the value version indicates that the tag named version of workloads is used as the grouping dimension. In addition to tags, built-in attributes of workloads can also be used as dimensions. For more information, see Built-in attributes of workloads.
fallbackPolicy
Specifies the fallback policy used when no dynamic subsets are matched. If this field is not specified, the fallback policy specified in DyunamicSubsetLB is used.
DynamicSubsetLB_FallbackPolicy
DynamicSubsetLB_FallbackPolicy specifies the enumerated values of the fallback policy for dynamic subset load balancing. The following table describes the supported values.
Value
Description
NO_FALLBACK
No fallback is performed.
ANY_ENDPOINT
Requests will be routed to any endpoint of the service if no subnet is matched.
DEFAULT_SUBSET
Requests will be routed to the default subset if no subnet is matched.
Built-in attributes of workloads
Attribute | Type | Description |
%ip% | string | The IP address of a pod where the workload is running. |
References
You can enable control-plane log collection and log-based alerting to detect and resolve potential risks in a timely manner. For more information, see Enable control-plane log collection and log-based alerting.
You can install the asmctl diagnostics tool to detect potential configuration issues in ASM. For more information, see Install and use asmctl.
You can add audit alerts for changes to ASM resources, such as virtual services and destination rules. This way, alerts are sent to alert contacts in a timely manner when important resources change. For more information, see Configure audit alerts for operations on ASM resources.
You can configure traffic management rules, such as virtual services and destination rules, to isolate a version of an application or an application with specific characteristics into an independent runtime environment, which is known as a lane. In addition, you can configure traffic shifting, which routes traffic to the baseline version or an application with specific characteristics when the destination version or application is unavailable.
If you want to obtain the lowest service call latency, you can use the zone aware routing feature to allow a client to call a destination service deployed in the same zone first. For more information, see Verify the zone aware routing feature on the topology of an ASM instance.