diff --git a/content/en/about/feature-stages/index.md b/content/en/about/feature-stages/index.md index d1a8bee241..12e8b0686a 100644 --- a/content/en/about/feature-stages/index.md +++ b/content/en/about/feature-stages/index.md @@ -44,7 +44,7 @@ Below is our list of existing features and their current phases. This informatio | Gateway: Ingress, Egress for all protocols | Stable | TLS termination and SNI Support in Gateways | Stable | SNI (multiple certs) at ingress | Stable -| [Locality load balancing](/docs/ops/configuration/traffic-management/locality-load-balancing/) | Beta +| [Locality load balancing](/docs/tasks/traffic-management/locality-load-balancing/) | Beta | Enabling custom filters in Envoy | Alpha | CNI container interface | Alpha | [Sidecar API](/docs/reference/config/networking/sidecar/) | Beta diff --git a/content/en/docs/ops/configuration/traffic-management/locality-load-balancing/index.md b/content/en/docs/ops/configuration/traffic-management/locality-load-balancing/index.md deleted file mode 100644 index 2c4451340a..0000000000 --- a/content/en/docs/ops/configuration/traffic-management/locality-load-balancing/index.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Locality Load Balancing -description: Information on how to enable and understand Locality Load Balancing. -weight: 20 -keywords: [locality,load balancing,priority,prioritized] -aliases: - - /help/ops/traffic-management/locality-load-balancing - - /help/ops/locality-load-balancing - - /help/tasks/traffic-management/locality-load-balancing - - /docs/ops/traffic-management/locality-load-balancing -owner: istio/wg-networking-maintainers -test: no ---- - -A locality defines a geographic location within your mesh using the following triplet: - -- Region -- Zone -- Sub-zone - -The geographic location typically represents a data center. Istio uses -this information to prioritize load balancing pools to control -the geographic location where requests are sent. - -## Configuring locality load balancing - -This feature is enabled by default. To disable locality load balancing, -pass the `--set meshConfig.localityLbSetting.enabled=false` flag when installing Istio. - -## Requirements - -Currently, the service discovery platform populates the locality automatically. -In Kubernetes, a pod's locality is determined via the [well-known labels for region and zone](https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domainbetakubernetesioregion) -on the node it is deployed. If you are using a hosted Kubernetes service your cloud provider -should configure this for you. If you are running your own Kubernetes cluster you will need -to add these labels to your nodes. The sub-zone concept doesn't exist in Kubernetes. -As a result, Istio introduced the custom node label `topology.istio.io/subzone` to define a sub-zone. - -In order for Istio to determine locality, a Service must be associated with the caller. - -To determine when instances are unhealthy, the proxies require an [outlier detection](/docs/reference/config/networking/destination-rule/#OutlierDetection) -configuration in a destination rule for each service. - -## Locality-prioritized load balancing - -_Locality-prioritized load balancing_ is the default behavior for _locality load balancing_. -In this mode, Istio tells Envoy to prioritize traffic to the workload instances most closely matching -the locality of the Envoy sending the request. When all instances are healthy, the requests -remains within the same locality. When instances become unhealthy, traffic spills over to -instances in the next prioritized locality. This behavior continues until all localities are -receiving traffic. You can find the exact percentages in the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/priority). - - {{< warning >}} - If no outlier detection configurations are defined in destination rules, the proxy can't determine if an instance is healthy, and it - routes traffic globally even if you enabled **locality-prioritized** load balancing. - {{< /warning >}} - -A typical prioritization for an Envoy with a locality of `us-west/zone2` is as follows: - -- Priority 0: `us-west/zone2` -- Priority 1: `us-west/zone1`, `us-west/zone3` -- Priority 2: `us-east/zone1`, `us-east/zone2`, `eu-west/zone1` - -The hierarchy of prioritization matches in the following order: - -1. Region -1. Zone -1. Sub-zone - -Proxies in the same zone but different regions are not considered local to one another. - -### Overriding the locality fail-over - -Sometimes, you need to constrain the traffic fail-over to avoid sending traffic to -endpoints across the globe when there are not enough healthy endpoints in the -same region. This behavior is useful when sending fail-over traffic across regions -would not improve service health or many other reasons including regulatory controls. -To constrain traffic to a region, configure the `meshConfig.localityLbSetting` option during install. See the -[Locality load balancing reference guide](/docs/reference/config/networking/destination-rule#LocalityLoadBalancerSetting) -for options. - -An example configuration: - -{{< text yaml >}} -meshConfig: - localityLbSetting: - enabled: true - failover: - - from: us-east - to: eu-west - - from: us-west - to: us-east -{{< /text >}} - -## Locality-weighted load balancing - -Locality-weighted load balancing distributes user-defined percentages of traffic to certain localities. - -For example, if we want to keep 80% of traffic within our region, and send 20% of traffic out of region: - -{{< text yaml >}} -meshConfig: - localityLbSetting: - enabled: true - distribute: - - from: "us-central1/*" - to: - "us-central1/*": 80 - "us-central2/*": 20 -{{< /text >}} diff --git a/content/en/docs/ops/deployment/deployment-models/index.md b/content/en/docs/ops/deployment/deployment-models/index.md index cd7225a539..423bba75c7 100644 --- a/content/en/docs/ops/deployment/deployment-models/index.md +++ b/content/en/docs/ops/deployment/deployment-models/index.md @@ -367,7 +367,7 @@ the cluster, enabling cross-cluster load balancing for these services. By default, Istio will load balance requests evenly between endpoints in each cluster. In large systems that span geographic regions, it may be -desirable to use [locality load balancing](/docs/ops/configuration/traffic-management/locality-load-balancing) +desirable to use [locality load balancing](/docs/tasks/traffic-management/locality-load-balancing) to prefer that traffic stay in the same zone or region. In some advanced scenarios, load balancing across clusters may not be desired. diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/_index.md b/content/en/docs/tasks/traffic-management/locality-load-balancing/_index.md new file mode 100644 index 0000000000..282d4febc3 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/_index.md @@ -0,0 +1,59 @@ +--- +title: Locality Load Balancing +description: This series of tasks demonstrate how to configure locality load balancing in Istio. +weight: 65 +icon: tasks +keywords: [locality,load balancing,priority,prioritized,kubernetes,multicluster] +simple_list: true +content_above: true +aliases: + - /help/ops/traffic-management/locality-load-balancing + - /help/ops/locality-load-balancing + - /help/tasks/traffic-management/locality-load-balancing + - /docs/ops/traffic-management/locality-load-balancing + - /docs/tasks/traffic-management/locality-load-balancing +owner: istio/wg-networking-maintainers +test: n/a +--- +A *locality* defines the geographic location of a +{{< gloss >}}workload instance{{}} within your mesh. The following +triplet defines a locality: + +- **Region**: Represents a large geographic area, such as *us-east*. A region + typically contains a number of availability *zones*. In Kubernetes, the label + [`topology.kubernetes.io/region`](https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/#topologykubernetesioregion) + determines a node's region. + +- **Zone**: A set of compute resources within a region. By running services in + multiple zones within a region, failover can occur between zones within the + region while maintaining data locality with the end-user. In Kubernetes, the + label [`topology.kubernetes.io/zone`](https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/#topologykubernetesiozone) + determines a node's zone. + +- **Sub-zone**: Allows administrators to further subdivide zones for more + fine-grained control, such as "same rack". The sub-zone concept doesn't exist + in Kubernetes. As a result, Istio introduced the custom node label + [`topology.istio.io/subzone`](https://github.com/istio/api/blob/master/label/label.go#L42) + to define a sub-zone. + +{{< tip >}} +If you are using a hosted Kubernetes service your cloud provider should +configure the region and zone labels for you. If you are running your own +Kubernetes cluster you will need to add these labels to your nodes. +{{< /tip >}} + +Localities are hierarchical, in the matching order: + +1. Region + +1. Zone + +1. Sub-zone + +That means that a pod running in zone `bar` of region `foo` +is **not** considered to be local to a pod running in zone `bar` of region +`baz`. + +Istio uses this locality information to control load balancing behavior. +Follow one of the tasks in this series to configure locality load balancing for +your mesh. diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/index.md b/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/index.md new file mode 100644 index 0000000000..09d45b861d --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/index.md @@ -0,0 +1,160 @@ +--- +title: Before you begin +description: Initial steps before configuring locality load balancing. +weight: 1 +icon: tasks +keywords: [locality,load balancing,priority,prioritized,kubernetes,multicluster] +test: yes +owner: istio/wg-networking-maintainers +--- +Before you begin tasks for locality load balancing, you must first +[install Istio on multiple clusters](/docs/setup/install/multicluster). The +clusters must span three regions, containing four availability zones. The +number of clusters required may vary based on the capabilities offered by +your cloud provider. + +{{< tip >}} +For simplicity, we will assume that there is only a single +{{< gloss >}}primary cluster{{< /gloss >}} in the mesh. This simplifies +the process of configuring the control plane, since changes only need to be +applied to one cluster. +{{< /tip >}} + +We will deploy several instances of the `HelloWorld` application as follows: + +{{< image width="75%" + link="setup.svg" + caption="Setup for locality load balancing tasks" + >}} + +## Environment Variables + +This guide assumes that all clusters will be accessed through contexts in the +default [Kubernetes configuration file](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/). +The following environment variables will be used for the various contexts: + +Variable | Description +-------- | ----------- +`CTX_PRIMARY` | The context used for applying configuration to the primary cluster. +`CTX_R1_Z1` | The context used to interact with pods in `region1.zone1`. +`CTX_R1_Z2` | The context used to interact with pods in `region1.zone2`. +`CTX_R2_Z3` | The context used to interact with pods in `region2.zone3`. +`CTX_R3_Z4` | The context used to interact with pods in `region3.zone4`. + +## Create the `sample` namespace + +To begin, generate yaml for the `sample` namespace with automatic sidecar +injection enabled: + +{{< text bash >}} +$ cat < sample.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: sample + labels: + istio-injection: enabled +EOF +{{< /text >}} + +Add the `sample` namespace to each cluster: + +{{< text bash >}} +$ for CTX in "$CTX_PRIMARY" "$CTX_R1_Z1" "$CTX_R1_Z2" "$CTX_R2_Z3" "$CTX_R3_Z4"; \ + do \ + kubectl --context="$CTX" apply -f sample.yaml; \ + done +{{< /text >}} + +## Deploy `HelloWorld` + +Generate the `HelloWorld` YAML for each locality, using the +locality as the version string: + +{{< text bash >}} +$ for LOC in "region1.zone1" "region1.zone2" "region2.zone3" "region3.zone4"; \ + do \ + ./@samples/helloworld/gen-helloworld.sh@ \ + --version "$LOC" > "helloworld-${LOC}.yaml"; \ + done +{{< /text >}} + +Apply the `HelloWorld` YAML to the appropriate cluster for each locality: + +{{< text bash >}} +$ kubectl apply --context="${CTX_R1_Z1}" -n sample \ + -f helloworld-region1.zone1.yaml +{{< /text >}} + +{{< text bash >}} +$ kubectl apply --context="${CTX_R1_Z2}" -n sample \ + -f helloworld-region1.zone2.yaml +{{< /text >}} + +{{< text bash >}} +$ kubectl apply --context="${CTX_R2_Z3}" -n sample \ + -f helloworld-region2.zone3.yaml +{{< /text >}} + +{{< text bash >}} +$ kubectl apply --context="${CTX_R3_Z4}" -n sample \ + -f helloworld-region3.zone4.yaml +{{< /text >}} + +## Deploy `Sleep` + +Deploy the `Sleep` application to `region1` `zone1`: + +{{< text bash >}} +$ kubectl apply --context="${CTX_R1_Z1}" \ + -f @samples/sleep/sleep.yaml@ -n sample +{{< /text >}} + +## Wait for `HelloWorld` pods + +Wait until the `HelloWorld` pods in each zone are `Running`: + +{{< text bash >}} +$ kubectl get pod --context="${CTX_R1_Z1}" -n sample -l app="helloworld" \ + -l version="region1.zone1" +NAME READY STATUS RESTARTS AGE +helloworld-region1.zone1-86f77cd7b-cpxhv 2/2 Running 0 30s +{{< /text >}} + +{{< text bash >}} +$ kubectl get pod --context="${CTX_R1_Z2}" -n sample -l app="helloworld" \ + -l version="region1.zone2" +NAME READY STATUS RESTARTS AGE +helloworld-region1.zone2-86f77cd7b-cpxhv 2/2 Running 0 30s +{{< /text >}} + +{{< text bash >}} +$ kubectl get pod --context="${CTX_R2_Z3}" -n sample -l app="helloworld" \ + -l version="region2.zone3" +NAME READY STATUS RESTARTS AGE +helloworld-region2.zone3-86f77cd7b-cpxhv 2/2 Running 0 30s +{{< /text >}} + +{{< text bash >}} +$ kubectl get pod --context="${CTX_R3_Z4}" -n sample -l app="helloworld" \ + -l version="region3.zone4" +NAME READY STATUS RESTARTS AGE +helloworld-region3.zone4-86f77cd7b-cpxhv 2/2 Running 0 30s +{{< /text >}} + +**Congratulations!** You successfully configured the system and are now ready +to begin the locality load balancing tasks! + +## Next steps + +You can now configure one of the following load balancing options: + +- [Locality failover](/docs/tasks/traffic-management/locality-load-balancing/failover) + +- [Locality weighted distribution](/docs/tasks/traffic-management/locality-load-balancing/distribute) + +{{< warning >}} +Only one of the load balancing options should be configured, as they are +mutually exclusive. Attempting to configure both may lead to unexpected +behavior. +{{< /warning >}} diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/setup.svg b/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/setup.svg new file mode 100644 index 0000000000..9fa9dce95d --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/setup.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/snips.sh b/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/snips.sh new file mode 100644 index 0000000000..6c8ff57ca6 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/snips.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# shellcheck disable=SC2034,SC2153,SC2155,SC2164 + +# Copyright Istio Authors. All Rights Reserved. +# +# 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. + +#################################################################################################### +# WARNING: THIS IS AN AUTO-GENERATED FILE, DO NOT EDIT. PLEASE MODIFY THE ORIGINAL MARKDOWN FILE: +# docs/tasks/traffic-management/locality-load-balancing/before-you-begin/index.md +#################################################################################################### + +snip_create_the_sample_namespace_1() { +cat < sample.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: sample + labels: + istio-injection: enabled +EOF +} + +snip_create_the_sample_namespace_2() { +for CTX in "$CTX_PRIMARY" "$CTX_R1_Z1" "$CTX_R1_Z2" "$CTX_R2_Z3" "$CTX_R3_Z4"; \ + do \ + kubectl --context="$CTX" apply -f sample.yaml; \ + done +} + +snip_deploy_helloworld_1() { +for LOC in "region1.zone1" "region1.zone2" "region2.zone3" "region3.zone4"; \ + do \ + ./samples/helloworld/gen-helloworld.sh \ + --version "$LOC" > "helloworld-${LOC}.yaml"; \ + done +} + +snip_deploy_helloworld_2() { +kubectl apply --context="${CTX_R1_Z1}" -n sample \ + -f helloworld-region1.zone1.yaml +} + +snip_deploy_helloworld_3() { +kubectl apply --context="${CTX_R1_Z2}" -n sample \ + -f helloworld-region1.zone2.yaml +} + +snip_deploy_helloworld_4() { +kubectl apply --context="${CTX_R2_Z3}" -n sample \ + -f helloworld-region2.zone3.yaml +} + +snip_deploy_helloworld_5() { +kubectl apply --context="${CTX_R3_Z4}" -n sample \ + -f helloworld-region3.zone4.yaml +} + +snip_deploy_sleep_1() { +kubectl apply --context="${CTX_R1_Z1}" \ + -f samples/sleep/sleep.yaml -n sample +} + +snip_wait_for_helloworld_pods_1() { +kubectl get pod --context="${CTX_R1_Z1}" -n sample -l app="helloworld" \ + -l version="region1.zone1" +} + +! read -r -d '' snip_wait_for_helloworld_pods_1_out <<\ENDSNIP +NAME READY STATUS RESTARTS AGE +helloworld-region1.zone1-86f77cd7b-cpxhv 2/2 Running 0 30s +ENDSNIP + +snip_wait_for_helloworld_pods_2() { +kubectl get pod --context="${CTX_R1_Z2}" -n sample -l app="helloworld" \ + -l version="region1.zone2" +} + +! read -r -d '' snip_wait_for_helloworld_pods_2_out <<\ENDSNIP +NAME READY STATUS RESTARTS AGE +helloworld-region1.zone2-86f77cd7b-cpxhv 2/2 Running 0 30s +ENDSNIP + +snip_wait_for_helloworld_pods_3() { +kubectl get pod --context="${CTX_R2_Z3}" -n sample -l app="helloworld" \ + -l version="region2.zone3" +} + +! read -r -d '' snip_wait_for_helloworld_pods_3_out <<\ENDSNIP +NAME READY STATUS RESTARTS AGE +helloworld-region2.zone3-86f77cd7b-cpxhv 2/2 Running 0 30s +ENDSNIP + +snip_wait_for_helloworld_pods_4() { +kubectl get pod --context="${CTX_R3_Z4}" -n sample -l app="helloworld" \ + -l version="region3.zone4" +} + +! read -r -d '' snip_wait_for_helloworld_pods_4_out <<\ENDSNIP +NAME READY STATUS RESTARTS AGE +helloworld-region3.zone4-86f77cd7b-cpxhv 2/2 Running 0 30s +ENDSNIP diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh b/content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh new file mode 100644 index 0000000000..216708abcb --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2034 + +# 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. + +# Initialize KUBE_CONTEXTS +_set_kube_vars + +# Include the before you begin tasks. +source content/en/docs/tasks/traffic-management/locality-load-balancing/before-you-begin/snips.sh + +set -e +set -u +set -o pipefail + +function set_env_vars +{ + # All use the same cluster. + export CTX_PRIMARY="${KUBE_CONTEXTS[0]}" + export CTX_R1_Z1="${KUBE_CONTEXTS[0]}" + export CTX_R1_Z2="${KUBE_CONTEXTS[0]}" + export CTX_R2_Z3="${KUBE_CONTEXTS[0]}" + export CTX_R3_Z4="${KUBE_CONTEXTS[0]}" +} + +function deploy_services +{ + echo "Creating the sample namespace" + snip_create_the_sample_namespace_1 + snip_create_the_sample_namespace_2 + + echo "Generating HelloWorld YAML" + snip_deploy_helloworld_1 + + echo "Adding istio-locality label to YAML" + for LOC in "region1.zone1" "region1.zone2" "region2.zone3" "region3.zone4"; + do + add_locality_label "helloworld-${LOC}.yaml" "$LOC" + done + + echo "Deploying HelloWorld" + snip_deploy_helloworld_2 + snip_deploy_helloworld_3 + snip_deploy_helloworld_4 + snip_deploy_helloworld_5 + + echo "Deploying Sleep" + # Make a copy of sleep.yaml. + cp "samples/sleep/sleep.yaml" "samples/sleep/sleep.yaml.original" + # Add the locality label to sleep.yaml + add_locality_label "samples/sleep/sleep.yaml" "region1.zone1" + # Deploy sleep + snip_deploy_sleep_1 + # Restore the original file. + mv -f "samples/sleep/sleep.yaml.original" "samples/sleep/sleep.yaml" + + echo "Waiting for HelloWorld pods" + _verify_like snip_wait_for_helloworld_pods_1 "$snip_wait_for_helloworld_pods_1_out" + _verify_like snip_wait_for_helloworld_pods_2 "$snip_wait_for_helloworld_pods_2_out" + _verify_like snip_wait_for_helloworld_pods_3 "$snip_wait_for_helloworld_pods_3_out" + _verify_like snip_wait_for_helloworld_pods_4 "$snip_wait_for_helloworld_pods_4_out" +} + +function add_locality_label +{ + local file="$1" + local locality="$2" + local nl=$'\n' + + local output="" + local in_deployment=false + while IFS= read -r line + do + # We only want to add the locality label to deployments, so track when + # we're inside a deployment. + if [[ "$line" =~ ^kind:[[:space:]]([a-zA-Z]+)$ ]]; then + if [[ "${BASH_REMATCH[1]}" == "Deployment" ]]; then + in_deployment=true + else + in_deployment=false + fi + fi + + # When we find an app label in the deployment, add the locality label + # right after. + if [[ "$in_deployment" == "true" && $line =~ ([[:space:]]+)app:[[:space:]](.*) ]]; then + output+="${line}${nl}" + output+="${BASH_REMATCH[1]}istio-locality: ${locality}${nl}" + else + output+="${line}${nl}" + fi + done < "$file" + + # Overwrite the original file. + echo "$output" > "$file" +} + +function verify_traffic +{ + local func=$1 + local expected=$2 + + # Require that we match the locality multiple times in a row. + VERIFY_CONSECUTIVE=10 + # Verify that all traffic now goes to region1.zone2 + _verify_like "$func" "$expected" + unset VERIFY_CONSECUTIVE +} + +function cleanup +{ + rm -f sample.yaml helloworld-region*.zone*.yaml + + # Delete the sample namespaces in each cluster + echo "Deleting sample namespace in all clusters" + for CTX in "$CTX_PRIMARY" "$CTX_R1_Z1" "$CTX_R1_Z2" "$CTX_R2_Z3" "$CTX_R3_Z4"; do + kubectl delete ns sample --context="$CTX" --ignore-not-found=true + done + + # Everything should be removed once cleanup completes. Use a small + # timeout for comparing cluster snapshots before/after the test. + export VERIFY_TIMEOUT=20 +} diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/distribute/index.md b/content/en/docs/tasks/traffic-management/locality-load-balancing/distribute/index.md new file mode 100644 index 0000000000..cf1e667dd0 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/distribute/index.md @@ -0,0 +1,78 @@ +--- +title: Locality weighted distribution +description: This guide demonstrates how to configure locality distribution. +weight: 20 +icon: tasks +keywords: [locality,load balancing,kubernetes,multicluster] +test: yes +owner: istio/wg-networking-maintainers +--- +Follow this guide to configure the distribution of traffic across localities. + +Before proceeding, be sure to complete the steps under +[before you begin](/docs/tasks/traffic-management/locality-load-balancing/before-you-begin). + +In this task, we will use the `Sleep` pod in `region1` `zone1` as the source of +requests to the `HelloWorld` service. We will configure Istio with the following +distribution across localities: + +Region | Zone | % of traffic +------ | ---- | ------------ +`region1` | `zone1` | 70 +`region1` | `zone2` | 20 +`region2` | `zone3` | 0 +`region3` | `zone4` | 10 + +## Configure Weighted Distribution + +Apply a `DestinationRule` that configures the following: + +- [Outlier detection](/docs/reference/config/networking/destination-rule/#OutlierDetection) + for the `HelloWorld` service. This is required in order for distribution to + function properly. In particular, it configures the sidecar proxies to know + when endpoints for a service are unhealthy. + +- [Weighted Distribution](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/locality_weight.html?highlight=weight) + for the `HelloWorld` service as described in the table above. + +{{< text bash >}} +$ kubectl --context="${CTX_PRIMARY}" apply -n sample -f - <}} + +## Verify the distribution + +Call the `HelloWorld` service from the `Sleep` pod: + +{{< text bash >}} +$ kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \ + "$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \ + app=sleep -o jsonpath='{.items[0].metadata.name}')" \ + -- curl -sL helloworld.sample:5000/hello +{{< /text >}} + +Repeat this a number of times and verify that the number of replies +for each pod match the expected percentage in the table at the top of +this guide. + +**Congratulations!** You successfully configured locality distribution! diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/distribute/snips.sh b/content/en/docs/tasks/traffic-management/locality-load-balancing/distribute/snips.sh new file mode 100644 index 0000000000..2f1af68e63 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/distribute/snips.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# shellcheck disable=SC2034,SC2153,SC2155,SC2164 + +# Copyright Istio Authors. All Rights Reserved. +# +# 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. + +#################################################################################################### +# WARNING: THIS IS AN AUTO-GENERATED FILE, DO NOT EDIT. PLEASE MODIFY THE ORIGINAL MARKDOWN FILE: +# docs/tasks/traffic-management/locality-load-balancing/distribute/index.md +#################################################################################################### + +snip_configure_weighted_distribution_1() { +kubectl --context="${CTX_PRIMARY}" apply -n sample -f - < 80)); then + echo "Invalid locality distribution to region1.zone1: $z1. Expected: 70" + exit 1 + elif ((z2 < 10 || z2 > 30)); then + echo "Invalid locality distribution to region1.zone2: $z2. Expected: 20" + exit 1 + elif ((z3 > 0)); then + echo "Invalid locality distribution to region2.zone3: $z3. Expected: 0" + exit 1 + elif ((z4 < 5 || z4 > 20)); then + echo "Invalid locality distribution to region1.zone2: $z4. Expected: 10" + exit 1 + fi +} + +set_env_vars +deploy_services +configureDistribution +verifyDistribution + +# @cleanup +set +e # ignore cleanup errors + +source content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh + +set_env_vars +cleanup diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/index.md b/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/index.md new file mode 100644 index 0000000000..358e7d6e29 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/index.md @@ -0,0 +1,177 @@ +--- +title: Locality failover +description: This task demonstrates how to configure your mesh for locality failover. +weight: 10 +icon: tasks +keywords: [locality,load balancing,priority,prioritized,kubernetes,multicluster] +test: yes +owner: istio/wg-networking-maintainers +--- +Follow this guide to configure your mesh for locality failover. + +Before proceeding, be sure to complete the steps under +[before you begin](/docs/tasks/traffic-management/locality-load-balancing/before-you-begin). + +In this task, we will use the `Sleep` pod in `region1.zone1` as the source of +requests to the `HelloWorld` service. We will then trigger failures that will +cause failover between localities in the following sequence: + +{{< image width="75%" + link="sequence.svg" + caption="Locality failover sequence" + >}} + +Internally, [Envoy priorities](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/priority.html) +are used to control failover. These priorities will be assigned as follows for +traffic originating from the `Sleep` pod (in `region1` `zone1`): + +Priority | Locality | Details +-------- | -------- | ------- +0 | `region1.zone1` | Region, zone, and sub-zone all match. +1 | None | Since we're not using sub-zones, there are no matches for a different sub-zone. +2 | `region1.zone2` | Different zone within the same region. +3 | `region2.zone3` | No match, however failover is defined for `region1`->`region2`. +4 | `region3.zone4` | No match and no failover defined for `region1`->`region3`. + +## Configure locality failover + +Apply a `DestinationRule` that configures the following: + +- [Outlier detection](/docs/reference/config/networking/destination-rule/#OutlierDetection) + for the `HelloWorld` service. This is required in order for failover to + function properly. In particular, it configures the sidecar proxies to know + when endpoints for a service are unhealthy, eventually triggering a failover + to the next locality. + +- [Failover](/docs/reference/config/networking/destination-rule/#LocalityLoadBalancerSetting-Failover) + policy between regions. This ensures that failover beyond a region boundary + will behave predictably. + +- [Connection Pool](/docs/reference/config/networking/destination-rule/#ConnectionPoolSettings-http) + policy that forces each HTTP request to use a new connection. This task utilizes + Envoy's [drain](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/operations/draining) + function to force a failover to the next locality. Once drained, Envoy will reject + new connection requests. Since each request uses a new connection, this results in failover + immediately following a drain. **This configuration is used for demonstration purposes only.** + +{{< text bash >}} +$ kubectl --context="${CTX_PRIMARY}" apply -n sample -f - <}} + +## Verify traffic stays in `region1.zone1` + +Call the `HelloWorld` service from the `Sleep` pod: + +{{< text bash >}} +$ kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \ + "$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \ + app=sleep -o jsonpath='{.items[0].metadata.name}')" \ + -- curl -sL helloworld.sample:5000/hello +Hello version: region1.zone1, instance: helloworld-region1.zone1-86f77cd7b-cpxhv +{{< /text >}} + +Verify that the `version` in the response is `region1.zone`. + +Repeat this several times and verify that the response is always the same. + +## Failover to `region1.zone2` + +Next, we trigger a failover to `region1.zone2`. To do this, we drain the +the Envoy sidecar proxy for `HelloWorld` in `region1.zone1`: + +{{< text bash >}} +$ kubectl --context="${CTX_R1_Z1}" exec \ + "$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l app=helloworld \ + -l version=region1.zone1 -o jsonpath='{.items[0].metadata.name}')" \ + -n sample -c istio-proxy -- curl -sL -X POST 127.0.0.1:15000/drain_listeners +{{< /text >}} + +Call the `HelloWorld` service from the `Sleep` pod: + +{{< text bash >}} +$ kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \ + "$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \ + app=sleep -o jsonpath='{.items[0].metadata.name}')" \ + -- curl -sL helloworld.sample:5000/hello +Hello version: region1.zone2, instance: helloworld-region1.zone2-86f77cd7b-cpxhv +{{< /text >}} + +The first call will fail, which triggers the failover. Repeat the command +several more times and verify that the `version` in the response is always +`region1.zone2`. + +## Failover to `region2.zone3` + +Now trigger a failover to `region2.zone3`. As we did previously, we configure +the `HelloWorld` in `region1.zone2` to fail when called: + +{{< text bash >}} +$ kubectl --context="${CTX_R1_Z2}" exec \ + "$(kubectl get pod --context="${CTX_R1_Z2}" -n sample -l app=helloworld \ + -l version=region1.zone2 -o jsonpath='{.items[0].metadata.name}')" \ + -n sample -c istio-proxy -- curl -sL -X POST 127.0.0.1:15000/drain_listeners +{{< /text >}} + +Call the `HelloWorld` service from the `Sleep` pod: + +{{< text bash >}} +$ kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \ + "$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \ + app=sleep -o jsonpath='{.items[0].metadata.name}')" \ + -- curl -sL helloworld.sample:5000/hello +Hello version: region2.zone3, instance: helloworld-region2.zone3-86f77cd7b-cpxhv +{{< /text >}} + +The first call will fail, which triggers the failover. Repeat the command +several more times and verify that the `version` in the response is always +`region2.zone3`. + +## Failover to `region3.zone4` + +Now trigger a failover to `region3.zone4`. As we did previously, we configure +the `HelloWorld` in `region2.zone3` to fail when called: + +{{< text bash >}} +$ kubectl --context="${CTX_R2_Z3}" exec \ + "$(kubectl get pod --context="${CTX_R2_Z3}" -n sample -l app=helloworld \ + -l version=region2.zone3 -o jsonpath='{.items[0].metadata.name}')" \ + -n sample -c istio-proxy -- curl -sL -X POST 127.0.0.1:15000/drain_listeners +{{< /text >}} + +Call the `HelloWorld` service from the `Sleep` pod: + +{{< text bash >}} +$ kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \ + "$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \ + app=sleep -o jsonpath='{.items[0].metadata.name}')" \ + -- curl -sL helloworld.sample:5000/hello +Hello version: region3.zone4, instance: helloworld-region3.zone4-86f77cd7b-cpxhv +{{< /text >}} + +The first call will fail, which triggers the failover. Repeat the command +several more times and verify that the `version` in the response is always +`region3.zone4`. + +**Congratulations!** You successfully configured locality failover! diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/sequence.svg b/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/sequence.svg new file mode 100644 index 0000000000..2134848776 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/sequence.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/snips.sh b/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/snips.sh new file mode 100644 index 0000000000..b5cdf879c5 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/locality-load-balancing/failover/snips.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# shellcheck disable=SC2034,SC2153,SC2155,SC2164 + +# Copyright Istio Authors. All Rights Reserved. +# +# 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. + +#################################################################################################### +# WARNING: THIS IS AN AUTO-GENERATED FILE, DO NOT EDIT. PLEASE MODIFY THE ORIGINAL MARKDOWN FILE: +# docs/tasks/traffic-management/locality-load-balancing/failover/index.md +#################################################################################################### + +snip_configure_locality_failover_1() { +kubectl --context="${CTX_PRIMARY}" apply -n sample -f - <