mirror of https://github.com/istio/istio.io.git
Rework locality LB docs into tasks (#8402)
Removing the old locality docs entirely and replacing with tested tasks.
This commit is contained in:
parent
4c544a8009
commit
c5e8a9adc5
|
|
@ -44,7 +44,7 @@ Below is our list of existing features and their current phases. This informatio
|
||||||
| Gateway: Ingress, Egress for all protocols | Stable
|
| Gateway: Ingress, Egress for all protocols | Stable
|
||||||
| TLS termination and SNI Support in Gateways | Stable
|
| TLS termination and SNI Support in Gateways | Stable
|
||||||
| SNI (multiple certs) at ingress | 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
|
| Enabling custom filters in Envoy | Alpha
|
||||||
| CNI container interface | Alpha
|
| CNI container interface | Alpha
|
||||||
| [Sidecar API](/docs/reference/config/networking/sidecar/) | Beta
|
| [Sidecar API](/docs/reference/config/networking/sidecar/) | Beta
|
||||||
|
|
|
||||||
|
|
@ -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 >}}
|
|
||||||
|
|
@ -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
|
By default, Istio will load balance requests evenly between endpoints in
|
||||||
each cluster. In large systems that span geographic regions, it may be
|
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.
|
to prefer that traffic stay in the same zone or region.
|
||||||
|
|
||||||
In some advanced scenarios, load balancing across clusters may not be desired.
|
In some advanced scenarios, load balancing across clusters may not be desired.
|
||||||
|
|
|
||||||
|
|
@ -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{{</ gloss >}} 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.
|
||||||
|
|
@ -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 <<EOF > 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 >}}
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 134 KiB |
|
|
@ -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 <<EOF > 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
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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 - <<EOF
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: DestinationRule
|
||||||
|
metadata:
|
||||||
|
name: helloworld
|
||||||
|
spec:
|
||||||
|
host: helloworld.sample.svc.cluster.local
|
||||||
|
trafficPolicy:
|
||||||
|
loadBalancer:
|
||||||
|
localityLbSetting:
|
||||||
|
enabled: true
|
||||||
|
distribute:
|
||||||
|
- from: region1/zone1/*
|
||||||
|
to:
|
||||||
|
"region1/zone1/*": 70
|
||||||
|
"region1/zone2/*": 20
|
||||||
|
"region3/zone4/*": 10
|
||||||
|
outlierDetection:
|
||||||
|
consecutive5xxErrors: 100
|
||||||
|
interval: 1s
|
||||||
|
baseEjectionTime: 10m
|
||||||
|
EOF
|
||||||
|
{{< /text >}}
|
||||||
|
|
||||||
|
## 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!
|
||||||
|
|
@ -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 - <<EOF
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: DestinationRule
|
||||||
|
metadata:
|
||||||
|
name: helloworld
|
||||||
|
spec:
|
||||||
|
host: helloworld.sample.svc.cluster.local
|
||||||
|
trafficPolicy:
|
||||||
|
loadBalancer:
|
||||||
|
localityLbSetting:
|
||||||
|
enabled: true
|
||||||
|
distribute:
|
||||||
|
- from: region1/zone1/*
|
||||||
|
to:
|
||||||
|
"region1/zone1/*": 70
|
||||||
|
"region1/zone2/*": 20
|
||||||
|
"region3/zone4/*": 10
|
||||||
|
outlierDetection:
|
||||||
|
consecutive5xxErrors: 100
|
||||||
|
interval: 1s
|
||||||
|
baseEjectionTime: 10m
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
snip_verify_the_distribution_1() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC2034,SC2154
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# @setup profile=default
|
||||||
|
|
||||||
|
source content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
function configureDistribution
|
||||||
|
{
|
||||||
|
echo "Applying configuration for locality distribution"
|
||||||
|
snip_configure_weighted_distribution_1
|
||||||
|
|
||||||
|
# Wait a bit for the change to propagate.
|
||||||
|
sleep 5
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyDistribution
|
||||||
|
{
|
||||||
|
echo "Verifying the distribution"
|
||||||
|
|
||||||
|
# Gather the totals that reach each zone.
|
||||||
|
local z1=0
|
||||||
|
local z2=0
|
||||||
|
local z3=0
|
||||||
|
local z4=0
|
||||||
|
for i in {1..50}; do
|
||||||
|
# Send traffic to HelloWorld and get the reply.
|
||||||
|
out="$(snip_verify_the_distribution_1)"
|
||||||
|
|
||||||
|
echo "$out"
|
||||||
|
|
||||||
|
# See which zone replied.
|
||||||
|
if [[ "$out" == *"region1.zone1"* ]]; then
|
||||||
|
z1=$(( z1 + 1 ))
|
||||||
|
elif [[ "$out" == *"region1.zone2"* ]]; then
|
||||||
|
z2=$(( z2 + 1 ))
|
||||||
|
elif [[ "$out" == *"region2.zone3"* ]]; then
|
||||||
|
z3=$(( z3 + 1 ))
|
||||||
|
elif [[ "$out" == *"region3.zone4"* ]]; then
|
||||||
|
z4=$(( z4 + 1 ))
|
||||||
|
else
|
||||||
|
echo "Unexpected response from HelloWorld: $out"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Scale the numbers so that they total 100.
|
||||||
|
z1=$(( z1 * 2 ))
|
||||||
|
z2=$(( z2 * 2 ))
|
||||||
|
z3=$(( z3 * 2 ))
|
||||||
|
z4=$(( z4 * 2 ))
|
||||||
|
|
||||||
|
echo "Actual locality distribution:"
|
||||||
|
echo "region1.zone1: ${z1}"
|
||||||
|
echo "region1.zone2: ${z2}"
|
||||||
|
echo "region2.zone3: ${z3}"
|
||||||
|
echo "region3.zone4: ${z4}"
|
||||||
|
|
||||||
|
if ((z1 < 60 || z1 > 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
|
||||||
|
|
@ -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 - <<EOF
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: DestinationRule
|
||||||
|
metadata:
|
||||||
|
name: helloworld
|
||||||
|
spec:
|
||||||
|
host: helloworld.sample.svc.cluster.local
|
||||||
|
trafficPolicy:
|
||||||
|
connectionPool:
|
||||||
|
http:
|
||||||
|
maxRequestsPerConnection: 1
|
||||||
|
loadBalancer:
|
||||||
|
simple: ROUND_ROBIN
|
||||||
|
localityLbSetting:
|
||||||
|
enabled: true
|
||||||
|
failover:
|
||||||
|
- from: region1
|
||||||
|
to: region2
|
||||||
|
outlierDetection:
|
||||||
|
consecutive5xxErrors: 1
|
||||||
|
interval: 1s
|
||||||
|
baseEjectionTime: 10m
|
||||||
|
EOF
|
||||||
|
{{< /text >}}
|
||||||
|
|
||||||
|
## 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!
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 141 KiB |
|
|
@ -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 - <<EOF
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: DestinationRule
|
||||||
|
metadata:
|
||||||
|
name: helloworld
|
||||||
|
spec:
|
||||||
|
host: helloworld.sample.svc.cluster.local
|
||||||
|
trafficPolicy:
|
||||||
|
connectionPool:
|
||||||
|
http:
|
||||||
|
maxRequestsPerConnection: 1
|
||||||
|
loadBalancer:
|
||||||
|
simple: ROUND_ROBIN
|
||||||
|
localityLbSetting:
|
||||||
|
enabled: true
|
||||||
|
failover:
|
||||||
|
- from: region1
|
||||||
|
to: region2
|
||||||
|
outlierDetection:
|
||||||
|
consecutive5xxErrors: 1
|
||||||
|
interval: 1s
|
||||||
|
baseEjectionTime: 10m
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
snip_verify_traffic_stays_in_region1zone1_1() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
! read -r -d '' snip_verify_traffic_stays_in_region1zone1_1_out <<\ENDSNIP
|
||||||
|
Hello version: region1.zone1, instance: helloworld-region1.zone1-86f77cd7b-cpxhv
|
||||||
|
ENDSNIP
|
||||||
|
|
||||||
|
snip_failover_to_region1zone2_1() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
snip_failover_to_region1zone2_2() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
! read -r -d '' snip_failover_to_region1zone2_2_out <<\ENDSNIP
|
||||||
|
Hello version: region1.zone2, instance: helloworld-region1.zone2-86f77cd7b-cpxhv
|
||||||
|
ENDSNIP
|
||||||
|
|
||||||
|
snip_failover_to_region2zone3_1() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
snip_failover_to_region2zone3_2() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
! read -r -d '' snip_failover_to_region2zone3_2_out <<\ENDSNIP
|
||||||
|
Hello version: region2.zone3, instance: helloworld-region2.zone3-86f77cd7b-cpxhv
|
||||||
|
ENDSNIP
|
||||||
|
|
||||||
|
snip_failover_to_region3zone4_1() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
snip_failover_to_region3zone4_2() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
! read -r -d '' snip_failover_to_region3zone4_2_out <<\ENDSNIP
|
||||||
|
Hello version: region3.zone4, instance: helloworld-region3.zone4-86f77cd7b-cpxhv
|
||||||
|
ENDSNIP
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC2034,SC2154
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# @setup profile=default
|
||||||
|
|
||||||
|
source content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
function verify_traffic_region1_zone1
|
||||||
|
{
|
||||||
|
echo "Verifying all traffic stays in region1.zone1"
|
||||||
|
snip_configure_locality_failover_1
|
||||||
|
verify_traffic snip_verify_traffic_stays_in_region1zone1_1 "$snip_verify_traffic_stays_in_region1zone1_1_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
function failover_to_region1_zone2
|
||||||
|
{
|
||||||
|
echo "Triggering failover to region1.zone2"
|
||||||
|
|
||||||
|
# Terminate the Envoy on the region1.zone1 pod.
|
||||||
|
snip_failover_to_region1zone2_1
|
||||||
|
|
||||||
|
# Verify that all traffic now goes to region1.zone2
|
||||||
|
verify_traffic snip_failover_to_region1zone2_2 "$snip_failover_to_region1zone2_2_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
function failover_to_region2_zone3
|
||||||
|
{
|
||||||
|
echo "Triggering failover to region2.zone3"
|
||||||
|
|
||||||
|
# Terminate the Envoy on the region1.zone2 pod.
|
||||||
|
snip_failover_to_region2zone3_1
|
||||||
|
|
||||||
|
# Verify that all traffic now goes to region2.zone3
|
||||||
|
verify_traffic snip_failover_to_region2zone3_2 "$snip_failover_to_region2zone3_2_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
function failover_to_region3_zone4
|
||||||
|
{
|
||||||
|
echo "Triggering failover to region3.zone4"
|
||||||
|
|
||||||
|
# Terminate the Envoy on the region2.zone3 pod.
|
||||||
|
snip_failover_to_region3zone4_1
|
||||||
|
|
||||||
|
# Verify that all traffic now goes to region3.zone4
|
||||||
|
verify_traffic snip_failover_to_region3zone4_2 "$snip_failover_to_region3zone4_2_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_env_vars
|
||||||
|
deploy_services
|
||||||
|
verify_traffic_region1_zone1
|
||||||
|
failover_to_region1_zone2
|
||||||
|
failover_to_region2_zone3
|
||||||
|
failover_to_region3_zone4
|
||||||
|
|
||||||
|
# @cleanup
|
||||||
|
set +e # ignore cleanup errors
|
||||||
|
|
||||||
|
source content/en/docs/tasks/traffic-management/locality-load-balancing/common.sh
|
||||||
|
|
||||||
|
set_env_vars
|
||||||
|
cleanup
|
||||||
|
|
@ -13,7 +13,7 @@ aliases:
|
||||||
|
|
||||||
## Traffic management
|
## Traffic management
|
||||||
|
|
||||||
- **Improved** [locality based routing](/docs/ops/configuration/traffic-management/locality-load-balancing/) in multicluster environments.
|
- **Improved** [locality based routing](/docs/tasks/traffic-management/locality-load-balancing/) in multicluster environments.
|
||||||
- **Improved** outbound traffic policy in [`ALLOW_ANY` mode](https://archive.istio.io/v1.2/docs/reference/config/installation-options/#global-options). Traffic for unknown HTTP/HTTPS hosts on an existing port will be [forwarded as is](/docs/tasks/traffic-management/egress/egress-control/#envoy-passthrough-to-external-services). Unknown traffic will be logged in Envoy access logs.
|
- **Improved** outbound traffic policy in [`ALLOW_ANY` mode](https://archive.istio.io/v1.2/docs/reference/config/installation-options/#global-options). Traffic for unknown HTTP/HTTPS hosts on an existing port will be [forwarded as is](/docs/tasks/traffic-management/egress/egress-control/#envoy-passthrough-to-external-services). Unknown traffic will be logged in Envoy access logs.
|
||||||
- **Added** support for setting HTTP idle timeouts to upstream services.
|
- **Added** support for setting HTTP idle timeouts to upstream services.
|
||||||
- **Improved** Sidecar support for [NONE mode](/docs/reference/config/networking/sidecar/#CaptureMode) (without iptables) .
|
- **Improved** Sidecar support for [NONE mode](/docs/reference/config/networking/sidecar/#CaptureMode) (without iptables) .
|
||||||
|
|
|
||||||
|
|
@ -238,16 +238,17 @@ func newClusterSnapshot(client kube.Client, contextName string) (ClusterSnapshot
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := wg.Wait(); err != nil {
|
||||||
|
return nilVal, err
|
||||||
|
}
|
||||||
|
|
||||||
sort.Strings(clusterSN.Namespaces)
|
sort.Strings(clusterSN.Namespaces)
|
||||||
sort.Slice(clusterSN.NamespaceSnapshots, func(i, j int) bool {
|
sort.Slice(clusterSN.NamespaceSnapshots, func(i, j int) bool {
|
||||||
return strings.Compare(clusterSN.NamespaceSnapshots[i].Namespace,
|
return strings.Compare(clusterSN.NamespaceSnapshots[i].Namespace,
|
||||||
clusterSN.NamespaceSnapshots[j].Namespace) < 0
|
clusterSN.NamespaceSnapshots[j].Namespace) < 0
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := wg.Wait(); err != nil {
|
|
||||||
return nilVal, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return clusterSN, nil
|
return clusterSN, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ func (s SnapshotValidator) run(ctx framework.TestContext) {
|
||||||
|
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
// Retriable error.
|
// Retriable error.
|
||||||
return nil, true, fmt.Errorf("snapshots are different: \n%v", diffText)
|
return nil, false, fmt.Errorf("snapshots are different: \n%v", diffText)
|
||||||
}
|
}
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}, snapshotRetryTimeout, snapshotRetryDelay); err != nil {
|
}, snapshotRetryTimeout, snapshotRetryDelay); err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue