Ensuring EndpointSlices are recreated after Service recreation

This fixes a bug that occurred when a Service was rapidly recreated.
This relied on an unfortunate series of events:

1. When the Service is deleted, the EndpointSlice controller removes it
from the EndpointSliceTracker along with any associated EndpointSlices.
2. When the Service is recreated, the EndpointSlice controller sees that
there are still appropriate EndpointSlices for the Service and does
nothing. (They have not yet been garbage collected).
3. When the EndpointSlice is deleted, the EndpointSlice controller
checks with the EndpointSliceTracker to see if it thinks we should have
this EndpointSlice. This check was intended to ensure we wouldn't
requeue a Service every time we delete an EndpointSlice for it.

This adds a check in reconciler to ensure that EndpointSlices it is
working with are owned by a Service with a matching UID. If not, it will
mark those EndpointSlices for deletion (assuming they're about to be
garbage collected anyway) and create new EndpointSlices.
This commit is contained in:
Rob Scott
2020-09-11 13:15:58 -07:00
parent 77f349ea17
commit de02323a9d
5 changed files with 135 additions and 24 deletions

View File

@@ -70,7 +70,7 @@ func (r *reconciler) reconcile(service *corev1.Service, pods []*corev1.Pod, exis
existingSlicesByPortMap := map[endpointutil.PortMapKey][]*discovery.EndpointSlice{}
numExistingEndpoints := 0
for _, existingSlice := range existingSlices {
if existingSlice.AddressType == addressType {
if existingSlice.AddressType == addressType && ownedBy(existingSlice, service) {
epHash := endpointutil.NewPortMapKey(existingSlice.Ports)
existingSlicesByPortMap[epHash] = append(existingSlicesByPortMap[epHash], existingSlice)
numExistingEndpoints += len(existingSlice.Endpoints)
@@ -187,13 +187,15 @@ func (r *reconciler) finalize(
}
sliceToDelete := slicesToDelete[i]
slice := slicesToCreate[len(slicesToCreate)-1]
// Only update EndpointSlices that have the same AddressType as this
// field is considered immutable. Since Services also consider IPFamily
// immutable, the only case where this should matter will be the
// migration from IP to IPv4 and IPv6 AddressTypes, where there's a
// Only update EndpointSlices that are owned by this Service and have
// the same AddressType. We need to avoid updating EndpointSlices that
// are being garbage collected for an old Service with the same name.
// The AddressType field is immutable. Since Services also consider
// IPFamily immutable, the only case where this should matter will be
// the migration from IP to IPv4 and IPv6 AddressTypes, where there's a
// chance EndpointSlices with an IP AddressType would otherwise be
// updated to IPv4 or IPv6 without this check.
if sliceToDelete.AddressType == slice.AddressType {
if sliceToDelete.AddressType == slice.AddressType && ownedBy(sliceToDelete, service) {
slice.Name = sliceToDelete.Name
slicesToCreate = slicesToCreate[:len(slicesToCreate)-1]
slicesToUpdate = append(slicesToUpdate, slice)