Skip to content

Prevent LoadBalancer updates on follower. #6872

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelogs/unreleased/6872-tsaarni-small.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a memory leak in Contour follower instance due to unprocessed LoadBalancer status updates.
33 changes: 33 additions & 0 deletions cmd/contour/ingressstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
core_v1 "k8s.io/api/core/v1"
networking_v1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/types"
client_go_cache "k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1"
Expand Down Expand Up @@ -55,13 +56,45 @@
statusUpdater k8s.StatusUpdater
ingressClassNames []string
gatewayRef *types.NamespacedName
statusAddress string
serviceName string
serviceNamespace string
}

func (isw *loadBalancerStatusWriter) NeedLeaderElection() bool {
return true
}

func (isw *loadBalancerStatusWriter) Start(ctx context.Context) error {
// Register an informer to watch envoy's service if we haven't been given static details.
// The informer is registered only after leader election to prevent events from being sent before the status writer
// is ready to process them.
if lbAddress := isw.statusAddress; len(lbAddress) > 0 {
isw.log.WithField("loadbalancer-address", lbAddress).Info("Using supplied information for Ingress status")
isw.lbStatus <- parseStatusFlag(lbAddress)
} else {
// Register Service informer to watch for status updates.
var serviceHandler client_go_cache.ResourceEventHandler = &k8s.ServiceStatusLoadBalancerWatcher{
ServiceName: isw.serviceName,
LBStatus: isw.lbStatus,
Log: isw.log.WithField("context", "serviceStatusLoadBalancerWatcher"),
}
var handler client_go_cache.ResourceEventHandler = serviceHandler
if isw.serviceNamespace != "" {
serviceHandler = k8s.NewNamespaceFilter([]string{isw.serviceNamespace}, handler)
}
inf, err := isw.cache.GetInformer(ctx, &core_v1.Service{})
if err != nil {
isw.log.WithError(err).Fatal("failed to get Service informer")
return err
}
_, err = inf.AddEventHandler(serviceHandler)
if err != nil {
isw.log.WithError(err).Fatal("failed to add Service event handler")
return err
}

Check warning on line 95 in cmd/contour/ingressstatus.go

View check run for this annotation

Codecov / codecov/patch

cmd/contour/ingressstatus.go#L69-L95

Added lines #L69 - L95 were not covered by tests
}

u := &k8s.StatusAddressUpdater{
Logger: func() logrus.FieldLogger {
// Configure the StatusAddressUpdater logger.
Expand Down
28 changes: 3 additions & 25 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -700,36 +700,14 @@
ingressClassNames: ingressClassNames,
gatewayRef: gatewayRef,
statusUpdater: sh.Writer(),
statusAddress: contourConfiguration.Ingress.StatusAddress,
serviceName: contourConfiguration.Envoy.Service.Name,
serviceNamespace: contourConfiguration.Envoy.Service.Namespace,

Check warning on line 705 in cmd/contour/serve.go

View check run for this annotation

Codecov / codecov/patch

cmd/contour/serve.go#L703-L705

Added lines #L703 - L705 were not covered by tests
}
if err := s.mgr.Add(lbsw); err != nil {
return err
}

// Register an informer to watch envoy's service if we haven't been given static details.
if lbAddress := contourConfiguration.Ingress.StatusAddress; len(lbAddress) > 0 {
s.log.WithField("loadbalancer-address", lbAddress).Info("Using supplied information for Ingress status")
lbsw.lbStatus <- parseStatusFlag(lbAddress)
} else {
serviceHandler := &k8s.ServiceStatusLoadBalancerWatcher{
ServiceName: contourConfiguration.Envoy.Service.Name,
LBStatus: lbsw.lbStatus,
Log: s.log.WithField("context", "serviceStatusLoadBalancerWatcher"),
}

var handler cache.ResourceEventHandler = serviceHandler
if contourConfiguration.Envoy.Service.Namespace != "" {
handler = k8s.NewNamespaceFilter([]string{contourConfiguration.Envoy.Service.Namespace}, handler)
}

if err := s.informOnResource(&core_v1.Service{}, handler); err != nil {
s.log.WithError(err).WithField("resource", "services").Fatal("failed to create informer")
}

s.log.WithField("envoy-service-name", contourConfiguration.Envoy.Service.Name).
WithField("envoy-service-namespace", contourConfiguration.Envoy.Service.Namespace).
Info("Watching Service for Ingress status")
}

xdsServer := &xdsServer{
log: s.log,
registry: s.registry,
Expand Down