Skip to content

Commit 754ac92

Browse files
flyikilia601
authored andcommitted
Service annotations for healthchecks (#66)
* add service annotations for nlb healtcheck configuration * force defaults and check if resource needs update
1 parent 5e20a6d commit 754ac92

4 files changed

Lines changed: 101 additions & 14 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ Due to API limitations, only one subnet from each zone must be present in each N
130130
* `yandex.cpi.flant.com/listener-address-ipv4` – select pre-defined IPv4 address. Works both on internal and external NetworkLoadBalancers.
131131
* `yandex.cpi.flant.com/loadbalancer-external` – override `YANDEX_CLOUD_DEFAULT_LB_LISTENER_SUBNET_ID` per-service.
132132
* `yandex.cpi.flant.com/target-group-name-prefix` - set target group for LB to target group with name `yandex.cpi.flant.com/target-group-name-prefix` annotation value + yandex cluster name + `YANDEX_CLOUD_DEFAULT_LB_TARGET_GROUP_NETWORK_ID`.
133+
* `yandex.cpi.flant.com/healthcheck-interval-seconds` - healthcheck interval(default 2).
134+
* `yandex.cpi.flant.com/healthcheck-timeout-seconds` - healthcheck timeout(default 1).
135+
* `yandex.cpi.flant.com/healthcheck-unhealthy-threshold` - healthcheck unhealthy threshold(default 2).
136+
* `yandex.cpi.flant.com/healthcheck-healthy-threshold` - healthcheck healthy threshold(default 2).
133137

134138
##### Node annotations
135139

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
golang.org/x/sync v0.1.0
1313
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21
1414
google.golang.org/grpc v1.51.0
15+
google.golang.org/protobuf v1.28.1
1516
k8s.io/api v0.27.3
1617
k8s.io/apimachinery v0.27.3
1718
k8s.io/client-go v0.27.3
@@ -95,7 +96,6 @@ require (
9596
golang.org/x/text v0.8.0 // indirect
9697
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
9798
google.golang.org/appengine v1.6.7 // indirect
98-
google.golang.org/protobuf v1.28.1 // indirect
9999
gopkg.in/inf.v0 v0.9.1 // indirect
100100
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
101101
gopkg.in/yaml.v2 v2.4.0 // indirect

pkg/cloudprovider/yandex/load_balancer.go

Lines changed: 89 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99

1010
"github.com/yandex-cloud/go-genproto/yandex/cloud/loadbalancer/v1"
11+
"google.golang.org/protobuf/types/known/durationpb"
1112
v1 "k8s.io/api/core/v1"
1213
svchelpers "k8s.io/cloud-provider/service/helpers"
1314
)
@@ -20,6 +21,12 @@ const (
2021
listenerSubnetIdAnnotation = "yandex.cpi.flant.com/listener-subnet-id"
2122
listenerAddressIPv4 = "yandex.cpi.flant.com/listener-address-ipv4"
2223

24+
// healthcheck options
25+
healthcheckIntervalSeconds = "yandex.cpi.flant.com/healthcheck-interval-seconds"
26+
healthcheckTimeoutSeconds = "yandex.cpi.flant.com/healthcheck-timeout-seconds"
27+
healthcheckUnhealthyThreshold = "yandex.cpi.flant.com/healthcheck-unhealthy-threshold"
28+
healthcheckHealthyThreshold = "yandex.cpi.flant.com/healthcheck-healthy-threshold"
29+
2330
nodesHealthCheckPath = "/healthz"
2431
// NOTE: Please keep the following port in sync with ProxyHealthzPort in pkg/cluster/ports/ports.go
2532
// ports.ProxyHealthzPort was not used here to avoid dependencies to k8s.io/kubernetes
@@ -114,7 +121,11 @@ func (yc *Cloud) ensureLB(ctx context.Context, service *v1.Service, nodes []*v1.
114121
}
115122

116123
lbName := defaultLoadBalancerName(service)
117-
lbParams := yc.getLoadBalancerParameters(service)
124+
lbParams, err := yc.getLoadBalancerParameters(service)
125+
126+
if err != nil {
127+
return nil, fmt.Errorf("error while extracting parameters: %w", err)
128+
}
118129

119130
var listenerSpecs []*loadbalancer.ListenerSpec
120131
for index, svcPort := range service.Spec.Ports {
@@ -165,21 +176,46 @@ func (yc *Cloud) ensureLB(ctx context.Context, service *v1.Service, nodes []*v1.
165176
hcPath, hcPort = svchelpers.GetServiceHealthCheckPathPort(service)
166177
}
167178

168-
log.Printf("Health checking on path %q and port %v", hcPath, hcPort)
169-
healthChecks := []*loadbalancer.HealthCheck{
170-
{
171-
Name: "kube-health-check",
172-
UnhealthyThreshold: 2,
173-
HealthyThreshold: 2,
174-
Options: &loadbalancer.HealthCheck_HttpOptions_{
175-
HttpOptions: &loadbalancer.HealthCheck_HttpOptions{
176-
Port: int64(hcPort),
177-
Path: hcPath,
178-
},
179+
healthCheck := &loadbalancer.HealthCheck{
180+
Name: "kube-health-check",
181+
Interval: &durationpb.Duration{Seconds: 2},
182+
Timeout: &durationpb.Duration{Seconds: 1},
183+
UnhealthyThreshold: 2,
184+
HealthyThreshold: 2,
185+
Options: &loadbalancer.HealthCheck_HttpOptions_{
186+
HttpOptions: &loadbalancer.HealthCheck_HttpOptions{
187+
Port: int64(hcPort),
188+
Path: hcPath,
179189
},
180190
},
181191
}
182192

193+
if lbParams.healthcheckIntervalSeconds > 0 {
194+
healthCheck.Interval = &durationpb.Duration{Seconds: int64(lbParams.healthcheckIntervalSeconds)}
195+
}
196+
197+
if lbParams.healthcheckTimeoutSeconds > 0 {
198+
healthCheck.Timeout = &durationpb.Duration{Seconds: int64(lbParams.healthcheckTimeoutSeconds)}
199+
}
200+
201+
if lbParams.healthcheckUnhealthyThreshold > 0 {
202+
healthCheck.UnhealthyThreshold = int64(lbParams.healthcheckUnhealthyThreshold)
203+
}
204+
205+
if lbParams.healthcheckHealthyThreshold > 0 {
206+
healthCheck.HealthyThreshold = int64(lbParams.healthcheckHealthyThreshold)
207+
}
208+
209+
log.Printf("Health checking on path %q and port %v; interval %v, timeout %v, UnhealthyThreshold %d, HealthyThreshold %d",
210+
healthCheck.GetHttpOptions().Path,
211+
healthCheck.GetHttpOptions().Port,
212+
healthCheck.GetInterval(),
213+
healthCheck.GetTimeout(),
214+
healthCheck.GetUnhealthyThreshold(),
215+
healthCheck.GetHealthyThreshold(),
216+
)
217+
healthChecks := []*loadbalancer.HealthCheck{healthCheck}
218+
183219
tgName := lbParams.targetGroupNamePrefix + yc.config.ClusterName + lbParams.targetGroupNetworkID
184220

185221
tg, err := yc.yandexService.LbSvc.GetTgByName(ctx, tgName)
@@ -209,9 +245,14 @@ type loadBalancerParameters struct {
209245
listenerSubnetID string
210246
listenerAddressIPv4 string
211247
internal bool
248+
249+
healthcheckIntervalSeconds int
250+
healthcheckTimeoutSeconds int
251+
healthcheckUnhealthyThreshold int
252+
healthcheckHealthyThreshold int
212253
}
213254

214-
func (yc *Cloud) getLoadBalancerParameters(svc *v1.Service) (lbParams loadBalancerParameters) {
255+
func (yc *Cloud) getLoadBalancerParameters(svc *v1.Service) (lbParams loadBalancerParameters, err error) {
215256
if value, ok := svc.ObjectMeta.Annotations[listenerSubnetIdAnnotation]; ok {
216257
lbParams.internal = true
217258
lbParams.listenerSubnetID = value
@@ -235,5 +276,40 @@ func (yc *Cloud) getLoadBalancerParameters(svc *v1.Service) (lbParams loadBalanc
235276
lbParams.targetGroupNamePrefix = value
236277
}
237278

279+
if value, ok := svc.ObjectMeta.Annotations[healthcheckIntervalSeconds]; ok {
280+
lbParams.healthcheckIntervalSeconds, err = tryAnnotationValueToInt(healthcheckIntervalSeconds, value)
281+
if err != nil {
282+
return
283+
}
284+
}
285+
286+
if value, ok := svc.ObjectMeta.Annotations[healthcheckTimeoutSeconds]; ok {
287+
lbParams.healthcheckTimeoutSeconds, err = tryAnnotationValueToInt(healthcheckTimeoutSeconds, value)
288+
if err != nil {
289+
return
290+
}
291+
}
292+
293+
if value, ok := svc.ObjectMeta.Annotations[healthcheckHealthyThreshold]; ok {
294+
lbParams.healthcheckHealthyThreshold, err = tryAnnotationValueToInt(healthcheckHealthyThreshold, value)
295+
if err != nil {
296+
return
297+
}
298+
}
299+
300+
if value, ok := svc.ObjectMeta.Annotations[healthcheckUnhealthyThreshold]; ok {
301+
lbParams.healthcheckUnhealthyThreshold, err = tryAnnotationValueToInt(healthcheckUnhealthyThreshold, value)
302+
if err != nil {
303+
return
304+
}
305+
}
238306
return
239307
}
308+
309+
func tryAnnotationValueToInt(name, value string) (int, error) {
310+
v, err := strconv.Atoi(value)
311+
if err != nil {
312+
return v, fmt.Errorf("can't convert value of annotation %q to int. value: %q, error %w", name, value, err)
313+
}
314+
return v, nil
315+
}

pkg/yapi/loadbalancer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,5 +506,12 @@ func nlbAttachedTargetGroupsAreEqual(actual *loadbalancer.AttachedTargetGroup, e
506506
if actualHealthCheckHttpOptions.Path != expectedHealthCheckHttpOptions.Path {
507507
return false
508508
}
509+
510+
if actualHealthCheck.Interval.GetSeconds() != expectedHealthCheck.Interval.GetSeconds() {
511+
return false
512+
}
513+
if actualHealthCheck.Timeout.GetSeconds() != expectedHealthCheck.Timeout.GetSeconds() {
514+
return false
515+
}
509516
return true
510517
}

0 commit comments

Comments
 (0)