Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Implement weighted round robin load balancing strategy #50

Closed
donovanmuller opened this issue Feb 24, 2020 · 8 comments
Closed

Implement weighted round robin load balancing strategy #50

donovanmuller opened this issue Feb 24, 2020 · 8 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@donovanmuller
Copy link
Contributor

As per the supported load balancing strategies in the initial design a weighted round robin strategy should be implemented to ensure the guarantees stated:

Weighted round robin - Specialisation of the above (default round robin #45) strategy but where a percentage weighting is applied to determine which cluster's Ingress node IPs to resolve. E.g. 80% cluster X and 20% cluster Y

Scenario 1:

  • Given 2 separate Kubernetes clusters, X, and Y
  • Each cluster has a healthy Deployment with a backend Service called app and that backend service exposed with a Gslb resource on cluster X as:
apiVersion: ohmyglb.absa.oss/v1beta1
kind: Gslb
metadata:
  name: app-gslb
  namespace: test-gslb
spec:
  ingress:
    rules:
      - host: app.cloud.example.com
        http:
          paths:
            - backend:
                serviceName: app
                servicePort: http
              path: /
  strategy: roundRobin 
    weight: 80%

and a Gslb resource on cluster Y as:

apiVersion: ohmyglb.absa.oss/v1beta1
kind: Gslb
metadata:
  name: app-gslb
  namespace: test-gslb
spec:
  ingress:
    rules:
      - host: app.cloud.example.com
        http:
          paths:
            - backend:
                serviceName: app
                servicePort: http
              path: /
  strategy: roundRobin 
    weight: 20%
  • Each cluster has one worker node that accepts Ingress traffic. The worker node in each cluster has the following name and IP:
cluster-x-worker-1: 10.0.1.10
cluster-y-worker-1: 10.1.1.11

When issuing the following command, curl -v http://app.cloud.example.com, I would expect the IP's resolved to reflect as follows (if this command was executed 6 times consecutively):

$ curl -v http://app.cloud.example.com # execution 1
*   Trying 10.0.1.10...
...

$ curl -v http://app.cloud.example.com # execution 2
*   Trying 10.0.1.10...
...

$ curl -v http://app.cloud.example.com # execution 3
*   Trying 10.0.1.10...
...

$ curl -v http://app.cloud.example.com # execution 4
*   Trying 10.0.1.10...
...

$ curl -v http://app.cloud.example.com # execution 5
*   Trying 10.1.1.11...
...

$ curl -v http://app.cloud.example.com # execution 6
*   Trying 10.1.1.11...
...

The resolved node IP's that ingress traffic will be sent should be spread approximately according to the weighting configured on the Glsb resources. In this scenario that would be 80% (4 out of 6) resolved to cluster X and 20% (2 out of 6) resolved to cluster Y.

NOTE:

  • The design of the specification around how to indicate the weighting as described in this issue is solely for the purpose of describing the scenario. It should not be considered a design.
  • The scenario where there are more than 2 clusters is currently undefined. I.e. how do the weightings get distributed in the event of missing weightings or uneven weightings? E.g. Given 3 clusters but only 2 Gslb resources in 2 clusters have a weight specified (that might or might not add up to 100%). How does that affect the distribution over 3 clusters?
  • Following on from the above, in the scenario where Deployments become unhealthy on a cluster, then the weighting should be adjusted to honour the weighting across the remaining clusters with healthy Deployments
@donovanmuller donovanmuller added the enhancement New feature or request label Feb 24, 2020
@donovanmuller donovanmuller added this to the 0.9 milestone Feb 24, 2020
@ytsarev ytsarev modified the milestones: 0.9, 1.0 Jun 23, 2021
@kuritka kuritka self-assigned this May 31, 2022
@kuritka
Copy link
Collaborator

kuritka commented Jun 6, 2022

The round robin is taken care of by our library https://github.com/k8gb-io/go-weight-shuffling, which shuffles the indexes in the array according to the predefined weights.

The library would run in the new CoreDNS external plugin within https://github.com/k8gb-io/coredns-crd-plugin. Data will be fed into this plugin from annotation within external DNS endpoints. The CoreDNS - external DNS plugin will read these annotations and arrange itself accordingly.

One cluster can have a number of IP addresses that can change from time to time. The N% weight is set per cluster (region), so I need IP addresses X Region X weight. The annotation is string, so I can annotate by json:

[
  {region: "eu", weightPercent: 20, targets:["172.18.0.5","172.18.0.6"]}, 
  {region: "us", weightPercent:80, targets:["172.18.0.1","172.18.0.2"]}
]
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  annotations:
    k8gb.absa.oss/dnstype: local
    k8gb.absa.oss/weight-round-robin: '[{"region":"eu","weightPercent":20,"targets":["172.18.0.5","172.18.0.6"]},{"region":"us","weightPercent":80,"targets":["172.18.0.1","172.18.0.2"]}]'
  name: k8gb-ns-extdns
  namespace: k8gb

kuritka added a commit that referenced this issue Jun 7, 2022
Related to #50
weight is also allowed for failower and geoip, although it will be ignored by controller.

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 7, 2022
Related to #50
The weight configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight: 20%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>

move RoundRobinStrategy, FailoverStrategy, GeoStrategy constants into depresolver package
kuritka added a commit that referenced this issue Jun 7, 2022
Related to #50
The weight configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight: 20%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>

move RoundRobinStrategy, FailoverStrategy, GeoStrategy constants into depresolver package
kuritka added a commit that referenced this issue Jun 7, 2022
Related to #50
The weight configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight: 20%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>

move RoundRobinStrategy, FailoverStrategy, GeoStrategy constants into depresolver package
kuritka added a commit that referenced this issue Jun 7, 2022
Related to #50
The weight configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight: 20%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>

move RoundRobinStrategy, FailoverStrategy, GeoStrategy constants into depresolver package
kuritka added a commit that referenced this issue Jun 7, 2022
Related to #50
The weight (optional field) configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight: 20%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>

move RoundRobinStrategy, FailoverStrategy, GeoStrategy constants into depresolver package
kuritka added a commit that referenced this issue Jun 14, 2022
Related to #50
The weight (optional field) configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.
The weight distribution must be available to all clusters, so the weight field contains the weights of all regions.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight:
      us: 60%
      eu: 15%
      za: 25%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>

move RoundRobinStrategy, FailoverStrategy, GeoStrategy constants into depresolver package

Weights configuration UPDATE

To be able to round robin by weight I must update GSLB spec contract. instead of
```yaml
spec:
  strategy: roundRobin
  weight: 20%
```
I must extend with map:
```yaml
spec:
  strategy: roundRobin
  weight:
    us: 20%
    eu: 80%
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 14, 2022
Related to #50
The weight (optional field) configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.
The weight distribution must be available to all clusters, so the weight field contains the weights of all regions.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight:
      us: 60%
      eu: 15%
      za: 25%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 14, 2022
Related to #50
The weight (optional field) configuration goes into the GSLB strategy. This PR only aims
to load and validate the weight configuration, which is specified in percentages.
The weight distribution must be available to all clusters, so the weight field contains the weights of all regions.

```yaml
  strategy:
    type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too
    weight:
      us: 60%
      eu: 15%
      za: 25%
```
gslb.spec.strategy.weight is not allowed for failover and geoip strategies. If it is not specified in roundRobin,
then it is not a weight RoundRobin but classic one.

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 22, 2022
related to #50

implemented code that adds an annotation to the local dnsEndpoint.

 - covered by unit-tests
 -  the annotation is as follows:
```json
{
  "eu":{
    "weight":35,
    "targets":[
      "10.10.0.1",
      "10.10.0.2"
    ]
  },
  "us":{
    "weight":50,
    "targets":[
      "10.0.0.1",
      "10.0.0.2"
    ]
  },
  "za":{
    "weight":15,
    "targets":[
      "10.22.0.1",
      "10.22.0.2",
      "10.22.1.1"
    ]
  }
}
```
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 22, 2022
related to #50

implemented code that adds an annotation to the local dnsEndpoint.

 - covered by unit-tests
 -  the annotation is as follows:
```json
{
  "eu":{
    "weight":35,
    "targets":[
      "10.10.0.1",
      "10.10.0.2"
    ]
  },
  "us":{
    "weight":50,
    "targets":[
      "10.0.0.1",
      "10.0.0.2"
    ]
  },
  "za":{
    "weight":15,
    "targets":[
      "10.22.0.1",
      "10.22.0.2",
      "10.22.1.1"
    ]
  }
}
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 22, 2022
related to #50

implemented code that adds an annotation to the local dnsEndpoint.

 - covered by unit-tests
 -  the annotation is as follows:
```json
{
  "eu":{
    "weight":35,
    "targets":[
      "10.10.0.1",
      "10.10.0.2"
    ]
  },
  "us":{
    "weight":50,
    "targets":[
      "10.0.0.1",
      "10.0.0.2"
    ]
  },
  "za":{
    "weight":15,
    "targets":[
      "10.22.0.1",
      "10.22.0.2",
      "10.22.1.1"
    ]
  }
}
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 22, 2022
related to #50

implemented code that adds an annotation to the local dnsEndpoint.

 - covered by unit-tests
 -  the annotation is as follows:
```json
{
  "eu":{
    "weight":35,
    "targets":[
      "10.10.0.1",
      "10.10.0.2"
    ]
  },
  "us":{
    "weight":50,
    "targets":[
      "10.0.0.1",
      "10.0.0.2"
    ]
  },
  "za":{
    "weight":15,
    "targets":[
      "10.22.0.1",
      "10.22.0.2",
      "10.22.1.1"
    ]
  }
}
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 22, 2022
related to #50

implemented code that adds an annotation to the local dnsEndpoint.

 - covered by unit-tests
 -  the annotation is as follows:
```json
{
  "eu":{
    "weight":35,
    "targets":[
      "10.10.0.1",
      "10.10.0.2"
    ]
  },
  "us":{
    "weight":50,
    "targets":[
      "10.0.0.1",
      "10.0.0.2"
    ]
  },
  "za":{
    "weight":15,
    "targets":[
      "10.22.0.1",
      "10.22.0.2",
      "10.22.1.1"
    ]
  }
}
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 27, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 20%
      us: 50%
      za: 30%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-eu-0-20: 10.10.0.1
      weight-eu-1-20: 10.0.0.2
      weight-za-0-30: 10.22.0.1
    recordTTL: 180
    recordType: A
    targets:
    - 10.0.0.1
    - 10.0.0.2
    - 10.10.0.1
    - 10.0.0.2
    - 10.22.0.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 29, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 30, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 30, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 30, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jun 30, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jul 1, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit that referenced this issue Jul 12, 2022
related to #50

implemented code that adds  labels to the local dnsEndpoint.

 - covered by unit-tests
 - the labels are as follows:
```yaml
kind: GSLB
spec:
  ingress:
    rules:
      - host: roundrobin.cloud.example.com
        http: # This section mirrors the same structure as that of an Ingress resource and will be used verbatim when creating the corresponding Ingress resource that will match the GSLB host
          paths:
            - path: /
              backend:
                service:
                  name: existing-app # Gslb should reflect NotFound status
                  port:
                    name: http
spec:
  strategy: roundRobin
    weight:
      eu: 35%
      us: 50%
      za: 15%
```

has local DNS endpoint like this:

```yaml
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: app_host
  annotations: k8gb.absa.oss/dnstype: local
spec:
  endpoints:
  - dnsName: app.bar.com
    labels:
      weight-eu-0-35: 10.10.0.1
      weight-eu-1-35: 10.10.0.2
      weight-us-0-50: 10.0.0.1
      weight-us-1-50: 10.0.0.2
      weight-za-0-15: 10.22.0.1
      weight-za-1-15: 10.22.0.2
      weight-za-2-15: 10.22.1.1
    recordTTL: 180
    recordType: A
    Targets:
      - 10.10.0.1
      - 10.10.0.2
      - 10.0.0.1
      - 10.0.0.2
      - 10.22.0.1
      - 10.22.0.2
      - 10.22.1.1
```
Signed-off-by: kuritka <kuritka@gmail.com>
@somaritane somaritane moved this to To do in k8gb Jul 25, 2022
@somaritane somaritane added this to k8gb Jul 25, 2022
@somaritane somaritane moved this from To do to In progress in k8gb Jul 25, 2022
@somaritane
Copy link
Contributor

@kuritka sorry if I'm coming late to the party, but I've tried to check settings for different implementations of WRR, and in most cases, WRR weights are provided as positive integer instead of percentage:

https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-weighted.html
https://cloud.google.com/dns/docs/zones/manage-routing-policies
https://en.wikipedia.org/wiki/Weighted_round_robin
https://en.wikipedia.org/wiki/SRV_record

The resulting percentage for a particular member can be calculated as a proportion of the total weight of all the members in the WRR group.

This way users also don't have to keep in mind the rule of having 100% of weights in total across n clusters.

@kuritka
Copy link
Collaborator

kuritka commented Jul 26, 2022

It's more about the point of view. The change is a little more extensive, but not complex. Currently it works with percentages and accept values values like "100", "100%",100,100%

But I can change it so that the results are equivalent

# current
weight:
  us: 50%
  eu: 30%
  za: 20
  uk: 0%

# new alternative (integers distribution) 
weight:
  us: 50
  eu: 30
  za: 20
  uk: 0

weight:
  us: 5
  eu: 3
  za: 2
  uk: 0

weight:
  us: 64
  eu: 38
  za: 26
  uk: 0

@somaritane
Copy link
Contributor

somaritane commented Jul 26, 2022

@kuritka Yep, so my point is that by using percentages we're forcing users to think in % and keep the "100% in total" rule in mind.
Whereas when we use just numbers and calculate resulting weights as a proportion of the total sum, we give more flexibility.
This approach still allows using percentages as well, as you've shown in the examples above.
And we don't have to provide a complex validation in this case, we might just limit the max weight to some sensible value, like 1000

@kuritka
Copy link
Collaborator

kuritka commented Jul 26, 2022

ok, will keep it consistent with route53 style and refactor k8gb controller to integers.

kuritka added a commit to k8gb-io/coredns-crd-plugin that referenced this issue Oct 14, 2022
related to k8gb-io/k8gb#50

there is difference between those two:
```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
      us: 1
```

the difference is that first one provides standard coreDNS `loadbalance round_robin`(RRR) while second one enables WRR.
We cannot easily switch the configuration in corefile to enable RRR once and WRR the second time.
This PR contains functionality that switches from WRR to RRR and vice versa in case it identifies missing weights.
```shell
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.3 172.18.0.4 172.18.0.6 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.4 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.4 172.18.0.3 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [0 1][eu1 us1]: [172.18.0.3 172.18.0.4 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.4 172.18.0.3]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.5 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.5 172.18.0.3 172.18.0.4]
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit to k8gb-io/coredns-crd-plugin that referenced this issue Oct 14, 2022
related to k8gb-io/k8gb#50

there is difference between those three:
```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
      us: 1
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
```

the difference is that first one provides standard coreDNS `loadbalance round_robin`(RRR) while second one enables WRR.
We cannot easily switch the configuration in corefile to enable RRR once and WRR the second time when GSLB configuration has change.
This PR contains functionality that switches from WRR to RRR and vice versa in case it identifies missing weights.
Than I'm reusing CoreDNS loadbalance to perform RRR. If GSLB weight configuration is invalid, balancing is off `[skipping][IPs...]` message is shown and IPs are retreived without shuffling (In same order as they come).

```shell
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.3 172.18.0.4 172.18.0.6 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.4 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.4 172.18.0.3 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [0 1][eu1 us1]: [172.18.0.3 172.18.0.4 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.4 172.18.0.3]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.5 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.5 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.4 172.18.0.3]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [0 1][eu1 us1]: [172.18.0.3 172.18.0.4 172.18.0.5 172.18.0.6]
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit to k8gb-io/coredns-crd-plugin that referenced this issue Oct 14, 2022
related to k8gb-io/k8gb#50

there is difference between those three:
```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
      us: 1
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
```

the difference is that first one provides standard coreDNS `loadbalance round_robin`(RRR) while second one enables WRR.
We cannot easily switch the configuration in corefile to enable RRR once and WRR the second time when GSLB configuration has change.
This PR contains functionality that switches from WRR to RRR and vice versa in case it identifies missing weights.
Than I'm reusing CoreDNS loadbalance to perform RRR. If GSLB weight configuration is invalid, balancing is off `[skipping][IPs...]` message is shown and IPs are retreived without shuffling (In same order as they come).

```shell
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.3 172.18.0.4 172.18.0.6 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.4 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.4 172.18.0.3 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [0 1][eu1 us1]: [172.18.0.3 172.18.0.4 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.4 172.18.0.3]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.5 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.5 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.4 172.18.0.3]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [0 1][eu1 us1]: [172.18.0.3 172.18.0.4 172.18.0.5 172.18.0.6]
```

Signed-off-by: kuritka <kuritka@gmail.com>
kuritka added a commit to k8gb-io/coredns-crd-plugin that referenced this issue Oct 14, 2022
related to k8gb-io/k8gb#50

there is difference between those three:
```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
      us: 1
```

```yaml
  strategy:
    type: roundRobin
    splitBrainThresholdSeconds: 300
    dnsTtlSeconds: 30
    weight:
      eu: 1
```

The difference is that first one provides standard coreDNS `loadbalance round_robin`(RRR) while second one enables WRR.
The third one is incompleted.

We cannot easily switch balancing in corefile to enable RRR and disable WRR when GSLB configuration has change.

This PR contains functionality that switches between WRR, RRR  and doing nothing (SKIP).

I'm reusing CoreDNS loadbalance to perform RRR.

```shell
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.3 172.18.0.4 172.18.0.6 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.6 172.18.0.3 172.18.0.4 172.18.0.5]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [random][172.18.0.4 172.18.0.3 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [0 1][eu1 us1]: [172.18.0.3 172.18.0.4 172.18.0.5 172.18.0.6]
k8gb-coredns-5454ddd5b7-r555w coredns [INFO] plugin/wrr: [1 0][us1 eu1]: [172.18.0.5 172.18.0.6 172.18.0.4 172.18.0.3]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
k8gb-coredns-79458796bb-mq855 coredns [INFO] plugin/wrr: [skipping][172.18.0.5 172.18.0.6 172.18.0.3 172.18.0.4]
```

Signed-off-by: kuritka <kuritka@gmail.com>
@ytsarev ytsarev moved this from In progress to To do in k8gb Apr 5, 2023
@ytsarev ytsarev moved this from To do to Review in progress in k8gb Apr 5, 2023
@ytsarev ytsarev moved this from Review in progress to Done in k8gb May 17, 2023
@ytsarev
Copy link
Member

ytsarev commented Dec 15, 2023

@kuritka as WRR is implemented, can we close this issue?

@kuritka
Copy link
Collaborator

kuritka commented Dec 16, 2023

Hi @ytsarev , sure we can. I supposed it's already closed

@ytsarev
Copy link
Member

ytsarev commented Dec 17, 2023

WRR was released in https://github.com/k8gb-io/k8gb/releases/tag/v0.11.1. Closing

@ytsarev ytsarev closed this as completed Dec 17, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

No branches or pull requests

4 participants